diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index d2a017bd2a02..af071c706856 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -31,3 +31,5 @@ ec2cc761bc7067712ecc7734502f703fe3b024c8 c682aa162b0d41e21cc6748f4fecfe01efb69d1f # reformat with updated edition 2024 1fcae03369abb4c2cc180cd5a49e1f4440a81300 +# Breaking up of compiletest runtest.rs +60600a6fa403216bfd66e04f948b1822f6450af7 diff --git a/.github/ISSUE_TEMPLATE/library_tracking_issue.md b/.github/ISSUE_TEMPLATE/library_tracking_issue.md index 934312662beb..d56da9d5d025 100644 --- a/.github/ISSUE_TEMPLATE/library_tracking_issue.md +++ b/.github/ISSUE_TEMPLATE/library_tracking_issue.md @@ -2,7 +2,7 @@ name: Library Tracking Issue about: A tracking issue for an unstable library feature. title: Tracking Issue for XXX -labels: C-tracking-issue, T-libs-api +labels: C-tracking-issue, T-libs-api, S-tracking-unimplemented --- +(Remember to update the `S-tracking-*` label when checking boxes.) + - [ ] Implementation: #... - [ ] Final comment period (FCP)[^1] - [ ] Stabilization PR diff --git a/.github/ISSUE_TEMPLATE/tracking_issue.md b/.github/ISSUE_TEMPLATE/tracking_issue.md index 3a9d8408b3c9..aedc15a54c27 100644 --- a/.github/ISSUE_TEMPLATE/tracking_issue.md +++ b/.github/ISSUE_TEMPLATE/tracking_issue.md @@ -41,7 +41,10 @@ for larger features an implementation could be broken up into multiple PRs. - [ ] Implement the RFC (cc @rust-lang/XXX -- can anyone write up mentoring instructions?) - [ ] Adjust documentation ([see instructions on rustc-dev-guide][doc-guide]) -- [ ] Formatting for new syntax has been added to the [Style Guide] ([nightly-style-procedure]) +- [ ] Style updates for any new syntax ([nightly-style-procedure]) + - [ ] Style team decision on new formatting + - [ ] Formatting for new syntax has been added to the [Style Guide] + - [ ] (non-blocking) Formatting has been implemented in `rustfmt` - [ ] Stabilization PR ([see instructions on rustc-dev-guide][stabilization-guide]) [stabilization-guide]: https://rustc-dev-guide.rust-lang.org/stabilization_guide.html#stabilization-pr diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 51dd0f81ed14..2e83bbf643fe 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -53,6 +53,13 @@ jobs: steps: - name: Checkout the source code uses: actions/checkout@v4 + # Cache citool to make its build faster, as it's in the critical path. + # The rust-cache doesn't bleed into the main `job`, so it should not affect any other + # Rust compilation. + - name: Cache citool + uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2.7.8 + with: + workspaces: src/ci/citool - name: Calculate the CI job matrix env: COMMIT_MESSAGE: ${{ github.event.head_commit.message }} diff --git a/.mailmap b/.mailmap index b09aebd12dd8..c3ce111bfe3b 100644 --- a/.mailmap +++ b/.mailmap @@ -292,6 +292,7 @@ James Hinshelwood James Miller James Perry James Sanderson +Jamie Hill-Daniel Jana Dönszelmann Jana Dönszelmann Jana Dönszelmann diff --git a/Cargo.lock b/Cargo.lock index fc1c9cf97f0b..97a90a44a398 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -186,6 +186,48 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" +[[package]] +name = "askama" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a4e46abb203e00ef226442d452769233142bbfdd79c3941e84c8e61c4112543" +dependencies = [ + "askama_derive", + "itoa", + "percent-encoding", + "serde", + "serde_json", +] + +[[package]] +name = "askama_derive" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54398906821fd32c728135f7b351f0c7494ab95ae421d41b6f5a020e158f28a6" +dependencies = [ + "askama_parser", + "basic-toml", + "memchr", + "proc-macro2", + "quote", + "rustc-hash 2.1.1", + "serde", + "serde_derive", + "syn 2.0.100", +] + +[[package]] +name = "askama_parser" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf315ce6524c857bb129ff794935cf6d42c82a6cff60526fe2a63593de4d0d4f" +dependencies = [ + "memchr", + "serde", + "serde_derive", + "winnow 0.7.4", +] + [[package]] name = "autocfg" version = "1.4.0" @@ -337,7 +379,7 @@ dependencies = [ name = "cargo-miri" version = "0.1.0" dependencies = [ - "cargo_metadata 0.18.1", + "cargo_metadata 0.19.2", "directories", "rustc-build-sysroot", "rustc_tools_util 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -676,8 +718,8 @@ name = "compiletest" version = "0.0.0" dependencies = [ "anstyle-svg", - "anyhow", "build_helper", + "camino", "colored", "diff", "getopts", @@ -890,15 +932,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "deranged" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" -dependencies = [ - "powerfmt", -] - [[package]] name = "derive-where" version = "1.2.7" @@ -971,11 +1004,11 @@ dependencies = [ [[package]] name = "directories" -version = "5.0.1" +version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a49173b84e034382284f27f1af4dcbbd231ffa358c0fe316541a7337f376a35" +checksum = "16f5094c54661b38d03bd7e50df373292118db60b585c08a411c6d840017fe7d" dependencies = [ - "dirs-sys", + "dirs-sys 0.5.0", ] [[package]] @@ -984,7 +1017,7 @@ version = "5.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" dependencies = [ - "dirs-sys", + "dirs-sys 0.4.1", ] [[package]] @@ -1005,10 +1038,22 @@ checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" dependencies = [ "libc", "option-ext", - "redox_users", + "redox_users 0.4.6", "windows-sys 0.48.0", ] +[[package]] +name = "dirs-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" +dependencies = [ + "libc", + "option-ext", + "redox_users 0.5.0", + "windows-sys 0.59.0", +] + [[package]] name = "dirs-sys-next" version = "0.1.2" @@ -1016,7 +1061,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" dependencies = [ "libc", - "redox_users", + "redox_users 0.4.6", "winapi", ] @@ -1168,7 +1213,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece" dependencies = [ "crc32fast", - "miniz_oxide 0.8.7", + "miniz_oxide 0.8.8", ] [[package]] @@ -1345,8 +1390,8 @@ name = "generate-copyright" version = "0.1.0" dependencies = [ "anyhow", + "askama", "cargo_metadata 0.18.1", - "rinja", "serde", "serde_json", "thiserror 1.0.69", @@ -1977,9 +2022,9 @@ checksum = "9fa0e2a1fcbe2f6be6c42e342259976206b383122fc152e872795338b5a3f3a7" [[package]] name = "libc" -version = "0.2.171" +version = "0.2.172" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" +checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" [[package]] name = "libdbus-sys" @@ -1993,9 +2038,9 @@ dependencies = [ [[package]] name = "libffi" -version = "3.2.0" +version = "4.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce826c243048e3d5cec441799724de52e2d42f820468431fc3fceee2341871e2" +checksum = "4a9434b6fc77375fb624698d5f8c49d7e80b10d59eb1219afda27d1f824d4074" dependencies = [ "libc", "libffi-sys", @@ -2003,9 +2048,9 @@ dependencies = [ [[package]] name = "libffi-sys" -version = "2.3.0" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f36115160c57e8529781b4183c2bb51fdc1f6d6d1ed345591d84be7703befb3c" +checksum = "ead36a2496acfc8edd6cc32352110e9478ac5b9b5f5b9856ebd3d28019addb84" dependencies = [ "cc", ] @@ -2170,20 +2215,6 @@ dependencies = [ "digest", ] -[[package]] -name = "measureme" -version = "11.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfa4a40f09af7aa6faef38285402a78847d0d72bf8827006cd2a332e1e6e4a8d" -dependencies = [ - "log", - "memmap2", - "parking_lot", - "perf-event-open-sys", - "rustc-hash 1.1.0", - "smallvec", -] - [[package]] name = "measureme" version = "12.0.1" @@ -2252,9 +2283,9 @@ dependencies = [ [[package]] name = "miniz_oxide" -version = "0.8.7" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff70ce3e48ae43fa075863cef62e8b43b71a4f2382229920e0df362592919430" +checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" dependencies = [ "adler2", ] @@ -2273,6 +2304,7 @@ name = "miri" version = "0.1.0" dependencies = [ "aes", + "bitflags", "chrono", "chrono-tz", "colored", @@ -2281,7 +2313,7 @@ dependencies = [ "libc", "libffi", "libloading", - "measureme 11.0.1", + "measureme", "rand 0.9.0", "regex", "rustc_version", @@ -2289,7 +2321,7 @@ dependencies = [ "tempfile", "tikv-jemalloc-sys", "ui_test", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -2385,12 +2417,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "num-conv" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" - [[package]] name = "num-integer" version = "0.1.46" @@ -2546,16 +2572,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" -[[package]] -name = "os_pipe" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ffd2b0a5634335b135d5728d84c5e0fd726954b87111f7506a61c502280d982" -dependencies = [ - "libc", - "windows-sys 0.59.0", -] - [[package]] name = "overload" version = "0.1.1" @@ -2768,12 +2784,6 @@ dependencies = [ "portable-atomic", ] -[[package]] -name = "powerfmt" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" - [[package]] name = "ppv-lite86" version = "0.2.21" @@ -2988,6 +2998,17 @@ dependencies = [ "thiserror 1.0.69", ] +[[package]] +name = "redox_users" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b" +dependencies = [ + "getrandom 0.2.15", + "libredox", + "thiserror 2.0.12", +] + [[package]] name = "regex" version = "1.11.1" @@ -3069,9 +3090,7 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3dc4940d00595430b3d7d5a01f6222b5e5b51395d1120bdb28d854bb8abb17a5" dependencies = [ - "humansize", "itoa", - "percent-encoding", "rinja_derive", ] @@ -3113,7 +3132,6 @@ dependencies = [ "gimli 0.31.1", "libc", "object 0.36.7", - "os_pipe", "regex", "serde_json", "similar", @@ -3169,26 +3187,13 @@ dependencies = [ ] [[package]] -name = "rustc-rayon" +name = "rustc-rayon-core" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cd9fb077db982d7ceb42a90471e5a69a990b58f71e06f0d8340bb2cf35eb751" +checksum = "2f42932dcd3bcbe484b38a3ccf79b7906fac41c02d408b5b1bac26da3416efdb" dependencies = [ - "either", - "indexmap", - "rustc-rayon-core", -] - -[[package]] -name = "rustc-rayon-core" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67668daaf00e359c126f6dcb40d652d89b458a008c8afa727a42a2d20fca0b7f" -dependencies = [ - "crossbeam-channel", "crossbeam-deque", "crossbeam-utils", - "num_cpus", ] [[package]] @@ -3430,7 +3435,7 @@ dependencies = [ "gimli 0.31.1", "itertools", "libc", - "measureme 12.0.1", + "measureme", "object 0.36.7", "rustc-demangle", "rustc_abi", @@ -3545,12 +3550,12 @@ dependencies = [ "indexmap", "jobserver", "libc", - "measureme 12.0.1", + "measureme", "memmap2", "parking_lot", "portable-atomic", "rustc-hash 2.1.1", - "rustc-rayon", + "rustc-rayon-core", "rustc-stable-hash", "rustc_arena", "rustc_graphviz", @@ -3578,6 +3583,7 @@ name = "rustc_driver_impl" version = "0.0.0" dependencies = [ "ctrlc", + "jiff", "libc", "rustc_abi", "rustc_ast", @@ -3624,7 +3630,6 @@ dependencies = [ "rustc_ty_utils", "serde_json", "shlex", - "time", "tracing", "windows 0.59.0", ] @@ -3896,7 +3901,6 @@ dependencies = [ name = "rustc_interface" version = "0.0.0" dependencies = [ - "rustc-rayon", "rustc-rayon-core", "rustc_abi", "rustc_ast", @@ -4305,7 +4309,7 @@ dependencies = [ name = "rustc_query_impl" version = "0.0.0" dependencies = [ - "measureme 12.0.1", + "measureme", "rustc_data_structures", "rustc_hashes", "rustc_hir", @@ -4360,7 +4364,6 @@ dependencies = [ "rustc_feature", "rustc_fluent_macro", "rustc_hir", - "rustc_index", "rustc_macros", "rustc_metadata", "rustc_middle", @@ -4407,6 +4410,7 @@ dependencies = [ "bitflags", "getopts", "libc", + "rand 0.9.0", "rustc_abi", "rustc_ast", "rustc_data_structures", @@ -4589,6 +4593,7 @@ version = "0.0.0" dependencies = [ "bitflags", "derive-where", + "ena", "indexmap", "rustc-hash 1.1.0", "rustc_ast_ir", @@ -4627,6 +4632,7 @@ name = "rustdoc" version = "0.0.0" dependencies = [ "arrayvec", + "askama", "base64", "expect-test", "indexmap", @@ -4635,7 +4641,6 @@ dependencies = [ "pulldown-cmark 0.9.6", "pulldown-cmark-escape", "regex", - "rinja", "rustdoc-json-types", "serde", "serde_json", @@ -4654,6 +4659,7 @@ name = "rustdoc-gui-test" version = "0.1.0" dependencies = [ "build_helper", + "camino", "compiletest", "getopts", "walkdir", @@ -5318,37 +5324,6 @@ dependencies = [ "libc", ] -[[package]] -name = "time" -version = "0.3.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" -dependencies = [ - "deranged", - "itoa", - "num-conv", - "powerfmt", - "serde", - "time-core", - "time-macros", -] - -[[package]] -name = "time-core" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" - -[[package]] -name = "time-macros" -version = "0.2.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49" -dependencies = [ - "num-conv", - "time-core", -] - [[package]] name = "tinystr" version = "0.7.6" @@ -5425,7 +5400,7 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "winnow", + "winnow 0.5.40", ] [[package]] @@ -6073,11 +6048,13 @@ dependencies = [ [[package]] name = "windows-bindgen" -version = "0.59.0" +version = "0.61.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b7fb600834d7e868f6e5bb748a86101427330fafbf9485c331b9d5f562d54a5" +checksum = "ac1c59c20569610dd9ed784d5f003fb493ec57b4cf39d974eb03a84bb7156c90" dependencies = [ "rayon", + "serde", + "serde_json", ] [[package]] @@ -6436,6 +6413,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "winnow" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e97b544156e9bebe1a0ffbc03484fc1ffe3100cbce3ffb17eac35f7cdd7ab36" +dependencies = [ + "memchr", +] + [[package]] name = "winsplit" version = "0.1.0" diff --git a/bootstrap.example.toml b/bootstrap.example.toml index 2a98821f2252..0927f648635c 100644 --- a/bootstrap.example.toml +++ b/bootstrap.example.toml @@ -28,7 +28,7 @@ # - A new option # - A change in the default values # -# If the change-id does not match the version currently in use, x.py will +# If the change-id does not match the version currently in use, x.py will # display the changes made to the bootstrap. # To suppress these warnings, you can set change-id = "ignore". #change-id = @@ -442,6 +442,9 @@ # What custom diff tool to use for displaying compiletest tests. #compiletest-diff-tool = +# Whether to use the precompiled stage0 libtest with compiletest. +#compiletest-use-stage0-libtest = true + # Indicates whether ccache is used when building certain artifacts (e.g. LLVM). # Set to `true` to use the first `ccache` in PATH, or set an absolute path to use # a specific version. diff --git a/compiler/rustc_abi/src/extern_abi.rs b/compiler/rustc_abi/src/extern_abi.rs index 4d70afd4e0bc..55f4845d2167 100644 --- a/compiler/rustc_abi/src/extern_abi.rs +++ b/compiler/rustc_abi/src/extern_abi.rs @@ -60,7 +60,6 @@ pub enum ExternAbi { System { unwind: bool, }, - RustIntrinsic, RustCall, /// *Not* a stable ABI, just directly use the Rust types to describe the ABI for LLVM. Even /// normally ABI-compatible Rust types can become ABI-incompatible with this ABI! @@ -128,7 +127,6 @@ abi_impls! { RiscvInterruptS =><= "riscv-interrupt-s", RustCall =><= "rust-call", RustCold =><= "rust-cold", - RustIntrinsic =><= "rust-intrinsic", Stdcall { unwind: false } =><= "stdcall", Stdcall { unwind: true } =><= "stdcall-unwind", System { unwind: false } =><= "system", @@ -199,7 +197,7 @@ impl ExternAbi { /// - are subject to change between compiler versions pub fn is_rustic_abi(self) -> bool { use ExternAbi::*; - matches!(self, Rust | RustCall | RustIntrinsic | RustCold) + matches!(self, Rust | RustCall | RustCold) } pub fn supports_varargs(self) -> bool { diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs index 7bffeaf4cc9e..42250aa173bb 100644 --- a/compiler/rustc_abi/src/layout.rs +++ b/compiler/rustc_abi/src/layout.rs @@ -315,7 +315,7 @@ impl LayoutCalculator { repr: &ReprOptions, variants: &IndexSlice>, is_enum: bool, - is_unsafe_cell: bool, + is_special_no_niche: bool, scalar_valid_range: (Bound, Bound), discr_range_of_repr: impl Fn(i128, i128) -> (Integer, bool), discriminants: impl Iterator, @@ -348,7 +348,7 @@ impl LayoutCalculator { repr, variants, is_enum, - is_unsafe_cell, + is_special_no_niche, scalar_valid_range, always_sized, present_first, @@ -505,7 +505,7 @@ impl LayoutCalculator { repr: &ReprOptions, variants: &IndexSlice>, is_enum: bool, - is_unsafe_cell: bool, + is_special_no_niche: bool, scalar_valid_range: (Bound, Bound), always_sized: bool, present_first: VariantIdx, @@ -524,7 +524,7 @@ impl LayoutCalculator { let mut st = self.univariant(&variants[v], repr, kind)?; st.variants = Variants::Single { index: v }; - if is_unsafe_cell { + if is_special_no_niche { let hide_niches = |scalar: &mut _| match scalar { Scalar::Initialized { value, valid_range } => { *valid_range = WrappingRange::full(value.size(dl)) diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index 843d5ca61ddd..59b74d292214 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -1829,7 +1829,7 @@ pub struct PointeeInfo { pub safe: Option, /// If `safe` is `Some`, then the pointer is either null or dereferenceable for this many bytes. /// On a function argument, "dereferenceable" here means "dereferenceable for the entire duration - /// of this function call", i.e. it is UB for the memory that this pointer points to to be freed + /// of this function call", i.e. it is UB for the memory that this pointer points to be freed /// while this function is still running. /// The size can be zero if the pointer is not dereferenceable. pub size: Size, diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 97e6879c33e9..1532ca77f713 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -120,6 +120,17 @@ impl Path { Path { segments: thin_vec![PathSegment::from_ident(ident)], span: ident.span, tokens: None } } + pub fn is_ident(&self, name: Symbol) -> bool { + if let [segment] = self.segments.as_ref() + && segment.args.is_none() + && segment.ident.name == name + { + true + } else { + false + } + } + pub fn is_global(&self) -> bool { self.segments.first().is_some_and(|segment| segment.ident.name == kw::PathRoot) } @@ -563,6 +574,7 @@ impl Pat { /// This is intended for use by diagnostics. pub fn to_ty(&self) -> Option> { let kind = match &self.kind { + PatKind::Missing => unreachable!(), // In a type expression `_` is an inference variable. PatKind::Wild => TyKind::Infer, // An IDENT pattern with no binding mode would be valid as path to a type. E.g. `u32`. @@ -625,7 +637,8 @@ impl Pat { | PatKind::Guard(s, _) => s.walk(it), // These patterns do not contain subpatterns, skip. - PatKind::Wild + PatKind::Missing + | PatKind::Wild | PatKind::Rest | PatKind::Never | PatKind::Expr(_) @@ -676,6 +689,7 @@ impl Pat { /// Return a name suitable for diagnostics. pub fn descr(&self) -> Option { match &self.kind { + PatKind::Missing => unreachable!(), PatKind::Wild => Some("_".to_string()), PatKind::Ident(BindingMode::NONE, ident, None) => Some(format!("{ident}")), PatKind::Ref(pat, mutbl) => pat.descr().map(|d| format!("&{}{d}", mutbl.prefix_str())), @@ -769,6 +783,9 @@ pub enum RangeSyntax { // Adding a new variant? Please update `test_pat` in `tests/ui/macros/stringify.rs`. #[derive(Clone, Encodable, Decodable, Debug)] pub enum PatKind { + /// A missing pattern, e.g. for an anonymous param in a bare fn like `fn f(u32)`. + Missing, + /// Represents a wildcard pattern (`_`). Wild, @@ -1169,6 +1186,7 @@ pub enum MacStmtStyle { #[derive(Clone, Encodable, Decodable, Debug)] pub struct Local { pub id: NodeId, + pub super_: Option, pub pat: P, pub ty: Option>, pub kind: LocalKind, @@ -3926,7 +3944,7 @@ mod size_asserts { static_assert_size!(Item, 144); static_assert_size!(ItemKind, 80); static_assert_size!(LitKind, 24); - static_assert_size!(Local, 80); + static_assert_size!(Local, 96); static_assert_size!(MetaItemLit, 40); static_assert_size!(Param, 40); static_assert_size!(Pat, 72); diff --git a/compiler/rustc_ast/src/ast_traits.rs b/compiler/rustc_ast/src/ast_traits.rs index c9e2e9911ef0..7f98e7ba8a61 100644 --- a/compiler/rustc_ast/src/ast_traits.rs +++ b/compiler/rustc_ast/src/ast_traits.rs @@ -6,7 +6,6 @@ use std::fmt; use std::marker::PhantomData; use crate::ptr::P; -use crate::token::Nonterminal; use crate::tokenstream::LazyAttrTokenStream; use crate::{ Arm, AssocItem, AttrItem, AttrKind, AttrVec, Attribute, Block, Crate, Expr, ExprField, @@ -206,19 +205,6 @@ impl HasTokens for Attribute { } } -impl HasTokens for Nonterminal { - fn tokens(&self) -> Option<&LazyAttrTokenStream> { - match self { - Nonterminal::NtBlock(block) => block.tokens(), - } - } - fn tokens_mut(&mut self) -> Option<&mut Option> { - match self { - Nonterminal::NtBlock(block) => block.tokens_mut(), - } - } -} - /// A trait for AST nodes having (or not having) attributes. pub trait HasAttrs { /// This is `true` if this `HasAttrs` might support 'custom' (proc-macro) inner diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index 0b65246693dd..f104400a572b 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -305,8 +305,8 @@ impl MetaItem { if let [PathSegment { ident, .. }] = self.path.segments[..] { Some(ident) } else { None } } - pub fn name_or_empty(&self) -> Symbol { - self.ident().unwrap_or_else(Ident::empty).name + pub fn name(&self) -> Option { + self.ident().map(|ident| ident.name) } pub fn has_name(&self, name: Symbol) -> bool { @@ -511,13 +511,14 @@ impl MetaItemInner { } } - /// For a single-segment meta item, returns its name; otherwise, returns `None`. + /// For a single-segment meta item, returns its identifier; otherwise, returns `None`. pub fn ident(&self) -> Option { self.meta_item().and_then(|meta_item| meta_item.ident()) } - pub fn name_or_empty(&self) -> Symbol { - self.ident().unwrap_or_else(Ident::empty).name + /// For a single-segment meta item, returns its name; otherwise, returns `None`. + pub fn name(&self) -> Option { + self.ident().map(|ident| ident.name) } /// Returns `true` if this list item is a MetaItem with a name of `name`. @@ -627,7 +628,7 @@ pub fn mk_doc_comment( Attribute { kind: AttrKind::DocComment(comment_kind, data), id: g.mk_attr_id(), style, span } } -pub fn mk_attr( +fn mk_attr( g: &AttrIdGenerator, style: AttrStyle, unsafety: Safety, @@ -738,9 +739,9 @@ pub trait AttributeExt: Debug { fn id(&self) -> AttrId; /// For a single-segment attribute (i.e., `#[attr]` and not `#[path::atrr]`), - /// return the name of the attribute, else return the empty identifier. - fn name_or_empty(&self) -> Symbol { - self.ident().unwrap_or_else(Ident::empty).name + /// return the name of the attribute; otherwise, returns `None`. + fn name(&self) -> Option { + self.ident().map(|ident| ident.name) } /// Get the meta item list, `#[attr(meta item list)]` @@ -752,7 +753,7 @@ pub trait AttributeExt: Debug { /// Gets the span of the value literal, as string, when using `#[attr = value]` fn value_span(&self) -> Option; - /// For a single-segment attribute, returns its name; otherwise, returns `None`. + /// For a single-segment attribute, returns its ident; otherwise, returns `None`. fn ident(&self) -> Option; /// Checks whether the path of this attribute matches the name. @@ -770,6 +771,11 @@ pub trait AttributeExt: Debug { self.ident().map(|x| x.name == name).unwrap_or(false) } + #[inline] + fn has_any_name(&self, names: &[Symbol]) -> bool { + names.iter().any(|&name| self.has_name(name)) + } + /// get the span of the entire attribute fn span(&self) -> Span; @@ -813,8 +819,8 @@ impl Attribute { AttributeExt::id(self) } - pub fn name_or_empty(&self) -> Symbol { - AttributeExt::name_or_empty(self) + pub fn name(&self) -> Option { + AttributeExt::name(self) } pub fn meta_item_list(&self) -> Option> { @@ -846,6 +852,11 @@ impl Attribute { AttributeExt::has_name(self, name) } + #[inline] + pub fn has_any_name(&self, names: &[Symbol]) -> bool { + AttributeExt::has_any_name(self, names) + } + pub fn span(&self) -> Span { AttributeExt::span(self) } diff --git a/compiler/rustc_ast/src/expand/autodiff_attrs.rs b/compiler/rustc_ast/src/expand/autodiff_attrs.rs index f01c781f46c6..2f918faaf752 100644 --- a/compiler/rustc_ast/src/expand/autodiff_attrs.rs +++ b/compiler/rustc_ast/src/expand/autodiff_attrs.rs @@ -50,8 +50,16 @@ pub enum DiffActivity { /// with it. Dual, /// Forward Mode, Compute derivatives for this input/output and *overwrite* the shadow argument + /// with it. It expects the shadow argument to be `width` times larger than the original + /// input/output. + Dualv, + /// Forward Mode, Compute derivatives for this input/output and *overwrite* the shadow argument /// with it. Drop the code which updates the original input/output for maximum performance. DualOnly, + /// Forward Mode, Compute derivatives for this input/output and *overwrite* the shadow argument + /// with it. Drop the code which updates the original input/output for maximum performance. + /// It expects the shadow argument to be `width` times larger than the original input/output. + DualvOnly, /// Reverse Mode, Compute derivatives for this &T or *T input and *add* it to the shadow argument. Duplicated, /// Reverse Mode, Compute derivatives for this &T or *T input and *add* it to the shadow argument. @@ -59,7 +67,15 @@ pub enum DiffActivity { DuplicatedOnly, /// All Integers must be Const, but these are used to mark the integer which represents the /// length of a slice/vec. This is used for safety checks on slices. - FakeActivitySize, + /// The integer (if given) specifies the size of the slice element in bytes. + FakeActivitySize(Option), +} + +impl DiffActivity { + pub fn is_dual_or_const(&self) -> bool { + use DiffActivity::*; + matches!(self, |Dual| DualOnly | Dualv | DualvOnly | Const) + } } /// We generate one of these structs for each `#[autodiff(...)]` attribute. #[derive(Clone, Eq, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)] @@ -92,6 +108,12 @@ pub struct AutoDiffAttrs { pub input_activity: Vec, } +impl AutoDiffAttrs { + pub fn has_primal_ret(&self) -> bool { + matches!(self.ret_activity, DiffActivity::Active | DiffActivity::Dual) + } +} + impl DiffMode { pub fn is_rev(&self) -> bool { matches!(self, DiffMode::Reverse) @@ -125,11 +147,7 @@ pub fn valid_ret_activity(mode: DiffMode, activity: DiffActivity) -> bool { match mode { DiffMode::Error => false, DiffMode::Source => false, - DiffMode::Forward => { - activity == DiffActivity::Dual - || activity == DiffActivity::DualOnly - || activity == DiffActivity::Const - } + DiffMode::Forward => activity.is_dual_or_const(), DiffMode::Reverse => { activity == DiffActivity::Const || activity == DiffActivity::Active @@ -147,10 +165,8 @@ pub fn valid_ret_activity(mode: DiffMode, activity: DiffActivity) -> bool { pub fn valid_ty_for_activity(ty: &P, activity: DiffActivity) -> bool { use DiffActivity::*; // It's always allowed to mark something as Const, since we won't compute derivatives wrt. it. - if matches!(activity, Const) { - return true; - } - if matches!(activity, Dual | DualOnly) { + // Dual variants also support all types. + if activity.is_dual_or_const() { return true; } // FIXME(ZuseZ4) We should make this more robust to also @@ -166,9 +182,7 @@ pub fn valid_input_activity(mode: DiffMode, activity: DiffActivity) -> bool { return match mode { DiffMode::Error => false, DiffMode::Source => false, - DiffMode::Forward => { - matches!(activity, Dual | DualOnly | Const) - } + DiffMode::Forward => activity.is_dual_or_const(), DiffMode::Reverse => { matches!(activity, Active | ActiveOnly | Duplicated | DuplicatedOnly | Const) } @@ -183,10 +197,12 @@ impl Display for DiffActivity { DiffActivity::Active => write!(f, "Active"), DiffActivity::ActiveOnly => write!(f, "ActiveOnly"), DiffActivity::Dual => write!(f, "Dual"), + DiffActivity::Dualv => write!(f, "Dualv"), DiffActivity::DualOnly => write!(f, "DualOnly"), + DiffActivity::DualvOnly => write!(f, "DualvOnly"), DiffActivity::Duplicated => write!(f, "Duplicated"), DiffActivity::DuplicatedOnly => write!(f, "DuplicatedOnly"), - DiffActivity::FakeActivitySize => write!(f, "FakeActivitySize"), + DiffActivity::FakeActivitySize(s) => write!(f, "FakeActivitySize({:?})", s), } } } @@ -214,7 +230,9 @@ impl FromStr for DiffActivity { "ActiveOnly" => Ok(DiffActivity::ActiveOnly), "Const" => Ok(DiffActivity::Const), "Dual" => Ok(DiffActivity::Dual), + "Dualv" => Ok(DiffActivity::Dualv), "DualOnly" => Ok(DiffActivity::DualOnly), + "DualvOnly" => Ok(DiffActivity::DualvOnly), "Duplicated" => Ok(DiffActivity::Duplicated), "DuplicatedOnly" => Ok(DiffActivity::DuplicatedOnly), _ => Err(()), diff --git a/compiler/rustc_ast/src/expand/mod.rs b/compiler/rustc_ast/src/expand/mod.rs index 04c816293236..323a8fab6d59 100644 --- a/compiler/rustc_ast/src/expand/mod.rs +++ b/compiler/rustc_ast/src/expand/mod.rs @@ -13,12 +13,12 @@ pub mod typetree; #[derive(Debug, Clone, Encodable, Decodable, HashStable_Generic)] pub struct StrippedCfgItem { pub parent_module: ModId, - pub name: Ident, + pub ident: Ident, pub cfg: MetaItem, } impl StrippedCfgItem { pub fn map_mod_id(self, f: impl FnOnce(ModId) -> New) -> StrippedCfgItem { - StrippedCfgItem { parent_module: f(self.parent_module), name: self.name, cfg: self.cfg } + StrippedCfgItem { parent_module: f(self.parent_module), ident: self.ident, cfg: self.cfg } } } diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs index da510e4967db..294c6c9ba7a5 100644 --- a/compiler/rustc_ast/src/lib.rs +++ b/compiler/rustc_ast/src/lib.rs @@ -6,7 +6,6 @@ // tidy-alphabetical-start #![allow(internal_features)] -#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![doc( html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/", test(attr(deny(warnings))) diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index f7d13acdfc40..6aae2e481a59 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -704,7 +704,8 @@ fn walk_parenthesized_parameter_data(vis: &mut T, args: &mut Pare } fn walk_local(vis: &mut T, local: &mut P) { - let Local { id, pat, ty, kind, span, colon_sp, attrs, tokens } = local.deref_mut(); + let Local { id, super_, pat, ty, kind, span, colon_sp, attrs, tokens } = local.deref_mut(); + visit_opt(super_, |sp| vis.visit_span(sp)); vis.visit_id(id); visit_attrs(vis, attrs); vis.visit_pat(pat); @@ -843,9 +844,9 @@ fn visit_lazy_tts(vis: &mut T, lazy_tts: &mut Option(vis: &mut T, t: &mut Token) { let Token { kind, span } = t; @@ -863,45 +864,11 @@ pub fn visit_token(vis: &mut T, t: &mut Token) { token::NtLifetime(ident, _is_raw) => { vis.visit_ident(ident); } - token::Interpolated(nt) => { - let nt = Arc::make_mut(nt); - visit_nonterminal(vis, nt); - } _ => {} } vis.visit_span(span); } -// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. -/// Applies the visitor to elements of interpolated nodes. -// -// N.B., this can occur only when applying a visitor to partially expanded -// code, where parsed pieces have gotten implanted ito *other* macro -// invocations. This is relevant for macro hygiene, but possibly not elsewhere. -// -// One problem here occurs because the types for flat_map_item, flat_map_stmt, -// etc., allow the visitor to return *multiple* items; this is a problem for the -// nodes here, because they insist on having exactly one piece. One solution -// would be to mangle the MutVisitor trait to include one-to-many and -// one-to-one versions of these entry points, but that would probably confuse a -// lot of people and help very few. Instead, I'm just going to put in dynamic -// checks. I think the performance impact of this will be pretty much -// nonexistent. The danger is that someone will apply a `MutVisitor` to a -// partially expanded node, and will be confused by the fact that their -// `flat_map_item` or `flat_map_stmt` isn't getting called on `NtItem` or `NtStmt` -// nodes. Hopefully they'll wind up reading this comment, and doing something -// appropriate. -// -// BTW, design choice: I considered just changing the type of, e.g., `NtItem` to -// contain multiple items, but decided against it when I looked at -// `parse_item_or_view_item` and tried to figure out what I would do with -// multiple items there.... -fn visit_nonterminal(vis: &mut T, nt: &mut token::Nonterminal) { - match nt { - token::NtBlock(block) => vis.visit_block(block), - } -} - // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. fn visit_defaultness(vis: &mut T, defaultness: &mut Defaultness) { match defaultness { @@ -1587,7 +1554,7 @@ pub fn walk_pat(vis: &mut T, pat: &mut P) { vis.visit_id(id); match kind { PatKind::Err(_guar) => {} - PatKind::Wild | PatKind::Rest | PatKind::Never => {} + PatKind::Missing | PatKind::Wild | PatKind::Rest | PatKind::Never => {} PatKind::Ident(_binding_mode, ident, sub) => { vis.visit_ident(ident); visit_opt(sub, |sub| vis.visit_pat(sub)); diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index d57a369eebf2..055481f5d878 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -1,13 +1,10 @@ use std::borrow::Cow; use std::fmt; -use std::sync::Arc; pub use LitKind::*; -pub use Nonterminal::*; pub use NtExprKind::*; pub use NtPatKind::*; pub use TokenKind::*; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_macros::{Decodable, Encodable, HashStable_Generic}; use rustc_span::edition::Edition; use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, kw, sym}; @@ -16,7 +13,6 @@ use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, kw, sym}; use rustc_span::{Ident, Symbol}; use crate::ast; -use crate::ptr::P; use crate::util::case::Case; #[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)] @@ -34,10 +30,6 @@ pub enum InvisibleOrigin { // Converted from `proc_macro::Delimiter` in // `proc_macro::Delimiter::to_internal`, i.e. returned by a proc macro. ProcMacro, - - // Converted from `TokenKind::Interpolated` in - // `TokenStream::flatten_token`. Treated similarly to `ProcMacro`. - FlattenToken, } impl PartialEq for InvisibleOrigin { @@ -134,9 +126,7 @@ impl Delimiter { match self { Delimiter::Parenthesis | Delimiter::Bracket | Delimiter::Brace => false, Delimiter::Invisible(InvisibleOrigin::MetaVar(_)) => false, - Delimiter::Invisible(InvisibleOrigin::FlattenToken | InvisibleOrigin::ProcMacro) => { - true - } + Delimiter::Invisible(InvisibleOrigin::ProcMacro) => true, } } @@ -337,9 +327,7 @@ impl From for bool { } } -// SAFETY: due to the `Clone` impl below, all fields of all variants other than -// `Interpolated` must impl `Copy`. -#[derive(PartialEq, Encodable, Decodable, Debug, HashStable_Generic)] +#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)] pub enum TokenKind { /* Expression-operator symbols. */ /// `=` @@ -468,21 +456,6 @@ pub enum TokenKind { /// the `lifetime` metavariable in the macro's RHS. NtLifetime(Ident, IdentIsRaw), - /// An embedded AST node, as produced by a macro. This only exists for - /// historical reasons. We'd like to get rid of it, for multiple reasons. - /// - It's conceptually very strange. Saying a token can contain an AST - /// node is like saying, in natural language, that a word can contain a - /// sentence. - /// - It requires special handling in a bunch of places in the parser. - /// - It prevents `Token` from implementing `Copy`. - /// It adds complexity and likely slows things down. Please don't add new - /// occurrences of this token kind! - /// - /// The span in the surrounding `Token` is that of the metavariable in the - /// macro's RHS. The span within the Nonterminal is that of the fragment - /// passed to the macro at the call site. - Interpolated(Arc), - /// A doc comment token. /// `Symbol` is the doc comment's data excluding its "quotes" (`///`, `/**`, etc) /// similarly to symbols in string literal tokens. @@ -492,20 +465,7 @@ pub enum TokenKind { Eof, } -impl Clone for TokenKind { - fn clone(&self) -> Self { - // `TokenKind` would impl `Copy` if it weren't for `Interpolated`. So - // for all other variants, this implementation of `clone` is just like - // a copy. This is faster than the `derive(Clone)` version which has a - // separate path for every variant. - match self { - Interpolated(nt) => Interpolated(Arc::clone(nt)), - _ => unsafe { std::ptr::read(self) }, - } - } -} - -#[derive(Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)] +#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)] pub struct Token { pub kind: TokenKind, pub span: Span, @@ -600,7 +560,7 @@ impl Token { | FatArrow | Pound | Dollar | Question | SingleQuote => true, OpenDelim(..) | CloseDelim(..) | Literal(..) | DocComment(..) | Ident(..) - | NtIdent(..) | Lifetime(..) | NtLifetime(..) | Interpolated(..) | Eof => false, + | NtIdent(..) | Lifetime(..) | NtLifetime(..) | Eof => false, } } @@ -631,7 +591,6 @@ impl Token { PathSep | // global path Lifetime(..) | // labeled loop Pound => true, // expression attributes - Interpolated(ref nt) => matches!(&**nt, NtBlock(..)), OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar( MetaVarKind::Block | MetaVarKind::Expr { .. } | @@ -703,7 +662,6 @@ impl Token { match self.kind { OpenDelim(Delimiter::Brace) | Literal(..) | Minus => true, Ident(name, IdentIsRaw::No) if name.is_bool_lit() => true, - Interpolated(ref nt) => matches!(&**nt, NtBlock(..)), OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar( MetaVarKind::Expr { .. } | MetaVarKind::Block | MetaVarKind::Literal, ))) => true, @@ -831,31 +789,20 @@ impl Token { /// Is this a pre-parsed expression dropped into the token stream /// (which happens while parsing the result of macro expansion)? pub fn is_metavar_expr(&self) -> bool { - #[allow(irrefutable_let_patterns)] // FIXME: temporary - if let Interpolated(nt) = &self.kind - && let NtBlock(_) = &**nt - { - true - } else if matches!( + matches!( self.is_metavar_seq(), - Some(MetaVarKind::Expr { .. } | MetaVarKind::Literal | MetaVarKind::Path) - ) { - true - } else { - matches!(self.is_metavar_seq(), Some(MetaVarKind::Path)) - } + Some( + MetaVarKind::Expr { .. } + | MetaVarKind::Literal + | MetaVarKind::Path + | MetaVarKind::Block + ) + ) } - /// Is the token an interpolated block (`$b:block`)? - pub fn is_whole_block(&self) -> bool { - #[allow(irrefutable_let_patterns)] // FIXME: temporary - if let Interpolated(nt) = &self.kind - && let NtBlock(..) = &**nt - { - return true; - } - - false + /// Are we at a block from a metavar (`$b:block`)? + pub fn is_metavar_block(&self) -> bool { + matches!(self.is_metavar_seq(), Some(MetaVarKind::Block)) } /// Returns `true` if the token is either the `mut` or `const` keyword. @@ -1024,7 +971,7 @@ impl Token { | PercentEq | CaretEq | AndEq | OrEq | ShlEq | ShrEq | At | DotDotDot | DotDotEq | Comma | Semi | PathSep | RArrow | LArrow | FatArrow | Pound | Dollar | Question | OpenDelim(..) | CloseDelim(..) | Literal(..) | Ident(..) | NtIdent(..) - | Lifetime(..) | NtLifetime(..) | Interpolated(..) | DocComment(..) | Eof, + | Lifetime(..) | NtLifetime(..) | DocComment(..) | Eof, _, ) => { return None; @@ -1063,12 +1010,6 @@ pub enum NtExprKind { Expr2021 { inferred: bool }, } -#[derive(Clone, Encodable, Decodable)] -/// For interpolation during macro expansion. -pub enum Nonterminal { - NtBlock(P), -} - #[derive(Debug, Copy, Clone, PartialEq, Eq, Encodable, Decodable, Hash, HashStable_Generic)] pub enum NonterminalKind { Item, @@ -1152,47 +1093,6 @@ impl fmt::Display for NonterminalKind { } } -impl Nonterminal { - pub fn use_span(&self) -> Span { - match self { - NtBlock(block) => block.span, - } - } - - pub fn descr(&self) -> &'static str { - match self { - NtBlock(..) => "block", - } - } -} - -impl PartialEq for Nonterminal { - fn eq(&self, _rhs: &Self) -> bool { - // FIXME: Assume that all nonterminals are not equal, we can't compare them - // correctly based on data from AST. This will prevent them from matching each other - // in macros. The comparison will become possible only when each nonterminal has an - // attached token stream from which it was parsed. - false - } -} - -impl fmt::Debug for Nonterminal { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match *self { - NtBlock(..) => f.pad("NtBlock(..)"), - } - } -} - -impl HashStable for Nonterminal -where - CTX: crate::HashStableContext, -{ - fn hash_stable(&self, _hcx: &mut CTX, _hasher: &mut StableHasher) { - panic!("interpolated tokens should not be present in the HIR") - } -} - // Some types are used a lot. Make sure they don't unintentionally get bigger. #[cfg(target_pointer_width = "64")] mod size_asserts { @@ -1202,7 +1102,6 @@ mod size_asserts { // tidy-alphabetical-start static_assert_size!(Lit, 12); static_assert_size!(LitKind, 2); - static_assert_size!(Nonterminal, 8); static_assert_size!(Token, 24); static_assert_size!(TokenKind, 16); // tidy-alphabetical-end diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index fb331e74aeb8..43d25d180750 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -25,7 +25,7 @@ use rustc_span::{DUMMY_SP, Span, SpanDecoder, SpanEncoder, Symbol, sym}; use crate::ast::AttrStyle; use crate::ast_traits::{HasAttrs, HasTokens}; -use crate::token::{self, Delimiter, InvisibleOrigin, Nonterminal, Token, TokenKind}; +use crate::token::{self, Delimiter, Token, TokenKind}; use crate::{AttrVec, Attribute}; /// Part of a `TokenStream`. @@ -305,11 +305,6 @@ pub struct AttrsTarget { } /// A `TokenStream` is an abstract sequence of tokens, organized into [`TokenTree`]s. -/// -/// The goal is for procedural macros to work with `TokenStream`s and `TokenTree`s -/// instead of a representation of the abstract syntax tree. -/// Today's `TokenTree`s can still contain AST via `token::Interpolated` for -/// backwards compatibility. #[derive(Clone, Debug, Default, Encodable, Decodable)] pub struct TokenStream(pub(crate) Arc>); @@ -476,61 +471,6 @@ impl TokenStream { TokenStream::new(tts) } - pub fn from_nonterminal_ast(nt: &Nonterminal) -> TokenStream { - match nt { - Nonterminal::NtBlock(block) => TokenStream::from_ast(block), - } - } - - fn flatten_token(token: &Token, spacing: Spacing) -> TokenTree { - match token.kind { - token::NtIdent(ident, is_raw) => { - TokenTree::Token(Token::new(token::Ident(ident.name, is_raw), ident.span), spacing) - } - token::NtLifetime(ident, is_raw) => TokenTree::Delimited( - DelimSpan::from_single(token.span), - DelimSpacing::new(Spacing::JointHidden, spacing), - Delimiter::Invisible(InvisibleOrigin::FlattenToken), - TokenStream::token_alone(token::Lifetime(ident.name, is_raw), ident.span), - ), - token::Interpolated(ref nt) => TokenTree::Delimited( - DelimSpan::from_single(token.span), - DelimSpacing::new(Spacing::JointHidden, spacing), - Delimiter::Invisible(InvisibleOrigin::FlattenToken), - TokenStream::from_nonterminal_ast(&nt).flattened(), - ), - _ => TokenTree::Token(token.clone(), spacing), - } - } - - fn flatten_token_tree(tree: &TokenTree) -> TokenTree { - match tree { - TokenTree::Token(token, spacing) => TokenStream::flatten_token(token, *spacing), - TokenTree::Delimited(span, spacing, delim, tts) => { - TokenTree::Delimited(*span, *spacing, *delim, tts.flattened()) - } - } - } - - #[must_use] - pub fn flattened(&self) -> TokenStream { - fn can_skip(stream: &TokenStream) -> bool { - stream.iter().all(|tree| match tree { - TokenTree::Token(token, _) => !matches!( - token.kind, - token::NtIdent(..) | token::NtLifetime(..) | token::Interpolated(..) - ), - TokenTree::Delimited(.., inner) => can_skip(inner), - }) - } - - if can_skip(self) { - return self.clone(); - } - - self.iter().map(|tree| TokenStream::flatten_token_tree(tree)).collect() - } - // If `vec` is not empty, try to glue `tt` onto its last token. The return // value indicates if gluing took place. fn try_glue_to_last(vec: &mut Vec, tt: &TokenTree) -> bool { diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 1ef92ff8898e..79193fcec63a 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -323,7 +323,7 @@ pub fn walk_crate<'a, V: Visitor<'a>>(visitor: &mut V, krate: &'a Crate) -> V::R } pub fn walk_local<'a, V: Visitor<'a>>(visitor: &mut V, local: &'a Local) -> V::Result { - let Local { id: _, pat, ty, kind, span: _, colon_sp: _, attrs, tokens: _ } = local; + let Local { id: _, super_: _, pat, ty, kind, span: _, colon_sp: _, attrs, tokens: _ } = local; walk_list!(visitor, visit_attribute, attrs); try_visit!(visitor.visit_pat(pat)); visit_opt!(visitor, visit_ty, ty); @@ -750,7 +750,7 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) -> V::Res try_visit!(visitor.visit_pat(subpattern)); try_visit!(visitor.visit_expr(guard_condition)); } - PatKind::Wild | PatKind::Rest | PatKind::Never => {} + PatKind::Missing | PatKind::Wild | PatKind::Rest | PatKind::Never => {} PatKind::Err(_guar) => {} PatKind::Tuple(elems) | PatKind::Slice(elems) | PatKind::Or(elems) => { walk_list!(visitor, visit_pat, elems); diff --git a/compiler/rustc_ast_lowering/src/block.rs b/compiler/rustc_ast_lowering/src/block.rs index 1d9ca6bb9c8c..c3222b79e55c 100644 --- a/compiler/rustc_ast_lowering/src/block.rs +++ b/compiler/rustc_ast_lowering/src/block.rs @@ -95,6 +95,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_local(&mut self, l: &Local) -> &'hir hir::LetStmt<'hir> { // Let statements are allowed to have impl trait in bindings. + let super_ = l.super_; let ty = l.ty.as_ref().map(|t| { self.lower_ty(t, self.impl_trait_in_bindings_ctxt(ImplTraitPosition::Variable)) }); @@ -109,7 +110,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let span = self.lower_span(l.span); let source = hir::LocalSource::Normal; self.lower_attrs(hir_id, &l.attrs, l.span); - self.arena.alloc(hir::LetStmt { hir_id, ty, pat, init, els, span, source }) + self.arena.alloc(hir::LetStmt { hir_id, super_, ty, pat, init, els, span, source }) } fn lower_block_check_mode(&mut self, b: &BlockCheckMode) -> hir::BlockCheckMode { diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs index 9899ee03a513..93c627f64c96 100644 --- a/compiler/rustc_ast_lowering/src/delegation.rs +++ b/compiler/rustc_ast_lowering/src/delegation.rs @@ -47,7 +47,7 @@ use rustc_errors::ErrorGuaranteed; use rustc_hir::def_id::DefId; use rustc_middle::span_bug; use rustc_middle::ty::{Asyncness, ResolverAstLowering}; -use rustc_span::{Ident, Span}; +use rustc_span::{Ident, Span, Symbol}; use {rustc_ast as ast, rustc_hir as hir}; use super::{GenericArgsMode, ImplTraitContext, LoweringContext, ParamMode}; @@ -85,7 +85,7 @@ impl<'hir> LoweringContext<'_, 'hir> { .delegation_fn_sigs .get(&local_def_id) .is_some_and(|sig| sig.has_self), - None => self.tcx.associated_item(def_id).fn_has_self_parameter, + None => self.tcx.associated_item(def_id).is_method(), }, _ => span_bug!(span, "unexpected DefKind for delegation item"), } @@ -234,12 +234,13 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::FnSig { decl, header, span } } - fn generate_param(&mut self, span: Span) -> (hir::Param<'hir>, NodeId) { + fn generate_param(&mut self, idx: usize, span: Span) -> (hir::Param<'hir>, NodeId) { let pat_node_id = self.next_node_id(); let pat_id = self.lower_node_id(pat_node_id); + let ident = Ident::with_dummy_span(Symbol::intern(&format!("arg{idx}"))); let pat = self.arena.alloc(hir::Pat { hir_id: pat_id, - kind: hir::PatKind::Binding(hir::BindingMode::NONE, pat_id, Ident::empty(), None), + kind: hir::PatKind::Binding(hir::BindingMode::NONE, pat_id, ident, None), span, default_binding_modes: false, }); @@ -247,9 +248,9 @@ impl<'hir> LoweringContext<'_, 'hir> { (hir::Param { hir_id: self.next_id(), pat, ty_span: span, span }, pat_node_id) } - fn generate_arg(&mut self, param_id: HirId, span: Span) -> hir::Expr<'hir> { + fn generate_arg(&mut self, idx: usize, param_id: HirId, span: Span) -> hir::Expr<'hir> { let segments = self.arena.alloc_from_iter(iter::once(hir::PathSegment { - ident: Ident::empty(), + ident: Ident::with_dummy_span(Symbol::intern(&format!("arg{idx}"))), hir_id: self.next_id(), res: Res::Local(param_id), args: None, @@ -273,7 +274,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let mut args: Vec> = Vec::with_capacity(param_count); for idx in 0..param_count { - let (param, pat_node_id) = this.generate_param(span); + let (param, pat_node_id) = this.generate_param(idx, span); parameters.push(param); let arg = if let Some(block) = block @@ -289,7 +290,7 @@ impl<'hir> LoweringContext<'_, 'hir> { this.ident_and_label_to_local_id.insert(pat_node_id, param.pat.hir_id.local_id); this.lower_target_expr(&block) } else { - this.generate_arg(param.pat.hir_id, span) + this.generate_arg(idx, param.pat.hir_id, span) }; args.push(arg); } diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index df4fd2ef52fe..8e1a3cd14354 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -399,12 +399,16 @@ impl<'hir> LoweringContext<'_, 'hir> { &mut self, expr: &'hir hir::Expr<'hir>, span: Span, - check_ident: Ident, - check_hir_id: HirId, + cond_ident: Ident, + cond_hir_id: HirId, ) -> &'hir hir::Expr<'hir> { - let checker_fn = self.expr_ident(span, check_ident, check_hir_id); - let span = self.mark_span_with_reason(DesugaringKind::Contract, span, None); - self.expr_call(span, checker_fn, std::slice::from_ref(expr)) + let cond_fn = self.expr_ident(span, cond_ident, cond_hir_id); + let call_expr = self.expr_call_lang_item_fn_mut( + span, + hir::LangItem::ContractCheckEnsures, + arena_vec![self; *cond_fn, *expr], + ); + self.arena.alloc(call_expr) } pub(crate) fn lower_const_block(&mut self, c: &AnonConst) -> hir::ConstBlock { diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 958a6917dff8..fc32c4efce56 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -645,7 +645,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ( // Disallow `impl Trait` in foreign items. this.lower_fn_decl(fdec, i.id, sig.span, FnDeclKind::ExternFn, None), - this.lower_fn_params_to_names(fdec), + this.lower_fn_params_to_idents(fdec), ) }); @@ -833,7 +833,7 @@ impl<'hir> LoweringContext<'_, 'hir> { }) => { // FIXME(contracts): Deny contract here since it won't apply to // any impl method or callees. - let names = self.lower_fn_params_to_names(&sig.decl); + let idents = self.lower_fn_params_to_idents(&sig.decl); let (generics, sig) = self.lower_method_sig( generics, sig, @@ -851,7 +851,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ( *ident, generics, - hir::TraitItemKind::Fn(sig, hir::TraitFn::Required(names)), + hir::TraitItemKind::Fn(sig, hir::TraitFn::Required(idents)), false, ) } @@ -1206,8 +1206,13 @@ impl<'hir> LoweringContext<'_, 'hir> { let precond = if let Some(req) = &contract.requires { // Lower the precondition check intrinsic. let lowered_req = this.lower_expr_mut(&req); + let req_span = this.mark_span_with_reason( + DesugaringKind::Contract, + lowered_req.span, + None, + ); let precond = this.expr_call_lang_item_fn_mut( - req.span, + req_span, hir::LangItem::ContractCheckRequires, &*arena_vec![this; lowered_req], ); @@ -1217,6 +1222,8 @@ impl<'hir> LoweringContext<'_, 'hir> { }; let (postcond, body) = if let Some(ens) = &contract.ensures { let ens_span = this.lower_span(ens.span); + let ens_span = + this.mark_span_with_reason(DesugaringKind::Contract, ens_span, None); // Set up the postcondition `let` statement. let check_ident: Ident = Ident::from_str_and_span("__ensures_checker", ens_span); @@ -1303,7 +1310,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // create a fake body so that the entire rest of the compiler doesn't have to deal with // this as a special case. return self.lower_fn_body(decl, contract, |this| { - if attrs.iter().any(|a| a.name_or_empty() == sym::rustc_intrinsic) { + if attrs.iter().any(|a| a.has_name(sym::rustc_intrinsic)) { let span = this.lower_span(span); let empty_block = hir::Block { hir_id: this.next_id(), diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index d5d6dcd8d631..c40987541f4a 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -32,7 +32,6 @@ // tidy-alphabetical-start #![allow(internal_features)] -#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![doc(rust_logo)] #![feature(assert_matches)] #![feature(box_patterns)] @@ -917,7 +916,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } fn lower_delim_args(&self, args: &DelimArgs) -> DelimArgs { - DelimArgs { dspan: args.dspan, delim: args.delim, tokens: args.tokens.flattened() } + DelimArgs { dspan: args.dspan, delim: args.delim, tokens: args.tokens.clone() } } /// Lower an associated item constraint. @@ -1247,7 +1246,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { safety: self.lower_safety(f.safety, hir::Safety::Safe), abi: self.lower_extern(f.ext), decl: self.lower_fn_decl(&f.decl, t.id, t.span, FnDeclKind::Pointer, None), - param_names: self.lower_fn_params_to_names(&f.decl), + param_idents: self.lower_fn_params_to_idents(&f.decl), })) } TyKind::UnsafeBinder(f) => { @@ -1494,20 +1493,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { })) } - fn lower_fn_params_to_names(&mut self, decl: &FnDecl) -> &'hir [Option] { + fn lower_fn_params_to_idents(&mut self, decl: &FnDecl) -> &'hir [Option] { self.arena.alloc_from_iter(decl.inputs.iter().map(|param| match param.pat.kind { - PatKind::Ident(_, ident, _) => { - if ident.name != kw::Empty { - Some(self.lower_ident(ident)) - } else { - None - } - } + PatKind::Missing => None, + PatKind::Ident(_, ident, _) => Some(self.lower_ident(ident)), PatKind::Wild => Some(Ident::new(kw::Underscore, self.lower_span(param.pat.span))), _ => { self.dcx().span_delayed_bug( param.pat.span, - "non-ident/wild param pat must trigger an error", + "non-missing/ident/wild param pat must trigger an error", ); None } @@ -1771,24 +1765,23 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ident: Ident, is_anon_in_path: IsAnonInPath, ) -> &'hir hir::Lifetime { - debug_assert_ne!(ident.name, kw::Empty); let res = self.resolver.get_lifetime_res(id).unwrap_or(LifetimeRes::Error); let res = match res { - LifetimeRes::Param { param, .. } => hir::LifetimeName::Param(param), + LifetimeRes::Param { param, .. } => hir::LifetimeKind::Param(param), LifetimeRes::Fresh { param, .. } => { debug_assert_eq!(ident.name, kw::UnderscoreLifetime); let param = self.local_def_id(param); - hir::LifetimeName::Param(param) + hir::LifetimeKind::Param(param) } LifetimeRes::Infer => { debug_assert_eq!(ident.name, kw::UnderscoreLifetime); - hir::LifetimeName::Infer + hir::LifetimeKind::Infer } LifetimeRes::Static { .. } => { debug_assert!(matches!(ident.name, kw::StaticLifetime | kw::UnderscoreLifetime)); - hir::LifetimeName::Static + hir::LifetimeKind::Static } - LifetimeRes::Error => hir::LifetimeName::Error, + LifetimeRes::Error => hir::LifetimeKind::Error, LifetimeRes::ElidedAnchor { .. } => { panic!("Unexpected `ElidedAnchar` {:?} at {:?}", ident, ident.span); } @@ -2039,7 +2032,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } fn lower_array_length_to_const_arg(&mut self, c: &AnonConst) -> &'hir hir::ConstArg<'hir> { - match c.value.kind { + // We cannot just match on `ExprKind::Underscore` as `(_)` is represented as + // `ExprKind::Paren(ExprKind::Underscore)` and should also be lowered to `GenericArg::Infer` + match c.value.peel_parens().kind { ExprKind::Underscore => { if !self.tcx.features().generic_arg_infer() { feature_err( @@ -2223,6 +2218,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.attrs.insert(hir_id.local_id, a); } let local = hir::LetStmt { + super_: None, hir_id, init, pat, @@ -2392,7 +2388,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let r = hir::Lifetime::new( self.next_id(), Ident::new(kw::UnderscoreLifetime, self.lower_span(span)), - hir::LifetimeName::ImplicitObjectLifetimeDefault, + hir::LifetimeKind::ImplicitObjectLifetimeDefault, IsAnonInPath::No, ); debug!("elided_dyn_bound: r={:?}", r); diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index 07cc64a1358e..f94d788a9b0e 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -26,6 +26,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let pat_hir_id = self.lower_node_id(pattern.id); let node = loop { match &pattern.kind { + PatKind::Missing => break hir::PatKind::Missing, PatKind::Wild => break hir::PatKind::Wild, PatKind::Never => break hir::PatKind::Never, PatKind::Ident(binding_mode, ident, sub) => { diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index c464c159c34c..0bd65aec10f4 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -448,8 +448,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { generic_args.args.insert_many( 0, - (start.as_u32()..end.as_u32()).map(|i| { - let id = NodeId::from_u32(i); + (start..end).map(|id| { let l = self.lower_lifetime_anon_in_path(id, elided_lifetime_span); GenericArg::Lifetime(l) }), diff --git a/compiler/rustc_ast_lowering/src/stability.rs b/compiler/rustc_ast_lowering/src/stability.rs index a2004bbb39f0..eb052ba1c6d7 100644 --- a/compiler/rustc_ast_lowering/src/stability.rs +++ b/compiler/rustc_ast_lowering/src/stability.rs @@ -79,10 +79,6 @@ pub fn extern_abi_stability(abi: ExternAbi) -> Result<(), UnstableAbi> { | ExternAbi::SysV64 { .. } | ExternAbi::System { .. } | ExternAbi::EfiApi => Ok(()), - // implementation details - ExternAbi::RustIntrinsic => { - Err(UnstableAbi { abi, feature: sym::intrinsics, explain: GateReason::ImplDetail }) - } ExternAbi::Unadjusted => { Err(UnstableAbi { abi, feature: sym::abi_unadjusted, explain: GateReason::ImplDetail }) } diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl index 25944392a52a..80754a8f65a6 100644 --- a/compiler/rustc_ast_passes/messages.ftl +++ b/compiler/rustc_ast_passes/messages.ftl @@ -79,6 +79,10 @@ ast_passes_extern_types_cannot = `type`s inside `extern` blocks cannot have {$de .suggestion = remove the {$remove_descr} .label = `extern` block begins here +ast_passes_extern_without_abi = `extern` declarations without an explicit ABI are disallowed + .suggestion = specify an ABI + .help = prior to Rust 2024, a default ABI was inferred + ast_passes_feature_on_non_nightly = `#![feature]` may not be used on the {$channel} release channel .suggestion = remove the attribute .stable_since = the feature `{$name}` has been stable since `{$since}` and no longer requires an attribute to enable diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 9916de8b7b13..1feb3e9bf9b4 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -244,7 +244,7 @@ impl<'a> AstValidator<'a> { fn check_decl_no_pat(decl: &FnDecl, mut report_err: impl FnMut(Span, Option, bool)) { for Param { pat, .. } in &decl.inputs { match pat.kind { - PatKind::Ident(BindingMode::NONE, _, None) | PatKind::Wild => {} + PatKind::Missing | PatKind::Ident(BindingMode::NONE, _, None) | PatKind::Wild => {} PatKind::Ident(BindingMode::MUT, ident, None) => { report_err(pat.span, Some(ident), true) } @@ -347,7 +347,7 @@ impl<'a> AstValidator<'a> { sym::forbid, sym::warn, ]; - !arr.contains(&attr.name_or_empty()) && rustc_attr_parsing::is_builtin_attr(*attr) + !attr.has_any_name(&arr) && rustc_attr_parsing::is_builtin_attr(*attr) }) .for_each(|attr| { if attr.is_doc_comment() { @@ -684,7 +684,7 @@ impl<'a> AstValidator<'a> { self.dcx().emit_err(errors::PatternFnPointer { span }); }); if let Extern::Implicit(extern_span) = bfty.ext { - self.maybe_lint_missing_abi(extern_span, ty.id); + self.handle_missing_abi(extern_span, ty.id); } } TyKind::TraitObject(bounds, ..) => { @@ -717,10 +717,12 @@ impl<'a> AstValidator<'a> { } } - fn maybe_lint_missing_abi(&mut self, span: Span, id: NodeId) { + fn handle_missing_abi(&mut self, span: Span, id: NodeId) { // FIXME(davidtwco): This is a hack to detect macros which produce spans of the // call site which do not have a macro backtrace. See #61963. - if self + if span.edition().at_least_edition_future() && self.features.explicit_extern_abis() { + self.dcx().emit_err(errors::MissingAbi { span }); + } else if self .sess .source_map() .span_to_snippet(span) @@ -945,8 +947,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.visit_attrs_vis_ident(&item.attrs, &item.vis, ident); self.check_defaultness(item.span, *defaultness); - let is_intrinsic = - item.attrs.iter().any(|a| a.name_or_empty() == sym::rustc_intrinsic); + let is_intrinsic = item.attrs.iter().any(|a| a.has_name(sym::rustc_intrinsic)); if body.is_none() && !is_intrinsic { self.dcx().emit_err(errors::FnWithoutBody { span: item.span, @@ -996,7 +997,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } if abi.is_none() { - self.maybe_lint_missing_abi(*extern_span, item.id); + self.handle_missing_abi(*extern_span, item.id); } self.with_in_extern_mod(*safety, |this| { visit::walk_item(this, item); @@ -1370,7 +1371,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { }, ) = fk { - self.maybe_lint_missing_abi(*extern_span, id); + self.handle_missing_abi(*extern_span, id); } // Functions without bodies cannot have patterns. diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index 8e53e600f7ac..6f9737e08314 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -2,7 +2,7 @@ use rustc_ast::ParamKindOrd; use rustc_errors::codes::*; -use rustc_errors::{Applicability, Diag, EmissionGuarantee, SubdiagMessageOp, Subdiagnostic}; +use rustc_errors::{Applicability, Diag, EmissionGuarantee, Subdiagnostic}; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::{Ident, Span, Symbol}; @@ -394,11 +394,7 @@ pub(crate) struct EmptyLabelManySpans(pub Vec); // The derive for `Vec` does multiple calls to `span_label`, adding commas between each impl Subdiagnostic for EmptyLabelManySpans { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { diag.span_labels(self.0, ""); } } @@ -749,11 +745,7 @@ pub(crate) struct StableFeature { } impl Subdiagnostic for StableFeature { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { diag.arg("name", self.name); diag.arg("since", self.since); diag.help(fluent::ast_passes_stable_since); @@ -823,3 +815,12 @@ pub(crate) struct DuplicatePreciseCapturing { #[label] pub bound2: Span, } + +#[derive(Diagnostic)] +#[diag(ast_passes_extern_without_abi)] +#[help] +pub(crate) struct MissingAbi { + #[primary_span] + #[suggestion(code = "extern \"\"", applicability = "has-placeholders")] + pub span: Span, +} diff --git a/compiler/rustc_ast_pretty/src/pprust/mod.rs b/compiler/rustc_ast_pretty/src/pprust/mod.rs index 97cb6e52d562..551506f2aef8 100644 --- a/compiler/rustc_ast_pretty/src/pprust/mod.rs +++ b/compiler/rustc_ast_pretty/src/pprust/mod.rs @@ -5,14 +5,10 @@ pub mod state; use std::borrow::Cow; use rustc_ast as ast; -use rustc_ast::token::{Nonterminal, Token, TokenKind}; +use rustc_ast::token::{Token, TokenKind}; use rustc_ast::tokenstream::{TokenStream, TokenTree}; pub use state::{AnnNode, Comments, PpAnn, PrintState, State, print_crate}; -pub fn nonterminal_to_string(nt: &Nonterminal) -> String { - State::new().nonterminal_to_string(nt) -} - /// Print the token kind precisely, without converting `$crate` into its respective crate name. pub fn token_kind_to_string(tok: &TokenKind) -> Cow<'static, str> { State::new().token_kind_to_string(tok) diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 3dbfc191f8f5..0985ebf945bb 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -11,7 +11,7 @@ use std::sync::Arc; use rustc_ast::attr::AttrIdGenerator; use rustc_ast::ptr::P; -use rustc_ast::token::{self, CommentKind, Delimiter, IdentIsRaw, Nonterminal, Token, TokenKind}; +use rustc_ast::token::{self, CommentKind, Delimiter, IdentIsRaw, Token, TokenKind}; use rustc_ast::tokenstream::{Spacing, TokenStream, TokenTree}; use rustc_ast::util::classify; use rustc_ast::util::comments::{Comment, CommentStyle}; @@ -876,14 +876,6 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere } } - fn nonterminal_to_string(&self, nt: &Nonterminal) -> String { - // We extract the token stream from the AST fragment and pretty print - // it, rather than using AST pretty printing, because `Nonterminal` is - // slated for removal in #124141. (This method will also then be - // removed.) - self.tts_to_string(&TokenStream::from_nonterminal_ast(nt)) - } - /// Print the token kind precisely, without converting `$crate` into its respective crate name. fn token_kind_to_string(&self, tok: &TokenKind) -> Cow<'static, str> { self.token_kind_to_string_ext(tok, None) @@ -976,8 +968,6 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere doc_comment_to_string(comment_kind, attr_style, data).into() } token::Eof => "".into(), - - token::Interpolated(ref nt) => self.nonterminal_to_string(&nt).into(), } } @@ -1336,6 +1326,9 @@ impl<'a> State<'a> { self.print_outer_attributes(&loc.attrs); self.space_if_not_bol(); self.ibox(INDENT_UNIT); + if loc.super_.is_some() { + self.word_nbsp("super"); + } self.word_nbsp("let"); self.ibox(INDENT_UNIT); @@ -1622,9 +1615,9 @@ impl<'a> State<'a> { fn print_pat(&mut self, pat: &ast::Pat) { self.maybe_print_comment(pat.span.lo()); self.ann.pre(self, AnnNode::Pat(pat)); - /* Pat isn't normalized, but the beauty of it - is that it doesn't matter */ + /* Pat isn't normalized, but the beauty of it is that it doesn't matter */ match &pat.kind { + PatKind::Missing => unreachable!(), PatKind::Wild => self.word("_"), PatKind::Never => self.word("!"), PatKind::Ident(BindingMode(by_ref, mutbl), ident, sub) => { @@ -1946,12 +1939,7 @@ impl<'a> State<'a> { if let Some(eself) = input.to_self() { self.print_explicit_self(&eself); } else { - let invalid = if let PatKind::Ident(_, ident, _) = input.pat.kind { - ident.name == kw::Empty - } else { - false - }; - if !invalid { + if !matches!(input.pat.kind, PatKind::Missing) { self.print_pat(&input.pat); self.word(":"); self.space(); diff --git a/compiler/rustc_ast_pretty/src/pprust/tests.rs b/compiler/rustc_ast_pretty/src/pprust/tests.rs index 4c42dd1f2023..bc7f22766a5c 100644 --- a/compiler/rustc_ast_pretty/src/pprust/tests.rs +++ b/compiler/rustc_ast_pretty/src/pprust/tests.rs @@ -7,12 +7,12 @@ use super::*; fn fun_to_string( decl: &ast::FnDecl, header: ast::FnHeader, - name: Ident, + ident: Ident, generics: &ast::Generics, ) -> String { to_string(|s| { s.head(""); - s.print_fn(decl, header, Some(name), generics); + s.print_fn(decl, header, Some(ident), generics); s.end(); // Close the head box. s.end(); // Close the outer box. }) diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg.rs b/compiler/rustc_attr_parsing/src/attributes/cfg.rs index 0d6d521b40c6..7cb1fede1741 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg.rs @@ -7,7 +7,6 @@ use rustc_session::config::ExpectedValues; use rustc_session::lint::BuiltinLintDiag; use rustc_session::lint::builtin::UNEXPECTED_CFGS; use rustc_session::parse::feature_err; -use rustc_span::symbol::kw; use rustc_span::{Span, Symbol, sym}; use crate::session_diagnostics::{self, UnsupportedLiteralReason}; @@ -89,20 +88,6 @@ pub fn eval_condition( let cfg = match cfg { MetaItemInner::MetaItem(meta_item) => meta_item, MetaItemInner::Lit(MetaItemLit { kind: LitKind::Bool(b), .. }) => { - if let Some(features) = features { - // we can't use `try_gate_cfg` as symbols don't differentiate between `r#true` - // and `true`, and we want to keep the former working without feature gate - gate_cfg( - &( - if *b { kw::True } else { kw::False }, - sym::cfg_boolean_literals, - |features: &Features| features.cfg_boolean_literals(), - ), - cfg.span(), - sess, - features, - ); - } return *b; } _ => { @@ -117,7 +102,7 @@ pub fn eval_condition( }; match &cfg.kind { - MetaItemKind::List(mis) if cfg.name_or_empty() == sym::version => { + MetaItemKind::List(mis) if cfg.has_name(sym::version) => { try_gate_cfg(sym::version, cfg.span, sess, features); let (min_version, span) = match &mis[..] { [MetaItemInner::Lit(MetaItemLit { kind: LitKind::Str(sym, ..), span, .. })] => { @@ -164,18 +149,18 @@ pub fn eval_condition( // The unwraps below may look dangerous, but we've already asserted // that they won't fail with the loop above. - match cfg.name_or_empty() { - sym::any => mis + match cfg.name() { + Some(sym::any) => mis .iter() // We don't use any() here, because we want to evaluate all cfg condition // as eval_condition can (and does) extra checks .fold(false, |res, mi| res | eval_condition(mi, sess, features, eval)), - sym::all => mis + Some(sym::all) => mis .iter() // We don't use all() here, because we want to evaluate all cfg condition // as eval_condition can (and does) extra checks .fold(true, |res, mi| res & eval_condition(mi, sess, features, eval)), - sym::not => { + Some(sym::not) => { let [mi] = mis.as_slice() else { dcx.emit_err(session_diagnostics::ExpectedOneCfgPattern { span: cfg.span }); return false; @@ -183,7 +168,7 @@ pub fn eval_condition( !eval_condition(mi, sess, features, eval) } - sym::target => { + Some(sym::target) => { if let Some(features) = features && !features.cfg_target_compact() { diff --git a/compiler/rustc_attr_parsing/src/attributes/transparency.rs b/compiler/rustc_attr_parsing/src/attributes/transparency.rs index ad83a1f7af80..ce42b0507ed5 100644 --- a/compiler/rustc_attr_parsing/src/attributes/transparency.rs +++ b/compiler/rustc_attr_parsing/src/attributes/transparency.rs @@ -20,7 +20,7 @@ impl SingleAttributeParser for TransparencyParser { fn convert(cx: &AcceptContext<'_>, args: &ArgParser<'_>) -> Option { match args.name_value().and_then(|nv| nv.value_as_str()) { Some(sym::transparent) => Some(Transparency::Transparent), - Some(sym::semitransparent) => Some(Transparency::SemiTransparent), + Some(sym::semiopaque | sym::semitransparent) => Some(Transparency::SemiOpaque), Some(sym::opaque) => Some(Transparency::Opaque), Some(other) => { cx.dcx().span_err(cx.attr_span, format!("unknown macro transparency: `{other}`")); diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index a68d4578b40f..972614a3366c 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -222,7 +222,7 @@ impl<'sess> AttributeParser<'sess> { // if we're only looking for a single attribute, // skip all the ones we don't care about if let Some(expected) = self.parse_only { - if attr.name_or_empty() != expected { + if !attr.has_name(expected) { continue; } } @@ -232,7 +232,7 @@ impl<'sess> AttributeParser<'sess> { // that's expanded right? But no, sometimes, when parsing attributes on macros, // we already use the lowering logic and these are still there. So, when `omit_doc` // is set we *also* want to ignore these - if omit_doc == OmitDoc::Skip && attr.name_or_empty() == sym::doc { + if omit_doc == OmitDoc::Skip && attr.has_name(sym::doc) { continue; } @@ -250,7 +250,7 @@ impl<'sess> AttributeParser<'sess> { })) } // // FIXME: make doc attributes go through a proper attribute parser - // ast::AttrKind::Normal(n) if n.name_or_empty() == sym::doc => { + // ast::AttrKind::Normal(n) if n.has_name(sym::doc) => { // let p = GenericMetaItemParser::from_attr(&n, self.dcx()); // // attributes.push(Attribute::Parsed(AttributeKind::DocComment { @@ -320,7 +320,7 @@ impl<'sess> AttributeParser<'sess> { ast::AttrArgs::Delimited(args) => AttrArgs::Delimited(DelimArgs { dspan: args.dspan, delim: args.delim, - tokens: args.tokens.flattened(), + tokens: args.tokens.clone(), }), // This is an inert key-value attribute - it will never be visible to macros // after it gets lowered to HIR. Therefore, we can extract literals to handle diff --git a/compiler/rustc_attr_parsing/src/lib.rs b/compiler/rustc_attr_parsing/src/lib.rs index a7465847e18b..249e71ef70dc 100644 --- a/compiler/rustc_attr_parsing/src/lib.rs +++ b/compiler/rustc_attr_parsing/src/lib.rs @@ -77,7 +77,6 @@ // tidy-alphabetical-start #![allow(internal_features)] -#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![doc(rust_logo)] #![feature(let_chains)] #![feature(rustdoc_internals)] diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs index a8a1460591cf..384fae59873f 100644 --- a/compiler/rustc_attr_parsing/src/parser.rs +++ b/compiler/rustc_attr_parsing/src/parser.rs @@ -485,25 +485,7 @@ impl<'a> MetaItemListParserContext<'a> { } // or a path. - let path = - if let Some(TokenTree::Token(Token { kind: token::Interpolated(_), span, .. }, _)) = - self.inside_delimiters.peek() - { - self.inside_delimiters.next(); - // We go into this path if an expr ended up in an attribute that - // expansion did not turn into a literal. Say, `#[repr(align(macro!()))]` - // where the macro didn't expand to a literal. An error is already given - // for this at this point, and then we do continue. This makes this path - // reachable... - let e = self.dcx.span_delayed_bug( - *span, - "expr in place where literal is expected (builtin attr parsing)", - ); - - return Some(MetaItemOrLitParser::Err(*span, e)); - } else { - self.next_path()? - }; + let path = self.next_path()?; // Paths can be followed by: // - `(more meta items)` (another list) diff --git a/compiler/rustc_borrowck/src/consumers.rs b/compiler/rustc_borrowck/src/consumers.rs index 45cdd2325647..1f087b092346 100644 --- a/compiler/rustc_borrowck/src/consumers.rs +++ b/compiler/rustc_borrowck/src/consumers.rs @@ -15,6 +15,7 @@ pub use super::polonius::legacy::{ RichLocation, RustcFacts, }; pub use super::region_infer::RegionInferenceContext; +use crate::{BorrowCheckRootCtxt, do_mir_borrowck}; /// Options determining the output behavior of [`get_body_with_borrowck_facts`]. /// @@ -97,8 +98,9 @@ pub struct BodyWithBorrowckFacts<'tcx> { /// * Polonius is highly unstable, so expect regular changes in its signature or other details. pub fn get_body_with_borrowck_facts( tcx: TyCtxt<'_>, - def: LocalDefId, + def_id: LocalDefId, options: ConsumerOptions, ) -> BodyWithBorrowckFacts<'_> { - *super::do_mir_borrowck(tcx, def, Some(options)).1.unwrap() + let mut root_cx = BorrowCheckRootCtxt::new(tcx, def_id); + *do_mir_borrowck(&mut root_cx, def_id, Some(options)).1.unwrap() } diff --git a/compiler/rustc_borrowck/src/def_use.rs b/compiler/rustc_borrowck/src/def_use.rs index 263f68d6a3dc..b9ced81c46c1 100644 --- a/compiler/rustc_borrowck/src/def_use.rs +++ b/compiler/rustc_borrowck/src/def_use.rs @@ -77,6 +77,9 @@ pub(crate) fn categorize(context: PlaceContext) -> Option { // Debug info is neither def nor use. PlaceContext::NonUse(NonUseContext::VarDebugInfo) => None, + // Backwards incompatible drop hint is not a use, just a marker for linting. + PlaceContext::NonUse(NonUseContext::BackwardIncompatibleDropHint) => None, + PlaceContext::MutatingUse(MutatingUseContext::Deinit | MutatingUseContext::SetDiscriminant) => { bug!("These statements are not allowed in this MIR phase") } diff --git a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs index aa968a1e40f3..134f30ed6f54 100644 --- a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs @@ -406,8 +406,8 @@ impl<'tcx> TypeOpInfo<'tcx> for crate::type_check::InstantiateOpaqueType<'tcx> { // started MIR borrowchecking with, so the region // constraints have already been taken. Use the data from // our `mbcx` instead. - |vid| mbcx.regioncx.var_infos[vid].origin, - |vid| mbcx.regioncx.var_infos[vid].universe, + |vid| RegionVariableOrigin::Nll(mbcx.regioncx.definitions[vid].origin), + |vid| mbcx.regioncx.definitions[vid].universe, ) } } @@ -487,7 +487,7 @@ fn try_extract_error_from_region_constraints<'a, 'tcx>( let (sub_region, cause) = info?; debug!(?sub_region, "cause = {:#?}", cause); - let error = match (error_region, *sub_region) { + let error = match (error_region, sub_region.kind()) { (Some(error_region), ty::ReVar(vid)) => RegionResolutionError::SubSupConflict( vid, region_var_origin(vid), diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 1f4eb0c449f8..cf735815fd2b 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -647,7 +647,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { && tc.polarity() == ty::PredicatePolarity::Positive && supertrait_def_ids(tcx, tc.def_id()) .flat_map(|trait_did| tcx.associated_items(trait_did).in_definition_order()) - .any(|item| item.fn_has_self_parameter) + .any(|item| item.is_method()) }) }) { return None; @@ -2500,11 +2500,11 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { ); let ty::Tuple(params) = tupled_params.kind() else { return }; - // Find the first argument with a matching type, get its name - let Some(this_name) = params.iter().zip(tcx.hir_body_param_names(closure.body)).find_map( - |(param_ty, name)| { + // Find the first argument with a matching type and get its identifier. + let Some(this_name) = params.iter().zip(tcx.hir_body_param_idents(closure.body)).find_map( + |(param_ty, ident)| { // FIXME: also support deref for stuff like `Rc` arguments - if param_ty.peel_refs() == local_ty { name } else { None } + if param_ty.peel_refs() == local_ty { ident } else { None } }, ) else { return; @@ -2959,21 +2959,27 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { } } - let mut err = self.path_does_not_live_long_enough(borrow_span, &format!("`{name}`")); + let name = if borrow_span.in_external_macro(self.infcx.tcx.sess.source_map()) { + // Don't name local variables in external macros. + "value".to_string() + } else { + format!("`{name}`") + }; + + let mut err = self.path_does_not_live_long_enough(borrow_span, &name); if let Some(annotation) = self.annotate_argument_and_return_for_borrow(borrow) { let region_name = annotation.emit(self, &mut err); err.span_label( borrow_span, - format!("`{name}` would have to be valid for `{region_name}`..."), + format!("{name} would have to be valid for `{region_name}`..."), ); err.span_label( drop_span, format!( - "...but `{}` will be dropped here, when the {} returns", - name, + "...but {name} will be dropped here, when the {} returns", self.infcx .tcx .opt_item_name(self.mir_def_id().to_def_id()) @@ -3011,7 +3017,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { } } else { err.span_label(borrow_span, "borrowed value does not live long enough"); - err.span_label(drop_span, format!("`{name}` dropped here while still borrowed")); + err.span_label(drop_span, format!("{name} dropped here while still borrowed")); borrow_spans.args_subdiag(&mut err, |args_span| { crate::session_diagnostics::CaptureArgLabel::Capture { @@ -3376,10 +3382,15 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { let (sugg_span, suggestion) = match tcx.sess.source_map().span_to_snippet(args_span) { Ok(string) => { - let coro_prefix = if string.starts_with("async") { - // `async` is 5 chars long. Not using `.len()` to avoid the cast from `usize` - // to `u32`. - Some(5) + let coro_prefix = if let Some(sub) = string.strip_prefix("async") { + let trimmed_sub = sub.trim_end(); + if trimmed_sub.ends_with("gen") { + // `async` is 5 chars long. + Some((trimmed_sub.len() + 5) as _) + } else { + // `async` is 5 chars long. + Some(5) + } } else if string.starts_with("gen") { // `gen` is 3 chars long Some(3) @@ -3774,7 +3785,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { method_args, *fn_span, call_source.from_hir_call(), - self.infcx.tcx.fn_arg_names(method_did)[0], + self.infcx.tcx.fn_arg_idents(method_did)[0], ) { err.note(format!("borrow occurs due to deref coercion to `{deref_target_ty}`")); diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs index f77dda0d386a..a845431facac 100644 --- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs +++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs @@ -95,7 +95,9 @@ impl<'tcx> BorrowExplanation<'tcx> { && let hir::def::Res::Local(hir_id) = p.res && let hir::Node::Pat(pat) = tcx.hir_node(hir_id) { - err.span_label(pat.span, format!("binding `{ident}` declared here")); + if !ident.span.in_external_macro(tcx.sess.source_map()) { + err.span_label(pat.span, format!("binding `{ident}` declared here")); + } } } } diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 899e145c2c04..f9f63ae92a84 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -8,9 +8,7 @@ use rustc_errors::{Applicability, Diag, EmissionGuarantee, MultiSpan, listify}; use rustc_hir::def::{CtorKind, Namespace}; use rustc_hir::{self as hir, CoroutineKind, LangItem}; use rustc_index::IndexSlice; -use rustc_infer::infer::{ - BoundRegionConversionTime, NllRegionVariableOrigin, RegionVariableOrigin, -}; +use rustc_infer::infer::{BoundRegionConversionTime, NllRegionVariableOrigin}; use rustc_infer::traits::SelectionError; use rustc_middle::bug; use rustc_middle::mir::{ @@ -587,7 +585,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { // this by hooking into the pretty printer and telling it to label the // lifetimes without names with the value `'0`. if let ty::Ref(region, ..) = ty.kind() { - match **region { + match region.kind() { ty::ReBound(_, ty::BoundRegion { kind: br, .. }) | ty::RePlaceholder(ty::PlaceholderRegion { bound: ty::BoundRegion { kind: br, .. }, @@ -607,7 +605,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { let mut printer = ty::print::FmtPrinter::new(self.infcx.tcx, Namespace::TypeNS); let region = if let ty::Ref(region, ..) = ty.kind() { - match **region { + match region.kind() { ty::ReBound(_, ty::BoundRegion { kind: br, .. }) | ty::RePlaceholder(ty::PlaceholderRegion { bound: ty::BoundRegion { kind: br, .. }, @@ -633,9 +631,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { ) { let predicate_span = path.iter().find_map(|constraint| { let outlived = constraint.sub; - if let Some(origin) = self.regioncx.var_infos.get(outlived) - && let RegionVariableOrigin::Nll(NllRegionVariableOrigin::Placeholder(_)) = - origin.origin + if let Some(origin) = self.regioncx.definitions.get(outlived) + && let NllRegionVariableOrigin::Placeholder(_) = origin.origin && let ConstraintCategory::Predicate(span) = constraint.category { Some(span) @@ -1029,7 +1026,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { method_args, *fn_span, call_source.from_hir_call(), - self.infcx.tcx.fn_arg_names(method_did)[0], + self.infcx.tcx.fn_arg_idents(method_did)[0], ); return FnSelfUse { diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index d1d783c22e35..4423edb06051 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -190,7 +190,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { where T: TypeFoldable>, { - fold_regions(tcx, ty, |region, _| match *region { + fold_regions(tcx, ty, |region, _| match region.kind() { ty::ReVar(vid) => self.to_error_region(vid).unwrap_or(region), _ => region, }) @@ -198,7 +198,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { /// Returns `true` if a closure is inferred to be an `FnMut` closure. fn is_closure_fn_mut(&self, fr: RegionVid) -> bool { - if let Some(ty::ReLateParam(late_param)) = self.to_error_region(fr).as_deref() + if let Some(r) = self.to_error_region(fr) + && let ty::ReLateParam(late_param) = r.kind() && let ty::LateParamRegionKind::ClosureEnv = late_param.kind && let DefiningTy::Closure(_, args) = self.regioncx.universal_regions().defining_ty { @@ -832,7 +833,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { if let (Some(f), Some(outlived_f)) = (self.to_error_region(fr), self.to_error_region(outlived_fr)) { - if *outlived_f != ty::ReStatic { + if outlived_f.kind() != ty::ReStatic { return; } let suitable_region = self.infcx.tcx.is_suitable_region(self.mir_def_id(), f); @@ -887,7 +888,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { // Skip `async` desugaring `impl Future`. } if let TyKind::TraitObject(_, lt) = alias_ty.kind { - if lt.res == hir::LifetimeName::ImplicitObjectLifetimeDefault { + if lt.kind == hir::LifetimeKind::ImplicitObjectLifetimeDefault { spans_suggs.push((lt.ident.span.shrink_to_hi(), " + 'a".to_string())); } else { spans_suggs.push((lt.ident.span, "'a".to_string())); diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index 45f5eaa514b2..b08c10983bbc 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -288,7 +288,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { let tcx = self.infcx.tcx; debug!("give_region_a_name: error_region = {:?}", error_region); - match *error_region { + match error_region.kind() { ty::ReEarlyParam(ebr) => ebr.has_name().then(|| { let def_id = tcx.generics_of(self.mir_def_id()).region_param(ebr, tcx).def_id; let span = tcx.hir_span_if_local(def_id).unwrap_or(DUMMY_SP); @@ -896,7 +896,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { &self, fr: RegionVid, ) -> Option { - let ty::ReEarlyParam(region) = *self.to_error_region(fr)? else { + let ty::ReEarlyParam(region) = self.to_error_region(fr)?.kind() else { return None; }; if region.has_name() { @@ -912,7 +912,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { let found = tcx .any_free_region_meets(&tcx.type_of(region_parent).instantiate_identity(), |r| { - *r == ty::ReEarlyParam(region) + r.kind() == ty::ReEarlyParam(region) }); Some(RegionName { @@ -931,7 +931,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { &self, fr: RegionVid, ) -> Option { - let ty::ReEarlyParam(region) = *self.to_error_region(fr)? else { + let ty::ReEarlyParam(region) = self.to_error_region(fr)?.kind() else { return None; }; if region.has_name() { @@ -1007,7 +1007,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { if data.projection_term.self_ty() == ty => {} _ => return false, } - tcx.any_free_region_meets(pred, |r| *r == ty::ReEarlyParam(region)) + tcx.any_free_region_meets(pred, |r| r.kind() == ty::ReEarlyParam(region)) }) } else { false diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 240bd20053b1..3b66142eb2ce 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -2,13 +2,13 @@ // tidy-alphabetical-start #![allow(internal_features)] -#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![doc(rust_logo)] #![feature(assert_matches)] #![feature(box_patterns)] #![feature(file_buffered)] #![feature(if_let_guard)] #![feature(let_chains)] +#![feature(negative_impls)] #![feature(never_type)] #![feature(rustc_attrs)] #![feature(rustdoc_internals)] @@ -21,6 +21,8 @@ use std::cell::RefCell; use std::marker::PhantomData; use std::ops::{ControlFlow, Deref}; +use borrow_set::LocalsStateAtExit; +use root_cx::BorrowCheckRootCtxt; use rustc_abi::FieldIdx; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::graph::dominators::Dominators; @@ -35,7 +37,9 @@ use rustc_infer::infer::{ }; use rustc_middle::mir::*; use rustc_middle::query::Providers; -use rustc_middle::ty::{self, ParamEnv, RegionVid, TyCtxt, TypingMode}; +use rustc_middle::ty::{ + self, ParamEnv, RegionVid, Ty, TyCtxt, TypeFoldable, TypeVisitable, TypingMode, fold_regions, +}; use rustc_middle::{bug, span_bug}; use rustc_mir_dataflow::impls::{ EverInitializedPlaces, MaybeInitializedPlaces, MaybeUninitializedPlaces, @@ -45,7 +49,7 @@ use rustc_mir_dataflow::move_paths::{ }; use rustc_mir_dataflow::{Analysis, EntryStates, Results, ResultsVisitor, visit_results}; use rustc_session::lint::builtin::{TAIL_EXPR_DROP_ORDER, UNUSED_MUT}; -use rustc_span::{Span, Symbol}; +use rustc_span::{ErrorGuaranteed, Span, Symbol}; use smallvec::SmallVec; use tracing::{debug, instrument}; @@ -73,7 +77,6 @@ mod def_use; mod diagnostics; mod member_constraints; mod nll; -mod opaque_types; mod path_utils; mod place_ext; mod places_conflict; @@ -81,6 +84,7 @@ mod polonius; mod prefixes; mod region_infer; mod renumber; +mod root_cx; mod session_diagnostics; mod type_check; mod universal_regions; @@ -102,64 +106,202 @@ pub fn provide(providers: &mut Providers) { *providers = Providers { mir_borrowck, ..*providers }; } -fn mir_borrowck(tcx: TyCtxt<'_>, def: LocalDefId) -> &BorrowCheckResult<'_> { +/// Provider for `query mir_borrowck`. Similar to `typeck`, this must +/// only be called for typeck roots which will then borrowck all +/// nested bodies as well. +fn mir_borrowck( + tcx: TyCtxt<'_>, + def: LocalDefId, +) -> Result<&ConcreteOpaqueTypes<'_>, ErrorGuaranteed> { + assert!(!tcx.is_typeck_child(def.to_def_id())); let (input_body, _) = tcx.mir_promoted(def); + debug!("run query mir_borrowck: {}", tcx.def_path_str(def)); + let input_body: &Body<'_> = &input_body.borrow(); - if input_body.should_skip() || input_body.tainted_by_errors.is_some() { - debug!("Skipping borrowck because of injected body or tainted body"); - // Let's make up a borrowck result! Fun times! - let result = BorrowCheckResult { - concrete_opaque_types: FxIndexMap::default(), - closure_requirements: None, - used_mut_upvars: SmallVec::new(), - tainted_by_errors: input_body.tainted_by_errors, - }; - return tcx.arena.alloc(result); + if let Some(guar) = input_body.tainted_by_errors { + debug!("Skipping borrowck because of tainted body"); + Err(guar) + } else if input_body.should_skip() { + debug!("Skipping borrowck because of injected body"); + let opaque_types = ConcreteOpaqueTypes(Default::default()); + Ok(tcx.arena.alloc(opaque_types)) + } else { + let mut root_cx = BorrowCheckRootCtxt::new(tcx, def); + let PropagatedBorrowCheckResults { closure_requirements, used_mut_upvars } = + do_mir_borrowck(&mut root_cx, def, None).0; + debug_assert!(closure_requirements.is_none()); + debug_assert!(used_mut_upvars.is_empty()); + root_cx.finalize() + } +} + +/// Data propagated to the typeck parent by nested items. +/// This should always be empty for the typeck root. +#[derive(Debug)] +struct PropagatedBorrowCheckResults<'tcx> { + closure_requirements: Option>, + used_mut_upvars: SmallVec<[FieldIdx; 8]>, +} + +/// After we borrow check a closure, we are left with various +/// requirements that we have inferred between the free regions that +/// appear in the closure's signature or on its field types. These +/// requirements are then verified and proved by the closure's +/// creating function. This struct encodes those requirements. +/// +/// The requirements are listed as being between various `RegionVid`. The 0th +/// region refers to `'static`; subsequent region vids refer to the free +/// regions that appear in the closure (or coroutine's) type, in order of +/// appearance. (This numbering is actually defined by the `UniversalRegions` +/// struct in the NLL region checker. See for example +/// `UniversalRegions::closure_mapping`.) Note the free regions in the +/// closure's signature and captures are erased. +/// +/// Example: If type check produces a closure with the closure args: +/// +/// ```text +/// ClosureArgs = [ +/// 'a, // From the parent. +/// 'b, +/// i8, // the "closure kind" +/// for<'x> fn(&' &'x u32) -> &'x u32, // the "closure signature" +/// &' String, // some upvar +/// ] +/// ``` +/// +/// We would "renumber" each free region to a unique vid, as follows: +/// +/// ```text +/// ClosureArgs = [ +/// '1, // From the parent. +/// '2, +/// i8, // the "closure kind" +/// for<'x> fn(&'3 &'x u32) -> &'x u32, // the "closure signature" +/// &'4 String, // some upvar +/// ] +/// ``` +/// +/// Now the code might impose a requirement like `'1: '2`. When an +/// instance of the closure is created, the corresponding free regions +/// can be extracted from its type and constrained to have the given +/// outlives relationship. +#[derive(Clone, Debug)] +pub struct ClosureRegionRequirements<'tcx> { + /// The number of external regions defined on the closure. In our + /// example above, it would be 3 -- one for `'static`, then `'1` + /// and `'2`. This is just used for a sanity check later on, to + /// make sure that the number of regions we see at the callsite + /// matches. + pub num_external_vids: usize, + + /// Requirements between the various free regions defined in + /// indices. + pub outlives_requirements: Vec>, +} + +/// Indicates an outlives-constraint between a type or between two +/// free regions declared on the closure. +#[derive(Copy, Clone, Debug)] +pub struct ClosureOutlivesRequirement<'tcx> { + // This region or type ... + pub subject: ClosureOutlivesSubject<'tcx>, + + // ... must outlive this one. + pub outlived_free_region: ty::RegionVid, + + // If not, report an error here ... + pub blame_span: Span, + + // ... due to this reason. + pub category: ConstraintCategory<'tcx>, +} + +// Make sure this enum doesn't unintentionally grow +#[cfg(target_pointer_width = "64")] +rustc_data_structures::static_assert_size!(ConstraintCategory<'_>, 16); + +/// The subject of a `ClosureOutlivesRequirement` -- that is, the thing +/// that must outlive some region. +#[derive(Copy, Clone, Debug)] +pub enum ClosureOutlivesSubject<'tcx> { + /// Subject is a type, typically a type parameter, but could also + /// be a projection. Indicates a requirement like `T: 'a` being + /// passed to the caller, where the type here is `T`. + Ty(ClosureOutlivesSubjectTy<'tcx>), + + /// Subject is a free region from the closure. Indicates a requirement + /// like `'a: 'b` being passed to the caller; the region here is `'a`. + Region(ty::RegionVid), +} + +/// Represents a `ty::Ty` for use in [`ClosureOutlivesSubject`]. +/// +/// This abstraction is necessary because the type may include `ReVar` regions, +/// which is what we use internally within NLL code, and they can't be used in +/// a query response. +#[derive(Copy, Clone, Debug)] +pub struct ClosureOutlivesSubjectTy<'tcx> { + inner: Ty<'tcx>, +} +// DO NOT implement `TypeVisitable` or `TypeFoldable` traits, because this +// type is not recognized as a binder for late-bound region. +impl<'tcx, I> !TypeVisitable for ClosureOutlivesSubjectTy<'tcx> {} +impl<'tcx, I> !TypeFoldable for ClosureOutlivesSubjectTy<'tcx> {} + +impl<'tcx> ClosureOutlivesSubjectTy<'tcx> { + /// All regions of `ty` must be of kind `ReVar` and must represent + /// universal regions *external* to the closure. + pub fn bind(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Self { + let inner = fold_regions(tcx, ty, |r, depth| match r.kind() { + ty::ReVar(vid) => { + let br = ty::BoundRegion { + var: ty::BoundVar::from_usize(vid.index()), + kind: ty::BoundRegionKind::Anon, + }; + ty::Region::new_bound(tcx, depth, br) + } + _ => bug!("unexpected region in ClosureOutlivesSubjectTy: {r:?}"), + }); + + Self { inner } } - let borrowck_result = do_mir_borrowck(tcx, def, None).0; - debug!("mir_borrowck done"); - - tcx.arena.alloc(borrowck_result) + pub fn instantiate( + self, + tcx: TyCtxt<'tcx>, + mut map: impl FnMut(ty::RegionVid) -> ty::Region<'tcx>, + ) -> Ty<'tcx> { + fold_regions(tcx, self.inner, |r, depth| match r.kind() { + ty::ReBound(debruijn, br) => { + debug_assert_eq!(debruijn, depth); + map(ty::RegionVid::from_usize(br.var.index())) + } + _ => bug!("unexpected region {r:?}"), + }) + } } /// Perform the actual borrow checking. /// /// Use `consumer_options: None` for the default behavior of returning -/// [`BorrowCheckResult`] only. Otherwise, return [`BodyWithBorrowckFacts`] according -/// to the given [`ConsumerOptions`]. -#[instrument(skip(tcx), level = "debug")] +/// [`PropagatedBorrowCheckResults`] only. Otherwise, return [`BodyWithBorrowckFacts`] +/// according to the given [`ConsumerOptions`]. +/// +/// For nested bodies this should only be called through `root_cx.get_or_insert_nested`. +#[instrument(skip(root_cx), level = "debug")] fn do_mir_borrowck<'tcx>( - tcx: TyCtxt<'tcx>, + root_cx: &mut BorrowCheckRootCtxt<'tcx>, def: LocalDefId, consumer_options: Option, -) -> (BorrowCheckResult<'tcx>, Option>>) { +) -> (PropagatedBorrowCheckResults<'tcx>, Option>>) { + let tcx = root_cx.tcx; let infcx = BorrowckInferCtxt::new(tcx, def); let (input_body, promoted) = tcx.mir_promoted(def); let input_body: &Body<'_> = &input_body.borrow(); let input_promoted: &IndexSlice<_, _> = &promoted.borrow(); if let Some(e) = input_body.tainted_by_errors { infcx.set_tainted_by_errors(e); - } - - let mut local_names = IndexVec::from_elem(None, &input_body.local_decls); - for var_debug_info in &input_body.var_debug_info { - if let VarDebugInfoContents::Place(place) = var_debug_info.value { - if let Some(local) = place.as_local() { - if let Some(prev_name) = local_names[local] - && var_debug_info.name != prev_name - { - span_bug!( - var_debug_info.source_info.span, - "local {:?} has many names (`{}` vs `{}`)", - local, - prev_name, - var_debug_info.name - ); - } - local_names[local] = Some(var_debug_info.name); - } - } + root_cx.set_tainted_by_errors(e); } // Replace all regions with fresh inference variables. This @@ -168,7 +310,7 @@ fn do_mir_borrowck<'tcx>( // will have a lifetime tied to the inference context. let mut body_owned = input_body.clone(); let mut promoted = input_promoted.to_owned(); - let free_regions = nll::replace_regions_in_mir(&infcx, &mut body_owned, &mut promoted); + let universal_regions = nll::replace_regions_in_mir(&infcx, &mut body_owned, &mut promoted); let body = &body_owned; // no further changes let location_table = PoloniusLocationTable::new(body); @@ -185,15 +327,15 @@ fn do_mir_borrowck<'tcx>( // Compute non-lexical lifetimes. let nll::NllOutput { regioncx, - concrete_opaque_types, polonius_input, polonius_output, opt_closure_req, nll_errors, polonius_diagnostics, } = nll::compute_regions( + root_cx, &infcx, - free_regions, + universal_regions, body, &promoted, &location_table, @@ -206,31 +348,23 @@ fn do_mir_borrowck<'tcx>( // Dump MIR results into a file, if that is enabled. This lets us // write unit-tests, as well as helping with debugging. nll::dump_nll_mir(&infcx, body, ®ioncx, &opt_closure_req, &borrow_set); - - // We also have a `#[rustc_regions]` annotation that causes us to dump - // information. - let diags_buffer = &mut BorrowckDiagnosticsBuffer::default(); - nll::dump_annotation( + polonius::dump_polonius_mir( &infcx, body, ®ioncx, &opt_closure_req, - &concrete_opaque_types, - diags_buffer, + &borrow_set, + polonius_diagnostics.as_ref(), ); - let movable_coroutine = - // The first argument is the coroutine type passed by value - if let Some(local) = body.local_decls.raw.get(1) - // Get the interior types and args which typeck computed - && let ty::Coroutine(def_id, _) = *local.ty.kind() - && tcx.coroutine_movability(def_id) == hir::Movability::Movable - { - true - } else { - false - }; + // We also have a `#[rustc_regions]` annotation that causes us to dump + // information. + nll::dump_annotation(&infcx, body, ®ioncx, &opt_closure_req); + let movable_coroutine = body.coroutine.is_some() + && tcx.coroutine_movability(def.to_def_id()) == hir::Movability::Movable; + + let diags_buffer = &mut BorrowckDiagnosticsBuffer::default(); // While promoteds should mostly be correct by construction, we need to check them for // invalid moves to detect moving out of arrays:`struct S; fn main() { &([S][0]); }`. for promoted_body in &promoted { @@ -240,6 +374,7 @@ fn do_mir_borrowck<'tcx>( // this check out of `MirBorrowckCtxt`, actually doing so is far from trivial. let move_data = MoveData::gather_moves(promoted_body, tcx, |_| true); let mut promoted_mbcx = MirBorrowckCtxt { + root_cx, infcx: &infcx, body: promoted_body, move_data: &move_data, @@ -247,7 +382,6 @@ fn do_mir_borrowck<'tcx>( location_table: &location_table, movable_coroutine, fn_self_span_reported: Default::default(), - locals_are_invalidated_at_exit, access_place_error_reported: Default::default(), reservation_error_reported: Default::default(), uninitialized_error_reported: Default::default(), @@ -279,13 +413,33 @@ fn do_mir_borrowck<'tcx>( promoted_mbcx.report_move_errors(); } + let mut local_names = IndexVec::from_elem(None, &body.local_decls); + for var_debug_info in &body.var_debug_info { + if let VarDebugInfoContents::Place(place) = var_debug_info.value { + if let Some(local) = place.as_local() { + if let Some(prev_name) = local_names[local] + && var_debug_info.name != prev_name + { + span_bug!( + var_debug_info.source_info.span, + "local {:?} has many names (`{}` vs `{}`)", + local, + prev_name, + var_debug_info.name + ); + } + local_names[local] = Some(var_debug_info.name); + } + } + } + let mut mbcx = MirBorrowckCtxt { + root_cx, infcx: &infcx, body, move_data: &move_data, location_table: &location_table, movable_coroutine, - locals_are_invalidated_at_exit, fn_self_span_reported: Default::default(), access_place_error_reported: Default::default(), reservation_error_reported: Default::default(), @@ -298,9 +452,9 @@ fn do_mir_borrowck<'tcx>( local_names, region_names: RefCell::default(), next_region_name: RefCell::new(1), - polonius_output, move_errors: Vec::new(), diags_buffer, + polonius_output: polonius_output.as_deref(), polonius_diagnostics: polonius_diagnostics.as_ref(), }; @@ -317,16 +471,6 @@ fn do_mir_borrowck<'tcx>( mbcx.report_move_errors(); - // If requested, dump polonius MIR. - polonius::dump_polonius_mir( - &infcx, - body, - ®ioncx, - &borrow_set, - polonius_diagnostics.as_ref(), - &opt_closure_req, - ); - // For each non-user used mutable variable, check if it's been assigned from // a user-declared local. If so, then put that local into the used_mut set. // Note that this set is expected to be small - only upvars from closures @@ -347,17 +491,16 @@ fn do_mir_borrowck<'tcx>( debug!("mbcx.used_mut: {:?}", mbcx.used_mut); mbcx.lint_unused_mut(); - let tainted_by_errors = mbcx.emit_errors(); + if let Some(guar) = mbcx.emit_errors() { + mbcx.root_cx.set_tainted_by_errors(guar); + } - let result = BorrowCheckResult { - concrete_opaque_types: concrete_opaque_types.into_inner(), + let result = PropagatedBorrowCheckResults { closure_requirements: opt_closure_req, used_mut_upvars: mbcx.used_mut_upvars, - tainted_by_errors, }; let body_with_facts = if consumer_options.is_some() { - let output_facts = mbcx.polonius_output; Some(Box::new(BodyWithBorrowckFacts { body: body_owned, promoted, @@ -365,7 +508,7 @@ fn do_mir_borrowck<'tcx>( region_inference_context: regioncx, location_table: polonius_input.as_ref().map(|_| location_table), input_facts: polonius_input, - output_facts, + output_facts: polonius_output, })) } else { None @@ -488,6 +631,7 @@ impl<'tcx> Deref for BorrowckInferCtxt<'tcx> { } struct MirBorrowckCtxt<'a, 'infcx, 'tcx> { + root_cx: &'a mut BorrowCheckRootCtxt<'tcx>, infcx: &'infcx BorrowckInferCtxt<'tcx>, body: &'a Body<'tcx>, move_data: &'a MoveData<'tcx>, @@ -497,13 +641,6 @@ struct MirBorrowckCtxt<'a, 'infcx, 'tcx> { location_table: &'a PoloniusLocationTable, movable_coroutine: bool, - /// This keeps track of whether local variables are free-ed when the function - /// exits even without a `StorageDead`, which appears to be the case for - /// constants. - /// - /// I'm not sure this is the right approach - @eddyb could you try and - /// figure this out? - locals_are_invalidated_at_exit: bool, /// This field keeps track of when borrow errors are reported in the access_place function /// so that there is no duplicate reporting. This field cannot also be used for the conflicting /// borrow errors that is handled by the `reservation_error_reported` field as the inclusion @@ -551,12 +688,11 @@ struct MirBorrowckCtxt<'a, 'infcx, 'tcx> { /// The counter for generating new region names. next_region_name: RefCell, - /// Results of Polonius analysis. - polonius_output: Option>, - diags_buffer: &'a mut BorrowckDiagnosticsBuffer<'infcx, 'tcx>, move_errors: Vec>, + /// Results of Polonius analysis. + polonius_output: Option<&'a PoloniusOutput>, /// When using `-Zpolonius=next`: the data used to compute errors and diagnostics. polonius_diagnostics: Option<&'a PoloniusDiagnosticsContext>, } @@ -780,13 +916,20 @@ impl<'a, 'tcx> ResultsVisitor<'a, 'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt< | TerminatorKind::Return | TerminatorKind::TailCall { .. } | TerminatorKind::CoroutineDrop => { - // Returning from the function implicitly kills storage for all locals and statics. - // Often, the storage will already have been killed by an explicit - // StorageDead, but we don't always emit those (notably on unwind paths), - // so this "extra check" serves as a kind of backup. - for i in state.borrows.iter() { - let borrow = &self.borrow_set[i]; - self.check_for_invalidation_at_exit(loc, borrow, span); + match self.borrow_set.locals_state_at_exit() { + LocalsStateAtExit::AllAreInvalidated => { + // Returning from the function implicitly kills storage for all locals and statics. + // Often, the storage will already have been killed by an explicit + // StorageDead, but we don't always emit those (notably on unwind paths), + // so this "extra check" serves as a kind of backup. + for i in state.borrows.iter() { + let borrow = &self.borrow_set[i]; + self.check_for_invalidation_at_exit(loc, borrow, span); + } + } + // If we do not implicitly invalidate all locals on exit, + // we check for conflicts when dropping or moving this local. + LocalsStateAtExit::SomeAreInvalidated { has_storage_dead_or_moved: _ } => {} } } @@ -1143,7 +1286,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { error_reported } - /// Through #123739, backward incompatible drops (BIDs) are introduced. + /// Through #123739, `BackwardIncompatibleDropHint`s (BIDs) are introduced. /// We would like to emit lints whether borrow checking fails at these future drop locations. #[instrument(level = "debug", skip(self, state))] fn check_backward_incompatible_drop( @@ -1361,11 +1504,13 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { | AggregateKind::CoroutineClosure(def_id, _) | AggregateKind::Coroutine(def_id, _) => { let def_id = def_id.expect_local(); - let BorrowCheckResult { used_mut_upvars, .. } = - self.infcx.tcx.mir_borrowck(def_id); + let used_mut_upvars = self.root_cx.used_mut_upvars(def_id); debug!("{:?} used_mut_upvars={:?}", def_id, used_mut_upvars); - for field in used_mut_upvars { - self.propagate_closure_used_mut_upvar(&operands[*field]); + // FIXME: We're cloning the `SmallVec` here to avoid borrowing `root_cx` + // when calling `propagate_closure_used_mut_upvar`. This should ideally + // be unnecessary. + for field in used_mut_upvars.clone() { + self.propagate_closure_used_mut_upvar(&operands[field]); } } AggregateKind::Adt(..) @@ -1556,22 +1701,15 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { // we'll have a memory leak) and assume that all statics have a destructor. // // FIXME: allow thread-locals to borrow other thread locals? - - let (might_be_alive, will_be_dropped) = - if self.body.local_decls[root_place.local].is_ref_to_thread_local() { - // Thread-locals might be dropped after the function exits - // We have to dereference the outer reference because - // borrows don't conflict behind shared references. - root_place.projection = TyCtxtConsts::DEREF_PROJECTION; - (true, true) - } else { - (false, self.locals_are_invalidated_at_exit) - }; - - if !will_be_dropped { - debug!("place_is_invalidated_at_exit({:?}) - won't be dropped", place); - return; - } + let might_be_alive = if self.body.local_decls[root_place.local].is_ref_to_thread_local() { + // Thread-locals might be dropped after the function exits + // We have to dereference the outer reference because + // borrows don't conflict behind shared references. + root_place.projection = TyCtxtConsts::DEREF_PROJECTION; + true + } else { + false + }; let sd = if might_be_alive { Deep } else { Shallow(None) }; diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index 8e7b6f083aca..fe899bb054fa 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -8,10 +8,7 @@ use std::str::FromStr; use polonius_engine::{Algorithm, Output}; use rustc_index::IndexSlice; use rustc_middle::mir::pretty::{PrettyPrintMirOptions, dump_mir_with_options}; -use rustc_middle::mir::{ - Body, ClosureOutlivesSubject, ClosureRegionRequirements, PassWhere, Promoted, create_dump_file, - dump_enabled, dump_mir, -}; +use rustc_middle::mir::{Body, PassWhere, Promoted, create_dump_file, dump_enabled, dump_mir}; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, TyCtxt}; use rustc_mir_dataflow::ResultsCursor; @@ -24,8 +21,7 @@ use tracing::{debug, instrument}; use crate::borrow_set::BorrowSet; use crate::consumers::ConsumerOptions; -use crate::diagnostics::{BorrowckDiagnosticsBuffer, RegionErrors}; -use crate::opaque_types::ConcreteOpaqueTypes; +use crate::diagnostics::RegionErrors; use crate::polonius::PoloniusDiagnosticsContext; use crate::polonius::legacy::{ PoloniusFacts, PoloniusFactsExt, PoloniusLocationTable, PoloniusOutput, @@ -33,13 +29,15 @@ use crate::polonius::legacy::{ use crate::region_infer::RegionInferenceContext; use crate::type_check::{self, MirTypeckResults}; use crate::universal_regions::UniversalRegions; -use crate::{BorrowckInferCtxt, polonius, renumber}; +use crate::{ + BorrowCheckRootCtxt, BorrowckInferCtxt, ClosureOutlivesSubject, ClosureRegionRequirements, + polonius, renumber, +}; /// The output of `nll::compute_regions`. This includes the computed `RegionInferenceContext`, any /// closure requirements to propagate, and any generated errors. pub(crate) struct NllOutput<'tcx> { pub regioncx: RegionInferenceContext<'tcx>, - pub concrete_opaque_types: ConcreteOpaqueTypes<'tcx>, pub polonius_input: Option>, pub polonius_output: Option>, pub opt_closure_req: Option>, @@ -78,6 +76,7 @@ pub(crate) fn replace_regions_in_mir<'tcx>( /// /// This may result in errors being reported. pub(crate) fn compute_regions<'a, 'tcx>( + root_cx: &mut BorrowCheckRootCtxt<'tcx>, infcx: &BorrowckInferCtxt<'tcx>, universal_regions: UniversalRegions<'tcx>, body: &Body<'tcx>, @@ -98,8 +97,6 @@ pub(crate) fn compute_regions<'a, 'tcx>( let location_map = Rc::new(DenseLocationMap::new(body)); - let mut concrete_opaque_types = ConcreteOpaqueTypes::default(); - // Run the MIR type-checker. let MirTypeckResults { constraints, @@ -107,6 +104,7 @@ pub(crate) fn compute_regions<'a, 'tcx>( opaque_type_values, polonius_context, } = type_check::type_check( + root_cx, infcx, body, promoted, @@ -117,14 +115,8 @@ pub(crate) fn compute_regions<'a, 'tcx>( flow_inits, move_data, Rc::clone(&location_map), - &mut concrete_opaque_types, ); - // Create the region inference context, taking ownership of the - // region inference data that was contained in `infcx`, and the - // base constraints generated by the type-check. - let var_infos = infcx.get_region_var_infos(); - // If requested, emit legacy polonius facts. polonius::legacy::emit_facts( &mut polonius_facts, @@ -137,13 +129,8 @@ pub(crate) fn compute_regions<'a, 'tcx>( &constraints, ); - let mut regioncx = RegionInferenceContext::new( - infcx, - var_infos, - constraints, - universal_region_relations, - location_map, - ); + let mut regioncx = + RegionInferenceContext::new(infcx, constraints, universal_region_relations, location_map); // If requested for `-Zpolonius=next`, convert NLL constraints to localized outlives constraints // and use them to compute loan liveness. @@ -181,11 +168,10 @@ pub(crate) fn compute_regions<'a, 'tcx>( infcx.set_tainted_by_errors(guar); } - regioncx.infer_opaque_types(infcx, opaque_type_values, &mut concrete_opaque_types); + regioncx.infer_opaque_types(root_cx, infcx, opaque_type_values); NllOutput { regioncx, - concrete_opaque_types, polonius_input: polonius_facts.map(Box::new), polonius_output, opt_closure_req: closure_region_requirements, @@ -301,8 +287,6 @@ pub(super) fn dump_annotation<'tcx, 'infcx>( body: &Body<'tcx>, regioncx: &RegionInferenceContext<'tcx>, closure_region_requirements: &Option>, - concrete_opaque_types: &ConcreteOpaqueTypes<'tcx>, - diagnostics_buffer: &mut BorrowckDiagnosticsBuffer<'infcx, 'tcx>, ) { let tcx = infcx.tcx; let base_def_id = tcx.typeck_root_def_id(body.source.def_id()); @@ -318,7 +302,7 @@ pub(super) fn dump_annotation<'tcx, 'infcx>( // better. let def_span = tcx.def_span(body.source.def_id()); - let mut err = if let Some(closure_region_requirements) = closure_region_requirements { + let err = if let Some(closure_region_requirements) = closure_region_requirements { let mut err = infcx.dcx().struct_span_note(def_span, "external requirements"); regioncx.annotate(tcx, &mut err); @@ -340,15 +324,11 @@ pub(super) fn dump_annotation<'tcx, 'infcx>( } else { let mut err = infcx.dcx().struct_span_note(def_span, "no external requirements"); regioncx.annotate(tcx, &mut err); - err }; - if !concrete_opaque_types.is_empty() { - err.note(format!("Inferred opaque type values:\n{concrete_opaque_types:#?}")); - } - - diagnostics_buffer.buffer_non_error(err); + // FIXME(@lcnr): We currently don't dump the inferred hidden types here. + err.emit(); } fn for_each_region_constraint<'tcx>( diff --git a/compiler/rustc_borrowck/src/opaque_types.rs b/compiler/rustc_borrowck/src/opaque_types.rs deleted file mode 100644 index 5c78814abdd2..000000000000 --- a/compiler/rustc_borrowck/src/opaque_types.rs +++ /dev/null @@ -1,55 +0,0 @@ -use rustc_data_structures::fx::FxIndexMap; -use rustc_hir::def_id::LocalDefId; -use rustc_middle::ty::{OpaqueHiddenType, Ty, TyCtxt}; - -#[derive(Debug, Default)] -pub(super) struct ConcreteOpaqueTypes<'tcx> { - concrete_opaque_types: FxIndexMap>, -} - -impl<'tcx> ConcreteOpaqueTypes<'tcx> { - pub(super) fn is_empty(&self) -> bool { - self.concrete_opaque_types.is_empty() - } - - pub(super) fn into_inner(self) -> FxIndexMap> { - self.concrete_opaque_types - } - - /// Insert an opaque type into the list of opaque types defined by this function - /// after mapping the hidden type to the generic parameters of the opaque type - /// definition. - pub(super) fn insert( - &mut self, - tcx: TyCtxt<'tcx>, - def_id: LocalDefId, - hidden_ty: OpaqueHiddenType<'tcx>, - ) { - // Sometimes two opaque types are the same only after we remap the generic parameters - // back to the opaque type definition. E.g. we may have `OpaqueType` mapped to - // `(X, Y)` and `OpaqueType` mapped to `(Y, X)`, and those are the same, but we - // only know that once we convert the generic parameters to those of the opaque type. - if let Some(prev) = self.concrete_opaque_types.get_mut(&def_id) { - if prev.ty != hidden_ty.ty { - let (Ok(guar) | Err(guar)) = - prev.build_mismatch_error(&hidden_ty, tcx).map(|d| d.emit()); - prev.ty = Ty::new_error(tcx, guar); - } - // Pick a better span if there is one. - // FIXME(oli-obk): collect multiple spans for better diagnostics down the road. - prev.span = prev.span.substitute_dummy(hidden_ty.span); - } else { - self.concrete_opaque_types.insert(def_id, hidden_ty); - } - } - - pub(super) fn extend_from_nested_body( - &mut self, - tcx: TyCtxt<'tcx>, - nested_body: &FxIndexMap>, - ) { - for (&def_id, &hidden_ty) in nested_body { - self.insert(tcx, def_id, hidden_ty); - } - } -} diff --git a/compiler/rustc_borrowck/src/polonius/dump.rs b/compiler/rustc_borrowck/src/polonius/dump.rs index aa64a7c4e2a6..6a943e192082 100644 --- a/compiler/rustc_borrowck/src/polonius/dump.rs +++ b/compiler/rustc_borrowck/src/polonius/dump.rs @@ -5,7 +5,7 @@ use rustc_index::IndexVec; use rustc_middle::mir::pretty::{ PassWhere, PrettyPrintMirOptions, create_dump_file, dump_enabled, dump_mir_to_writer, }; -use rustc_middle::mir::{Body, ClosureRegionRequirements, Location}; +use rustc_middle::mir::{Body, Location}; use rustc_middle::ty::{RegionVid, TyCtxt}; use rustc_mir_dataflow::points::PointIndex; use rustc_session::config::MirIncludeSpans; @@ -17,16 +17,16 @@ use crate::polonius::{ }; use crate::region_infer::values::LivenessValues; use crate::type_check::Locations; -use crate::{BorrowckInferCtxt, RegionInferenceContext}; +use crate::{BorrowckInferCtxt, ClosureRegionRequirements, RegionInferenceContext}; /// `-Zdump-mir=polonius` dumps MIR annotated with NLL and polonius specific information. pub(crate) fn dump_polonius_mir<'tcx>( infcx: &BorrowckInferCtxt<'tcx>, body: &Body<'tcx>, regioncx: &RegionInferenceContext<'tcx>, + closure_region_requirements: &Option>, borrow_set: &BorrowSet<'tcx>, polonius_diagnostics: Option<&PoloniusDiagnosticsContext>, - closure_region_requirements: &Option>, ) { let tcx = infcx.tcx; if !tcx.sess.opts.unstable_opts.polonius.is_next_enabled() { @@ -334,7 +334,7 @@ fn emit_mermaid_nll_regions<'tcx>( writeln!(out, "flowchart TD")?; // Emit the region nodes. - for region in regioncx.var_infos.indices() { + for region in regioncx.definitions.indices() { write!(out, "{}[\"", region.as_usize())?; render_region(region, regioncx, out)?; writeln!(out, "\"]")?; @@ -387,7 +387,7 @@ fn emit_mermaid_nll_sccs<'tcx>( // Gather and emit the SCC nodes. let mut nodes_per_scc: IndexVec<_, _> = regioncx.constraint_sccs().all_sccs().map(|_| Vec::new()).collect(); - for region in regioncx.var_infos.indices() { + for region in regioncx.definitions.indices() { let scc = regioncx.constraint_sccs().scc(region); nodes_per_scc[scc].push(region); } diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index a80d74d9e370..f8af9e59f635 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -9,22 +9,20 @@ use rustc_errors::Diag; use rustc_hir::def_id::CRATE_DEF_ID; use rustc_index::IndexVec; use rustc_infer::infer::outlives::test_type_match; -use rustc_infer::infer::region_constraints::{GenericKind, VarInfos, VerifyBound, VerifyIfEq}; +use rustc_infer::infer::region_constraints::{GenericKind, VerifyBound, VerifyIfEq}; use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin}; use rustc_middle::bug; use rustc_middle::mir::{ - AnnotationSource, BasicBlock, Body, ClosureOutlivesRequirement, ClosureOutlivesSubject, - ClosureOutlivesSubjectTy, ClosureRegionRequirements, ConstraintCategory, Local, Location, - ReturnConstraint, TerminatorKind, + AnnotationSource, BasicBlock, Body, ConstraintCategory, Local, Location, ReturnConstraint, + TerminatorKind, }; use rustc_middle::traits::{ObligationCause, ObligationCauseCode}; use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable, UniverseIndex, fold_regions}; use rustc_mir_dataflow::points::DenseLocationMap; use rustc_span::hygiene::DesugaringKind; use rustc_span::{DUMMY_SP, Span}; -use tracing::{debug, instrument, trace}; +use tracing::{Level, debug, enabled, instrument, trace}; -use crate::BorrowckInferCtxt; use crate::constraints::graph::{self, NormalConstraintGraph, RegionGraph}; use crate::constraints::{ConstraintSccIndex, OutlivesConstraint, OutlivesConstraintSet}; use crate::dataflow::BorrowIndex; @@ -37,6 +35,10 @@ use crate::region_infer::values::{LivenessValues, RegionElement, RegionValues, T use crate::type_check::free_region_relations::UniversalRegionRelations; use crate::type_check::{Locations, MirTypeckRegionConstraints}; use crate::universal_regions::UniversalRegions; +use crate::{ + BorrowckInferCtxt, ClosureOutlivesRequirement, ClosureOutlivesSubject, + ClosureOutlivesSubjectTy, ClosureRegionRequirements, +}; mod dump_mir; mod graphviz; @@ -139,13 +141,11 @@ impl RegionTracker { } pub struct RegionInferenceContext<'tcx> { - pub var_infos: VarInfos, - /// Contains the definition for every region variable. Region /// variables are identified by their index (`RegionVid`). The /// definition contains information about where the region came /// from as well as its final inferred value. - definitions: IndexVec>, + pub(crate) definitions: Frozen>>, /// The liveness constraints added to each region. For most /// regions, these start out empty and steadily grow, though for @@ -327,31 +327,34 @@ fn sccs_info<'tcx>(infcx: &BorrowckInferCtxt<'tcx>, sccs: &ConstraintSccs) { let mut var_to_origin_sorted = var_to_origin.clone().into_iter().collect::>(); var_to_origin_sorted.sort_by_key(|vto| vto.0); - let mut reg_vars_to_origins_str = "region variables to origins:\n".to_string(); - for (reg_var, origin) in var_to_origin_sorted.into_iter() { - reg_vars_to_origins_str.push_str(&format!("{reg_var:?}: {origin:?}\n")); + if enabled!(Level::DEBUG) { + let mut reg_vars_to_origins_str = "region variables to origins:\n".to_string(); + for (reg_var, origin) in var_to_origin_sorted.into_iter() { + reg_vars_to_origins_str.push_str(&format!("{reg_var:?}: {origin:?}\n")); + } + debug!("{}", reg_vars_to_origins_str); } - debug!("{}", reg_vars_to_origins_str); let num_components = sccs.num_sccs(); let mut components = vec![FxIndexSet::default(); num_components]; - for (reg_var_idx, scc_idx) in sccs.scc_indices().iter().enumerate() { - let reg_var = ty::RegionVid::from_usize(reg_var_idx); + for (reg_var, scc_idx) in sccs.scc_indices().iter_enumerated() { let origin = var_to_origin.get(®_var).unwrap_or(&RegionCtxt::Unknown); components[scc_idx.as_usize()].insert((reg_var, *origin)); } - let mut components_str = "strongly connected components:".to_string(); - for (scc_idx, reg_vars_origins) in components.iter().enumerate() { - let regions_info = reg_vars_origins.clone().into_iter().collect::>(); - components_str.push_str(&format!( - "{:?}: {:?},\n)", - ConstraintSccIndex::from_usize(scc_idx), - regions_info, - )) + if enabled!(Level::DEBUG) { + let mut components_str = "strongly connected components:".to_string(); + for (scc_idx, reg_vars_origins) in components.iter().enumerate() { + let regions_info = reg_vars_origins.clone().into_iter().collect::>(); + components_str.push_str(&format!( + "{:?}: {:?},\n)", + ConstraintSccIndex::from_usize(scc_idx), + regions_info, + )) + } + debug!("{}", components_str); } - debug!("{}", components_str); // calculate the best representative for each component let components_representatives = components @@ -381,6 +384,26 @@ fn sccs_info<'tcx>(infcx: &BorrowckInferCtxt<'tcx>, sccs: &ConstraintSccs) { debug!("SCC edges {:#?}", scc_node_to_edges); } +fn create_definitions<'tcx>( + infcx: &BorrowckInferCtxt<'tcx>, + universal_regions: &UniversalRegions<'tcx>, +) -> Frozen>> { + // Create a RegionDefinition for each inference variable. + let mut definitions: IndexVec<_, _> = infcx + .get_region_var_infos() + .iter() + .map(|info| RegionDefinition::new(info.universe, info.origin)) + .collect(); + + // Add the external name for all universal regions. + for (external_name, variable) in universal_regions.named_universal_regions_iter() { + debug!("region {variable:?} has external name {external_name:?}"); + definitions[variable].external_name = Some(external_name); + } + + Frozen::freeze(definitions) +} + impl<'tcx> RegionInferenceContext<'tcx> { /// Creates a new region inference context with a total of /// `num_region_variables` valid inference variables; the first N @@ -391,7 +414,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// of constraints produced by the MIR type check. pub(crate) fn new( infcx: &BorrowckInferCtxt<'tcx>, - var_infos: VarInfos, constraints: MirTypeckRegionConstraints<'tcx>, universal_region_relations: Frozen>, location_map: Rc, @@ -422,11 +444,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { infcx.set_tainted_by_errors(guar); } - // Create a RegionDefinition for each inference variable. - let definitions: IndexVec<_, _> = var_infos - .iter() - .map(|info| RegionDefinition::new(info.universe, info.origin)) - .collect(); + let definitions = create_definitions(infcx, &universal_regions); let constraint_sccs = outlives_constraints.add_outlives_static(&universal_regions, &definitions); @@ -449,7 +467,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { Rc::new(member_constraints.into_mapped(|r| constraint_sccs.scc(r))); let mut result = Self { - var_infos, definitions, liveness_constraints, constraints, @@ -523,18 +540,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// means that the `R1: !1` constraint here will cause /// `R1` to become `'static`. fn init_free_and_bound_regions(&mut self) { - // Update the names (if any) - // This iterator has unstable order but we collect it all into an IndexVec - for (external_name, variable) in - self.universal_region_relations.universal_regions.named_universal_regions_iter() - { - debug!( - "init_free_and_bound_regions: region {:?} has external name {:?}", - variable, external_name - ); - self.definitions[variable].external_name = Some(external_name); - } - for variable in self.definitions.indices() { let scc = self.constraint_sccs.scc(variable); diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index a098450352ff..550c57338d30 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -10,7 +10,7 @@ use rustc_trait_selection::opaque_types::check_opaque_type_parameter_valid; use tracing::{debug, instrument}; use super::RegionInferenceContext; -use crate::opaque_types::ConcreteOpaqueTypes; +use crate::BorrowCheckRootCtxt; use crate::session_diagnostics::LifetimeMismatchOpaqueParam; use crate::universal_regions::RegionClassification; @@ -58,12 +58,12 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// /// [rustc-dev-guide chapter]: /// https://rustc-dev-guide.rust-lang.org/opaque-types-region-infer-restrictions.html - #[instrument(level = "debug", skip(self, infcx), ret)] + #[instrument(level = "debug", skip(self, root_cx, infcx), ret)] pub(crate) fn infer_opaque_types( &self, + root_cx: &mut BorrowCheckRootCtxt<'tcx>, infcx: &InferCtxt<'tcx>, opaque_ty_decls: FxIndexMap, OpaqueHiddenType<'tcx>>, - concrete_opaque_types: &mut ConcreteOpaqueTypes<'tcx>, ) { let mut decls_modulo_regions: FxIndexMap, (OpaqueTypeKey<'tcx>, Span)> = FxIndexMap::default(); @@ -140,11 +140,11 @@ impl<'tcx> RegionInferenceContext<'tcx> { } } - concrete_opaque_types.insert( - infcx.tcx, + root_cx.add_concrete_opaque_type( opaque_type_key.def_id, - OpaqueHiddenType { ty, span: concrete_type.span }, + OpaqueHiddenType { span: concrete_type.span, ty }, ); + // Check that all opaque types have the same region parameters if they have the same // non-region parameters. This is necessary because within the new solver we perform // various query operations modulo regions, and thus could unsoundly select some impls @@ -186,7 +186,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { where T: TypeFoldable>, { - fold_regions(tcx, ty, |region, _| match *region { + fold_regions(tcx, ty, |region, _| match region.kind() { ty::ReVar(vid) => { let scc = self.constraint_sccs.scc(vid); diff --git a/compiler/rustc_borrowck/src/root_cx.rs b/compiler/rustc_borrowck/src/root_cx.rs new file mode 100644 index 000000000000..13daa5c72214 --- /dev/null +++ b/compiler/rustc_borrowck/src/root_cx.rs @@ -0,0 +1,101 @@ +use rustc_abi::FieldIdx; +use rustc_data_structures::fx::FxHashMap; +use rustc_hir::def_id::LocalDefId; +use rustc_middle::bug; +use rustc_middle::ty::{OpaqueHiddenType, Ty, TyCtxt, TypeVisitableExt}; +use rustc_span::ErrorGuaranteed; +use smallvec::SmallVec; + +use crate::{ClosureRegionRequirements, ConcreteOpaqueTypes, PropagatedBorrowCheckResults}; + +/// The shared context used by both the root as well as all its nested +/// items. +pub(super) struct BorrowCheckRootCtxt<'tcx> { + pub tcx: TyCtxt<'tcx>, + root_def_id: LocalDefId, + concrete_opaque_types: ConcreteOpaqueTypes<'tcx>, + nested_bodies: FxHashMap>, + tainted_by_errors: Option, +} + +impl<'tcx> BorrowCheckRootCtxt<'tcx> { + pub(super) fn new(tcx: TyCtxt<'tcx>, root_def_id: LocalDefId) -> BorrowCheckRootCtxt<'tcx> { + BorrowCheckRootCtxt { + tcx, + root_def_id, + concrete_opaque_types: Default::default(), + nested_bodies: Default::default(), + tainted_by_errors: None, + } + } + + /// Collect all defining uses of opaque types inside of this typeck root. This + /// expects the hidden type to be mapped to the definition parameters of the opaque + /// and errors if we end up with distinct hidden types. + pub(super) fn add_concrete_opaque_type( + &mut self, + def_id: LocalDefId, + hidden_ty: OpaqueHiddenType<'tcx>, + ) { + // Sometimes two opaque types are the same only after we remap the generic parameters + // back to the opaque type definition. E.g. we may have `OpaqueType` mapped to + // `(X, Y)` and `OpaqueType` mapped to `(Y, X)`, and those are the same, but we + // only know that once we convert the generic parameters to those of the opaque type. + if let Some(prev) = self.concrete_opaque_types.0.get_mut(&def_id) { + if prev.ty != hidden_ty.ty { + let guar = hidden_ty.ty.error_reported().err().unwrap_or_else(|| { + let (Ok(e) | Err(e)) = + prev.build_mismatch_error(&hidden_ty, self.tcx).map(|d| d.emit()); + e + }); + prev.ty = Ty::new_error(self.tcx, guar); + } + // Pick a better span if there is one. + // FIXME(oli-obk): collect multiple spans for better diagnostics down the road. + prev.span = prev.span.substitute_dummy(hidden_ty.span); + } else { + self.concrete_opaque_types.0.insert(def_id, hidden_ty); + } + } + + pub(super) fn set_tainted_by_errors(&mut self, guar: ErrorGuaranteed) { + self.tainted_by_errors = Some(guar); + } + + fn get_or_insert_nested(&mut self, def_id: LocalDefId) -> &PropagatedBorrowCheckResults<'tcx> { + debug_assert_eq!( + self.tcx.typeck_root_def_id(def_id.to_def_id()), + self.root_def_id.to_def_id() + ); + if !self.nested_bodies.contains_key(&def_id) { + let result = super::do_mir_borrowck(self, def_id, None).0; + if let Some(prev) = self.nested_bodies.insert(def_id, result) { + bug!("unexpected previous nested body: {prev:?}"); + } + } + + self.nested_bodies.get(&def_id).unwrap() + } + + pub(super) fn closure_requirements( + &mut self, + nested_body_def_id: LocalDefId, + ) -> &Option> { + &self.get_or_insert_nested(nested_body_def_id).closure_requirements + } + + pub(super) fn used_mut_upvars( + &mut self, + nested_body_def_id: LocalDefId, + ) -> &SmallVec<[FieldIdx; 8]> { + &self.get_or_insert_nested(nested_body_def_id).used_mut_upvars + } + + pub(super) fn finalize(self) -> Result<&'tcx ConcreteOpaqueTypes<'tcx>, ErrorGuaranteed> { + if let Some(guar) = self.tainted_by_errors { + Err(guar) + } else { + Ok(self.tcx.arena.alloc(self.concrete_opaque_types)) + } + } +} diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs index 6fbe1db6330e..57516565147e 100644 --- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs +++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs @@ -6,7 +6,6 @@ use rustc_infer::infer::region_constraints::{GenericKind, VerifyBound}; use rustc_infer::infer::{self, InferCtxt, SubregionOrigin}; use rustc_infer::traits::query::type_op::DeeplyNormalize; use rustc_middle::bug; -use rustc_middle::mir::{ClosureOutlivesSubject, ClosureRegionRequirements, ConstraintCategory}; use rustc_middle::ty::{ self, GenericArgKind, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, fold_regions, }; @@ -18,10 +17,10 @@ use crate::constraints::OutlivesConstraint; use crate::region_infer::TypeTest; use crate::type_check::{Locations, MirTypeckRegionConstraints}; use crate::universal_regions::UniversalRegions; +use crate::{ClosureOutlivesSubject, ClosureRegionRequirements, ConstraintCategory}; pub(crate) struct ConstraintConversion<'a, 'tcx> { infcx: &'a InferCtxt<'tcx>, - tcx: TyCtxt<'tcx>, universal_regions: &'a UniversalRegions<'tcx>, /// Each RBP `GK: 'a` is assumed to be true. These encode /// relationships like `T: 'a` that are added via implicit bounds @@ -34,7 +33,6 @@ pub(crate) struct ConstraintConversion<'a, 'tcx> { /// logic expecting to see (e.g.) `ReStatic`, and if we supplied /// our special inference variable there, we would mess that up. region_bound_pairs: &'a RegionBoundPairs<'tcx>, - implicit_region_bound: ty::Region<'tcx>, param_env: ty::ParamEnv<'tcx>, known_type_outlives_obligations: &'a [ty::PolyTypeOutlivesPredicate<'tcx>], locations: Locations, @@ -49,7 +47,6 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { infcx: &'a InferCtxt<'tcx>, universal_regions: &'a UniversalRegions<'tcx>, region_bound_pairs: &'a RegionBoundPairs<'tcx>, - implicit_region_bound: ty::Region<'tcx>, param_env: ty::ParamEnv<'tcx>, known_type_outlives_obligations: &'a [ty::PolyTypeOutlivesPredicate<'tcx>], locations: Locations, @@ -59,10 +56,8 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { ) -> Self { Self { infcx, - tcx: infcx.tcx, universal_regions, region_bound_pairs, - implicit_region_bound, param_env, known_type_outlives_obligations, locations, @@ -96,7 +91,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { // into a vector. These are the regions that we will be // relating to one another. let closure_mapping = &UniversalRegions::closure_mapping( - self.tcx, + self.infcx.tcx, closure_args, closure_requirements.num_external_vids, closure_def_id, @@ -111,7 +106,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { let subject = match outlives_requirement.subject { ClosureOutlivesSubject::Region(re) => closure_mapping[re].into(), ClosureOutlivesSubject::Ty(subject_ty) => { - subject_ty.instantiate(self.tcx, |vid| closure_mapping[vid]).into() + subject_ty.instantiate(self.infcx.tcx, |vid| closure_mapping[vid]).into() } }; @@ -127,14 +122,14 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { predicate: ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>, constraint_category: ConstraintCategory<'tcx>, ) { + let tcx = self.infcx.tcx; debug!("generate: constraints at: {:#?}", self.locations); // Extract out various useful fields we'll need below. let ConstraintConversion { - tcx, infcx, + universal_regions, region_bound_pairs, - implicit_region_bound, known_type_outlives_obligations, .. } = *self; @@ -145,7 +140,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { break; } - if !self.tcx.recursion_limit().value_within_limit(iteration) { + if !tcx.recursion_limit().value_within_limit(iteration) { bug!( "FIXME(-Znext-solver): Overflowed when processing region obligations: {outlives_predicates:#?}" ); @@ -170,10 +165,11 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { ); } + let implicit_region_bound = + ty::Region::new_var(tcx, universal_regions.implicit_region_bound()); // we don't actually use this for anything, but // the `TypeOutlives` code needs an origin. let origin = infer::RelateParamBound(self.span, t1, None); - TypeOutlives::new( &mut *self, tcx, @@ -205,7 +201,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { /// are dealt with during trait solving. fn replace_placeholders_with_nll>>(&mut self, value: T) -> T { if value.has_placeholders() { - fold_regions(self.tcx, value, |r, _| match *r { + fold_regions(self.infcx.tcx, value, |r, _| match r.kind() { ty::RePlaceholder(placeholder) => { self.constraints.placeholder_region(self.infcx, placeholder) } @@ -227,7 +223,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { } fn to_region_vid(&mut self, r: ty::Region<'tcx>) -> ty::RegionVid { - if let ty::RePlaceholder(placeholder) = *r { + if let ty::RePlaceholder(placeholder) = r.kind() { self.constraints.placeholder_region(self.infcx, placeholder).as_var() } else { self.universal_regions.to_region_vid(r) 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 eaac633b512d..536a27763d29 100644 --- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs +++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs @@ -49,14 +49,12 @@ pub(crate) struct CreateResult<'tcx> { pub(crate) fn create<'tcx>( infcx: &InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, - implicit_region_bound: ty::Region<'tcx>, universal_regions: UniversalRegions<'tcx>, constraints: &mut MirTypeckRegionConstraints<'tcx>, ) -> CreateResult<'tcx> { UniversalRegionRelationsBuilder { infcx, param_env, - implicit_region_bound, constraints, universal_regions, region_bound_pairs: Default::default(), @@ -181,7 +179,6 @@ struct UniversalRegionRelationsBuilder<'a, 'tcx> { infcx: &'a InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, universal_regions: UniversalRegions<'tcx>, - implicit_region_bound: ty::Region<'tcx>, constraints: &'a mut MirTypeckRegionConstraints<'tcx>, // outputs: @@ -320,7 +317,6 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { self.infcx, &self.universal_regions, &self.region_bound_pairs, - self.implicit_region_bound, param_env, &known_type_outlives_obligations, Locations::All(span), diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index f6144a25938c..3c00b819a96b 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -45,7 +45,6 @@ use crate::borrow_set::BorrowSet; use crate::constraints::{OutlivesConstraint, OutlivesConstraintSet}; use crate::diagnostics::UniverseInfo; use crate::member_constraints::MemberConstraintSet; -use crate::opaque_types::ConcreteOpaqueTypes; use crate::polonius::legacy::{PoloniusFacts, PoloniusLocationTable}; use crate::polonius::{PoloniusContext, PoloniusLivenessContext}; use crate::region_infer::TypeTest; @@ -53,7 +52,7 @@ use crate::region_infer::values::{LivenessValues, PlaceholderIndex, PlaceholderI use crate::session_diagnostics::{MoveUnsized, SimdIntrinsicArgConst}; use crate::type_check::free_region_relations::{CreateResult, UniversalRegionRelations}; use crate::universal_regions::{DefiningTy, UniversalRegions}; -use crate::{BorrowckInferCtxt, path_utils}; +use crate::{BorrowCheckRootCtxt, BorrowckInferCtxt, path_utils}; macro_rules! span_mirbug { ($context:expr, $elem:expr, $($message:tt)*) => ({ @@ -102,6 +101,7 @@ mod relate_tys; /// - `move_data` -- move-data constructed when performing the maybe-init dataflow analysis /// - `location_map` -- map between MIR `Location` and `PointIndex` pub(crate) fn type_check<'a, 'tcx>( + root_cx: &mut BorrowCheckRootCtxt<'tcx>, infcx: &BorrowckInferCtxt<'tcx>, body: &Body<'tcx>, promoted: &IndexSlice>, @@ -112,9 +112,7 @@ pub(crate) fn type_check<'a, 'tcx>( flow_inits: ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>, move_data: &MoveData<'tcx>, location_map: Rc, - concrete_opaque_types: &mut ConcreteOpaqueTypes<'tcx>, ) -> MirTypeckResults<'tcx> { - let implicit_region_bound = ty::Region::new_var(infcx.tcx, universal_regions.fr_fn_body); let mut constraints = MirTypeckRegionConstraints { placeholder_indices: PlaceholderIndices::default(), placeholder_index_to_region: IndexVec::default(), @@ -130,13 +128,7 @@ pub(crate) fn type_check<'a, 'tcx>( region_bound_pairs, normalized_inputs_and_output, known_type_outlives_obligations, - } = free_region_relations::create( - infcx, - infcx.param_env, - implicit_region_bound, - universal_regions, - &mut constraints, - ); + } = free_region_relations::create(infcx, infcx.param_env, universal_regions, &mut constraints); let pre_obligations = infcx.take_registered_region_obligations(); assert!( @@ -153,6 +145,7 @@ pub(crate) fn type_check<'a, 'tcx>( }; let mut typeck = TypeChecker { + root_cx, infcx, last_span: body.span, body, @@ -160,14 +153,12 @@ pub(crate) fn type_check<'a, 'tcx>( user_type_annotations: &body.user_type_annotations, region_bound_pairs, known_type_outlives_obligations, - implicit_region_bound, reported_errors: Default::default(), universal_regions: &universal_region_relations.universal_regions, location_table, polonius_facts, borrow_set, constraints: &mut constraints, - concrete_opaque_types, polonius_liveness, }; @@ -215,6 +206,7 @@ enum FieldAccessError { /// way, it accrues region constraints -- these can later be used by /// NLL region checking. struct TypeChecker<'a, 'tcx> { + root_cx: &'a mut BorrowCheckRootCtxt<'tcx>, infcx: &'a BorrowckInferCtxt<'tcx>, last_span: Span, body: &'a Body<'tcx>, @@ -226,14 +218,12 @@ struct TypeChecker<'a, 'tcx> { user_type_annotations: &'a CanonicalUserTypeAnnotations<'tcx>, region_bound_pairs: RegionBoundPairs<'tcx>, known_type_outlives_obligations: Vec>, - implicit_region_bound: ty::Region<'tcx>, reported_errors: FxIndexSet<(Ty<'tcx>, Span)>, universal_regions: &'a UniversalRegions<'tcx>, location_table: &'a PoloniusLocationTable, polonius_facts: &'a mut Option, borrow_set: &'a BorrowSet<'tcx>, constraints: &'a mut MirTypeckRegionConstraints<'tcx>, - concrete_opaque_types: &'a mut ConcreteOpaqueTypes<'tcx>, /// When using `-Zpolonius=next`, the liveness helper data used to create polonius constraints. polonius_liveness: Option, } @@ -423,7 +413,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { self.infcx, self.universal_regions, &self.region_bound_pairs, - self.implicit_region_bound, self.infcx.param_env, &self.known_type_outlives_obligations, locations, @@ -1568,11 +1557,15 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } } CastKind::Transmute => { - span_mirbug!( - self, - rvalue, - "Unexpected CastKind::Transmute, which is not permitted in Analysis MIR", - ); + let ty_from = op.ty(self.body, tcx); + match ty_from.kind() { + ty::Pat(base, _) if base == ty => {} + _ => span_mirbug!( + self, + rvalue, + "Unexpected CastKind::Transmute {ty_from:?} -> {ty:?}, which is not permitted in Analysis MIR", + ), + } } } } @@ -2503,16 +2496,11 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { args: GenericArgsRef<'tcx>, locations: Locations, ) -> ty::InstantiatedPredicates<'tcx> { - let closure_borrowck_results = tcx.mir_borrowck(def_id); - self.concrete_opaque_types - .extend_from_nested_body(tcx, &closure_borrowck_results.concrete_opaque_types); - - if let Some(closure_requirements) = &closure_borrowck_results.closure_requirements { + if let Some(closure_requirements) = &self.root_cx.closure_requirements(def_id) { constraint_conversion::ConstraintConversion::new( self.infcx, self.universal_regions, &self.region_bound_pairs, - self.implicit_region_bound, self.infcx.param_env, &self.known_type_outlives_obligations, locations, diff --git a/compiler/rustc_borrowck/src/type_check/opaque_types.rs b/compiler/rustc_borrowck/src/type_check/opaque_types.rs index 8bab979a7246..d41cbf757d7f 100644 --- a/compiler/rustc_borrowck/src/type_check/opaque_types.rs +++ b/compiler/rustc_borrowck/src/type_check/opaque_types.rs @@ -271,7 +271,7 @@ where } fn visit_region(&mut self, r: ty::Region<'tcx>) { - match *r { + match r.kind() { // ignore bound regions, keep visiting ty::ReBound(_, _) => {} _ => (self.op)(r), diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index 8f6b405fcef2..c11e14d214c4 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -438,6 +438,10 @@ impl<'tcx> UniversalRegions<'tcx> { } } + pub(crate) fn implicit_region_bound(&self) -> RegionVid { + self.fr_fn_body + } + pub(crate) fn tainted_by_errors(&self) -> Option { self.indices.tainted_by_errors.get() } @@ -909,19 +913,19 @@ impl<'tcx> UniversalRegionIndices<'tcx> { /// if it is a placeholder. Handling placeholders requires access to the /// `MirTypeckRegionConstraints`. fn to_region_vid(&self, r: ty::Region<'tcx>) -> RegionVid { - if let ty::ReVar(..) = *r { - r.as_var() - } else if let ty::ReError(guar) = *r { - self.tainted_by_errors.set(Some(guar)); - // We use the `'static` `RegionVid` because `ReError` doesn't actually exist in the - // `UniversalRegionIndices`. This is fine because 1) it is a fallback only used if - // errors are being emitted and 2) it leaves the happy path unaffected. - self.fr_static - } else { - *self + match r.kind() { + ty::ReVar(..) => r.as_var(), + ty::ReError(guar) => { + self.tainted_by_errors.set(Some(guar)); + // We use the `'static` `RegionVid` because `ReError` doesn't actually exist in the + // `UniversalRegionIndices`. This is fine because 1) it is a fallback only used if + // errors are being emitted and 2) it leaves the happy path unaffected. + self.fr_static + } + _ => *self .indices .get(&r) - .unwrap_or_else(|| bug!("cannot convert `{:?}` to a region vid", r)) + .unwrap_or_else(|| bug!("cannot convert `{:?}` to a region vid", r)), } } diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl index 603dc90bafca..5316e90847ac 100644 --- a/compiler/rustc_builtin_macros/messages.ftl +++ b/compiler/rustc_builtin_macros/messages.ftl @@ -231,8 +231,6 @@ builtin_macros_format_unused_args = multiple unused formatting arguments builtin_macros_format_use_positional = consider using a positional formatting argument instead -builtin_macros_invalid_crate_attribute = invalid crate attribute - builtin_macros_multiple_default_attrs = multiple `#[default]` attributes .note = only one `#[default]` attribute is needed .label = `#[default]` used here diff --git a/compiler/rustc_builtin_macros/src/autodiff.rs b/compiler/rustc_builtin_macros/src/autodiff.rs index 7f99f75b2b9d..daebd516499b 100644 --- a/compiler/rustc_builtin_macros/src/autodiff.rs +++ b/compiler/rustc_builtin_macros/src/autodiff.rs @@ -17,7 +17,7 @@ mod llvm_enzyme { use rustc_ast::visit::AssocCtxt::*; use rustc_ast::{ self as ast, AssocItemKind, BindingMode, ExprKind, FnRetTy, FnSig, Generics, ItemKind, - MetaItemInner, PatKind, QSelf, TyKind, + MetaItemInner, PatKind, QSelf, TyKind, Visibility, }; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_span::{Ident, Span, Symbol, kw, sym}; @@ -72,6 +72,16 @@ mod llvm_enzyme { } } + // Get information about the function the macro is applied to + fn extract_item_info(iitem: &P) -> Option<(Visibility, FnSig, Ident)> { + match &iitem.kind { + ItemKind::Fn(box ast::Fn { sig, ident, .. }) => { + Some((iitem.vis.clone(), sig.clone(), ident.clone())) + } + _ => None, + } + } + pub(crate) fn from_ast( ecx: &mut ExtCtxt<'_>, meta_item: &ThinVec, @@ -199,38 +209,32 @@ mod llvm_enzyme { return vec![item]; } let dcx = ecx.sess.dcx(); - // first get the annotable item: - let (primal, sig, is_impl): (Ident, FnSig, bool) = match &item { - Annotatable::Item(iitem) => { - let (ident, sig) = match &iitem.kind { - ItemKind::Fn(box ast::Fn { ident, sig, .. }) => (ident, sig), - _ => { - dcx.emit_err(errors::AutoDiffInvalidApplication { span: item.span() }); - return vec![item]; - } - }; - (*ident, sig.clone(), false) - } + + // first get information about the annotable item: + let Some((vis, sig, primal)) = (match &item { + Annotatable::Item(iitem) => extract_item_info(iitem), + Annotatable::Stmt(stmt) => match &stmt.kind { + ast::StmtKind::Item(iitem) => extract_item_info(iitem), + _ => None, + }, Annotatable::AssocItem(assoc_item, Impl { of_trait: false }) => { - let (ident, sig) = match &assoc_item.kind { - ast::AssocItemKind::Fn(box ast::Fn { ident, sig, .. }) => (ident, sig), - _ => { - dcx.emit_err(errors::AutoDiffInvalidApplication { span: item.span() }); - return vec![item]; + match &assoc_item.kind { + ast::AssocItemKind::Fn(box ast::Fn { sig, ident, .. }) => { + Some((assoc_item.vis.clone(), sig.clone(), ident.clone())) } - }; - (*ident, sig.clone(), true) - } - _ => { - dcx.emit_err(errors::AutoDiffInvalidApplication { span: item.span() }); - return vec![item]; + _ => None, + } } + _ => None, + }) else { + dcx.emit_err(errors::AutoDiffInvalidApplication { span: item.span() }); + return vec![item]; }; let meta_item_vec: ThinVec = match meta_item.kind { ast::MetaItemKind::List(ref vec) => vec.clone(), _ => { - dcx.emit_err(errors::AutoDiffInvalidApplication { span: item.span() }); + dcx.emit_err(errors::AutoDiffMissingConfig { span: item.span() }); return vec![item]; } }; @@ -238,15 +242,6 @@ mod llvm_enzyme { let has_ret = has_ret(&sig.decl.output); let sig_span = ecx.with_call_site_ctxt(sig.span); - let vis = match &item { - Annotatable::Item(iitem) => iitem.vis.clone(), - Annotatable::AssocItem(assoc_item, _) => assoc_item.vis.clone(), - _ => { - dcx.emit_err(errors::AutoDiffInvalidApplication { span: item.span() }); - return vec![item]; - } - }; - // create TokenStream from vec elemtents: // meta_item doesn't have a .tokens field let mut ts: Vec = vec![]; @@ -379,6 +374,22 @@ mod llvm_enzyme { } Annotatable::AssocItem(assoc_item.clone(), i) } + Annotatable::Stmt(ref mut stmt) => { + match stmt.kind { + ast::StmtKind::Item(ref mut iitem) => { + if !iitem.attrs.iter().any(|a| same_attribute(&a.kind, &attr.kind)) { + iitem.attrs.push(attr); + } + if !iitem.attrs.iter().any(|a| same_attribute(&a.kind, &inline_never.kind)) + { + iitem.attrs.push(inline_never.clone()); + } + } + _ => unreachable!("stmt kind checked previously"), + }; + + Annotatable::Stmt(stmt.clone()) + } _ => { unreachable!("annotatable kind checked previously") } @@ -389,22 +400,40 @@ mod llvm_enzyme { delim: rustc_ast::token::Delimiter::Parenthesis, tokens: ts, }); + let d_attr = outer_normal_attr(&rustc_ad_attr, new_id, span); - let d_annotatable = if is_impl { - let assoc_item: AssocItemKind = ast::AssocItemKind::Fn(asdf); - let d_fn = P(ast::AssocItem { - attrs: thin_vec![d_attr, inline_never], - id: ast::DUMMY_NODE_ID, - span, - vis, - kind: assoc_item, - tokens: None, - }); - Annotatable::AssocItem(d_fn, Impl { of_trait: false }) - } else { - let mut d_fn = ecx.item(span, thin_vec![d_attr, inline_never], ItemKind::Fn(asdf)); - d_fn.vis = vis; - Annotatable::Item(d_fn) + let d_annotatable = match &item { + Annotatable::AssocItem(_, _) => { + let assoc_item: AssocItemKind = ast::AssocItemKind::Fn(asdf); + let d_fn = P(ast::AssocItem { + attrs: thin_vec![d_attr, inline_never], + id: ast::DUMMY_NODE_ID, + span, + vis, + kind: assoc_item, + tokens: None, + }); + Annotatable::AssocItem(d_fn, Impl { of_trait: false }) + } + Annotatable::Item(_) => { + let mut d_fn = ecx.item(span, thin_vec![d_attr, inline_never], ItemKind::Fn(asdf)); + d_fn.vis = vis; + + Annotatable::Item(d_fn) + } + Annotatable::Stmt(_) => { + let mut d_fn = ecx.item(span, thin_vec![d_attr, inline_never], ItemKind::Fn(asdf)); + d_fn.vis = vis; + + Annotatable::Stmt(P(ast::Stmt { + id: ast::DUMMY_NODE_ID, + kind: ast::StmtKind::Item(d_fn), + span, + })) + } + _ => { + unreachable!("item kind checked previously") + } }; return vec![orig_annotatable, d_annotatable]; @@ -770,8 +799,19 @@ mod llvm_enzyme { d_inputs.push(shadow_arg.clone()); } } - DiffActivity::Dual | DiffActivity::DualOnly => { - for i in 0..x.width { + DiffActivity::Dual + | DiffActivity::DualOnly + | DiffActivity::Dualv + | DiffActivity::DualvOnly => { + // the *v variants get lowered to enzyme_dupv and enzyme_dupnoneedv, which cause + // Enzyme to not expect N arguments, but one argument (which is instead larger). + let iterations = + if matches!(activity, DiffActivity::Dualv | DiffActivity::DualvOnly) { + 1 + } else { + x.width + }; + for i in 0..iterations { let mut shadow_arg = arg.clone(); let old_name = if let PatKind::Ident(_, ident, _) = arg.pat.kind { ident.name @@ -794,7 +834,7 @@ mod llvm_enzyme { DiffActivity::Const => { // Nothing to do here. } - DiffActivity::None | DiffActivity::FakeActivitySize => { + DiffActivity::None | DiffActivity::FakeActivitySize(_) => { panic!("Should not happen"); } } @@ -858,8 +898,8 @@ mod llvm_enzyme { } }; - if let DiffActivity::Dual = x.ret_activity { - let kind = if x.width == 1 { + if matches!(x.ret_activity, DiffActivity::Dual | DiffActivity::Dualv) { + let kind = if x.width == 1 || matches!(x.ret_activity, DiffActivity::Dualv) { // Dual can only be used for f32/f64 ret. // In that case we return now a tuple with two floats. TyKind::Tup(thin_vec![ty.clone(), ty.clone()]) @@ -874,7 +914,7 @@ mod llvm_enzyme { let ty = P(rustc_ast::Ty { kind, id: ty.id, span: ty.span, tokens: None }); d_decl.output = FnRetTy::Ty(ty); } - if let DiffActivity::DualOnly = x.ret_activity { + if matches!(x.ret_activity, DiffActivity::DualOnly | DiffActivity::DualvOnly) { // No need to change the return type, // we will just return the shadow in place of the primal return. // However, if we have a width > 1, then we don't return -> T, but -> [T; width] diff --git a/compiler/rustc_builtin_macros/src/cfg_eval.rs b/compiler/rustc_builtin_macros/src/cfg_eval.rs index b3ba90731184..da01e3e9607b 100644 --- a/compiler/rustc_builtin_macros/src/cfg_eval.rs +++ b/compiler/rustc_builtin_macros/src/cfg_eval.rs @@ -92,11 +92,7 @@ impl CfgEval<'_> { // the location of `#[cfg]` and `#[cfg_attr]` in the token stream. The tokenization // process is lossless, so this process is invisible to proc-macros. - // 'Flatten' all nonterminals (i.e. `TokenKind::Interpolated`) - // to `None`-delimited groups containing the corresponding tokens. This - // is normally delayed until the proc-macro server actually needs to - // provide a `TokenKind::Interpolated` to a proc-macro. We do this earlier, - // so that we can handle cases like: + // Interesting cases: // // ```rust // #[cfg_eval] #[cfg] $item @@ -104,8 +100,8 @@ impl CfgEval<'_> { // // where `$item` is `#[cfg_attr] struct Foo {}`. We want to make // sure to evaluate *all* `#[cfg]` and `#[cfg_attr]` attributes - the simplest - // way to do this is to do a single parse of a stream without any nonterminals. - let orig_tokens = annotatable.to_tokens().flattened(); + // way to do this is to do a single parse of the token stream. + let orig_tokens = annotatable.to_tokens(); // Re-parse the tokens, setting the `capture_cfg` flag to save extra information // to the captured `AttrTokenStream` (specifically, we capture diff --git a/compiler/rustc_builtin_macros/src/cmdline_attrs.rs b/compiler/rustc_builtin_macros/src/cmdline_attrs.rs index 6afd8c4b43b9..423b6a15b646 100644 --- a/compiler/rustc_builtin_macros/src/cmdline_attrs.rs +++ b/compiler/rustc_builtin_macros/src/cmdline_attrs.rs @@ -1,44 +1,37 @@ //! Attributes injected into the crate root from command line using `-Z crate-attr`. -use rustc_ast::attr::mk_attr; -use rustc_ast::{self as ast, AttrItem, AttrStyle, token}; -use rustc_parse::parser::ForceCollect; -use rustc_parse::{new_parser_from_source_str, unwrap_or_emit_fatal}; +use rustc_ast::{self as ast}; +use rustc_errors::Diag; +use rustc_parse::parser::attr::InnerAttrPolicy; +use rustc_parse::{parse_in, source_str_to_stream}; use rustc_session::parse::ParseSess; use rustc_span::FileName; -use crate::errors; - pub fn inject(krate: &mut ast::Crate, psess: &ParseSess, attrs: &[String]) { for raw_attr in attrs { - let mut parser = unwrap_or_emit_fatal(new_parser_from_source_str( - psess, - FileName::cli_crate_attr_source_code(raw_attr), - raw_attr.clone(), - )); - - let start_span = parser.token.span; - let AttrItem { unsafety, path, args, tokens: _ } = - match parser.parse_attr_item(ForceCollect::No) { - Ok(ai) => ai, - Err(err) => { + let source = format!("#![{raw_attr}]"); + let parse = || -> Result>> { + let tokens = source_str_to_stream( + psess, + FileName::cli_crate_attr_source_code(raw_attr), + source, + None, + )?; + parse_in(psess, tokens, "", |p| { + p.parse_attribute(InnerAttrPolicy::Permitted) + }) + .map_err(|e| vec![e]) + }; + let meta = match parse() { + Ok(meta) => meta, + Err(errs) => { + for err in errs { err.emit(); - continue; } - }; - let end_span = parser.token.span; - if parser.token != token::Eof { - psess.dcx().emit_err(errors::InvalidCrateAttr { span: start_span.to(end_span) }); - continue; - } + continue; + } + }; - krate.attrs.push(mk_attr( - &psess.attr_id_generator, - AttrStyle::Inner, - unsafety, - path, - args, - start_span.to(end_span), - )); + krate.attrs.push(meta); } } diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index b9197be44426..d9aac54ee73c 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -527,15 +527,14 @@ impl<'a> TraitDef<'a> { item.attrs .iter() .filter(|a| { - [ + a.has_any_name(&[ sym::allow, sym::warn, sym::deny, sym::forbid, sym::stable, sym::unstable, - ] - .contains(&a.name_or_empty()) + ]) }) .cloned(), ); diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs index 4bbe212f4296..d14ad8f40144 100644 --- a/compiler/rustc_builtin_macros/src/errors.rs +++ b/compiler/rustc_builtin_macros/src/errors.rs @@ -1,7 +1,7 @@ use rustc_errors::codes::*; use rustc_errors::{ Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, MultiSpan, SingleLabelManySpans, - SubdiagMessageOp, Subdiagnostic, + Subdiagnostic, }; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::{Ident, Span, Symbol}; @@ -109,13 +109,6 @@ pub(crate) struct ProcMacro { pub(crate) span: Span, } -#[derive(Diagnostic)] -#[diag(builtin_macros_invalid_crate_attribute)] -pub(crate) struct InvalidCrateAttr { - #[primary_span] - pub(crate) span: Span, -} - #[derive(Diagnostic)] #[diag(builtin_macros_non_abi)] pub(crate) struct NonABI { @@ -691,13 +684,9 @@ pub(crate) struct FormatUnusedArg { // Allow the singular form to be a subdiagnostic of the multiple-unused // form of diagnostic. impl Subdiagnostic for FormatUnusedArg { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { diag.arg("named", self.named); - let msg = f(diag, crate::fluent_generated::builtin_macros_format_unused_arg.into()); + let msg = diag.eagerly_translate(crate::fluent_generated::builtin_macros_format_unused_arg); diag.span_label(self.span, msg); } } diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index 606e85577f7e..bcd40f980e64 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -5,7 +5,6 @@ #![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] -#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(assert_matches)] diff --git a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs index 8862965c0532..a91f2d38a93a 100644 --- a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs +++ b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs @@ -20,14 +20,14 @@ use crate::errors; struct ProcMacroDerive { id: NodeId, trait_name: Symbol, - function_name: Ident, + function_ident: Ident, span: Span, attrs: Vec, } struct ProcMacroDef { id: NodeId, - function_name: Ident, + function_ident: Ident, span: Span, } @@ -95,7 +95,7 @@ impl<'a> CollectProcMacros<'a> { fn collect_custom_derive( &mut self, item: &'a ast::Item, - function_name: Ident, + function_ident: Ident, attr: &'a ast::Attribute, ) { let Some((trait_name, proc_attrs)) = @@ -109,7 +109,7 @@ impl<'a> CollectProcMacros<'a> { id: item.id, span: item.span, trait_name, - function_name, + function_ident, attrs: proc_attrs, })); } else { @@ -123,12 +123,12 @@ impl<'a> CollectProcMacros<'a> { } } - fn collect_attr_proc_macro(&mut self, item: &'a ast::Item, function_name: Ident) { + fn collect_attr_proc_macro(&mut self, item: &'a ast::Item, function_ident: Ident) { if self.in_root && item.vis.kind.is_pub() { self.macros.push(ProcMacro::Attr(ProcMacroDef { id: item.id, span: item.span, - function_name, + function_ident, })); } else { let msg = if !self.in_root { @@ -141,12 +141,12 @@ impl<'a> CollectProcMacros<'a> { } } - fn collect_bang_proc_macro(&mut self, item: &'a ast::Item, function_name: Ident) { + fn collect_bang_proc_macro(&mut self, item: &'a ast::Item, function_ident: Ident) { if self.in_root && item.vis.kind.is_pub() { self.macros.push(ProcMacro::Bang(ProcMacroDef { id: item.id, span: item.span, - function_name, + function_ident, })); } else { let msg = if !self.in_root { @@ -303,7 +303,7 @@ fn mk_decls(cx: &mut ExtCtxt<'_>, macros: &[ProcMacro]) -> P { ProcMacro::Derive(m) => m.span, ProcMacro::Attr(m) | ProcMacro::Bang(m) => m.span, }; - let local_path = |cx: &ExtCtxt<'_>, name| cx.expr_path(cx.path(span, vec![name])); + let local_path = |cx: &ExtCtxt<'_>, ident| cx.expr_path(cx.path(span, vec![ident])); let proc_macro_ty_method_path = |cx: &ExtCtxt<'_>, method| { cx.expr_path(cx.path( span.with_ctxt(harness_span.ctxt()), @@ -327,7 +327,7 @@ fn mk_decls(cx: &mut ExtCtxt<'_>, macros: &[ProcMacro]) -> P { .map(|&s| cx.expr_str(span, s)) .collect::>(), ), - local_path(cx, cd.function_name), + local_path(cx, cd.function_ident), ], ) } @@ -345,8 +345,8 @@ fn mk_decls(cx: &mut ExtCtxt<'_>, macros: &[ProcMacro]) -> P { harness_span, proc_macro_ty_method_path(cx, ident), thin_vec![ - cx.expr_str(span, ca.function_name.name), - local_path(cx, ca.function_name), + cx.expr_str(span, ca.function_ident.name), + local_path(cx, ca.function_ident), ], ) } diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs index 444dc4412868..00136ac4a574 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs @@ -169,8 +169,11 @@ fn produce_final_output_artifacts( if codegen_results.modules.len() == 1 { // 1) Only one codegen unit. In this case it's no difficulty // to copy `foo.0.x` to `foo.x`. - let module_name = Some(&codegen_results.modules[0].name[..]); - let path = crate_output.temp_path(output_type, module_name); + let path = crate_output.temp_path_for_cgu( + output_type, + &codegen_results.modules[0].name, + sess.invocation_temp.as_deref(), + ); let output = crate_output.path(output_type); if !output_type.is_text_output() && output.is_tty() { sess.dcx() @@ -183,22 +186,16 @@ fn produce_final_output_artifacts( ensure_removed(sess.dcx(), &path); } } else { - let extension = crate_output - .temp_path(output_type, None) - .extension() - .unwrap() - .to_str() - .unwrap() - .to_owned(); - if crate_output.outputs.contains_explicit_name(&output_type) { // 2) Multiple codegen units, with `--emit foo=some_name`. We have // no good solution for this case, so warn the user. - sess.dcx().emit_warn(ssa_errors::IgnoringEmitPath { extension }); + sess.dcx() + .emit_warn(ssa_errors::IgnoringEmitPath { extension: output_type.extension() }); } else if crate_output.single_output_file.is_some() { // 3) Multiple codegen units, with `-o some_name`. We have // no good solution for this case, so warn the user. - sess.dcx().emit_warn(ssa_errors::IgnoringOutput { extension }); + sess.dcx() + .emit_warn(ssa_errors::IgnoringOutput { extension: output_type.extension() }); } else { // 4) Multiple codegen units, but no explicit name. We // just leave the `foo.0.x` files in place. @@ -351,6 +348,7 @@ fn make_module(sess: &Session, name: String) -> UnwindModule { fn emit_cgu( output_filenames: &OutputFilenames, + invocation_temp: Option<&str>, prof: &SelfProfilerRef, name: String, module: UnwindModule, @@ -366,6 +364,7 @@ fn emit_cgu( let module_regular = emit_module( output_filenames, + invocation_temp, prof, product.object, ModuleKind::Regular, @@ -391,6 +390,7 @@ fn emit_cgu( fn emit_module( output_filenames: &OutputFilenames, + invocation_temp: Option<&str>, prof: &SelfProfilerRef, mut object: cranelift_object::object::write::Object<'_>, kind: ModuleKind, @@ -409,7 +409,7 @@ fn emit_module( object.set_section_data(comment_section, producer, 1); } - let tmp_file = output_filenames.temp_path(OutputType::Object, Some(&name)); + let tmp_file = output_filenames.temp_path_for_cgu(OutputType::Object, &name, invocation_temp); let file = match File::create(&tmp_file) { Ok(file) => file, Err(err) => return Err(format!("error creating object file: {}", err)), @@ -449,8 +449,11 @@ fn reuse_workproduct_for_cgu( cgu: &CodegenUnit<'_>, ) -> Result { let work_product = cgu.previous_work_product(tcx); - let obj_out_regular = - tcx.output_filenames(()).temp_path(OutputType::Object, Some(cgu.name().as_str())); + let obj_out_regular = tcx.output_filenames(()).temp_path_for_cgu( + OutputType::Object, + cgu.name().as_str(), + tcx.sess.invocation_temp.as_deref(), + ); let source_file_regular = rustc_incremental::in_incr_comp_dir_sess( &tcx.sess, &work_product.saved_files.get("o").expect("no saved object file in work product"), @@ -595,13 +598,19 @@ fn module_codegen( let global_asm_object_file = profiler.generic_activity_with_arg("compile assembly", &*cgu_name).run(|| { - crate::global_asm::compile_global_asm(&global_asm_config, &cgu_name, &cx.global_asm) + crate::global_asm::compile_global_asm( + &global_asm_config, + &cgu_name, + &cx.global_asm, + cx.invocation_temp.as_deref(), + ) })?; let codegen_result = profiler.generic_activity_with_arg("write object file", &*cgu_name).run(|| { emit_cgu( &global_asm_config.output_filenames, + cx.invocation_temp.as_deref(), &profiler, cgu_name, module, @@ -626,8 +635,11 @@ fn emit_metadata_module(tcx: TyCtxt<'_>, metadata: &EncodedMetadata) -> Compiled .as_str() .to_string(); - let tmp_file = - tcx.output_filenames(()).temp_path(OutputType::Metadata, Some(&metadata_cgu_name)); + let tmp_file = tcx.output_filenames(()).temp_path_for_cgu( + OutputType::Metadata, + &metadata_cgu_name, + tcx.sess.invocation_temp.as_deref(), + ); let symbol_name = rustc_middle::middle::exported_symbols::metadata_symbol_name(tcx); let obj = create_compressed_metadata_file(tcx.sess, metadata, &symbol_name); @@ -657,6 +669,7 @@ fn emit_allocator_module(tcx: TyCtxt<'_>) -> Option { match emit_module( tcx.output_filenames(()), + tcx.sess.invocation_temp.as_deref(), &tcx.sess.prof, product.object, ModuleKind::Allocator, @@ -728,26 +741,27 @@ pub(crate) fn run_aot( let concurrency_limiter = IntoDynSyncSend(ConcurrencyLimiter::new(todo_cgus.len())); - let modules = tcx.sess.time("codegen mono items", || { - let mut modules: Vec<_> = par_map(todo_cgus, |(_, cgu)| { - let dep_node = cgu.codegen_dep_node(tcx); - tcx.dep_graph - .with_task( + let modules: Vec<_> = + tcx.sess.time("codegen mono items", || { + let modules: Vec<_> = par_map(todo_cgus, |(_, cgu)| { + let dep_node = cgu.codegen_dep_node(tcx); + let (module, _) = tcx.dep_graph.with_task( dep_node, tcx, (global_asm_config.clone(), cgu.name(), concurrency_limiter.acquire(tcx.dcx())), module_codegen, Some(rustc_middle::dep_graph::hash_result), - ) - .0 - }); - modules.extend( - done_cgus + ); + IntoDynSyncSend(module) + }); + modules .into_iter() - .map(|(_, cgu)| OngoingModuleCodegen::Sync(reuse_workproduct_for_cgu(tcx, cgu))), - ); - modules - }); + .map(|module| module.0) + .chain(done_cgus.into_iter().map(|(_, cgu)| { + OngoingModuleCodegen::Sync(reuse_workproduct_for_cgu(tcx, cgu)) + })) + .collect() + }); let allocator_module = emit_allocator_module(tcx); diff --git a/compiler/rustc_codegen_cranelift/src/global_asm.rs b/compiler/rustc_codegen_cranelift/src/global_asm.rs index 9ea92c300f89..79cefb05de32 100644 --- a/compiler/rustc_codegen_cranelift/src/global_asm.rs +++ b/compiler/rustc_codegen_cranelift/src/global_asm.rs @@ -132,6 +132,7 @@ pub(crate) fn compile_global_asm( config: &GlobalAsmConfig, cgu_name: &str, global_asm: &str, + invocation_temp: Option<&str>, ) -> Result, String> { if global_asm.is_empty() { return Ok(None); @@ -146,7 +147,7 @@ pub(crate) fn compile_global_asm( global_asm.push('\n'); let global_asm_object_file = add_file_stem_postfix( - config.output_filenames.temp_path(OutputType::Object, Some(cgu_name)), + config.output_filenames.temp_path_for_cgu(OutputType::Object, cgu_name, invocation_temp), ".asm", ); diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs index 75f3a3c19724..d3f47ad72633 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs @@ -1,5 +1,4 @@ -//! Codegen of intrinsics. This includes `extern "rust-intrinsic"`, -//! functions marked with the `#[rustc_intrinsic]` attribute +//! Codegen of intrinsics. This includes functions marked with the `#[rustc_intrinsic]` attribute //! and LLVM intrinsics that have symbol names starting with `llvm.`. macro_rules! intrinsic_args { diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs index e7afaff3b428..9d9e790289cf 100644 --- a/compiler/rustc_codegen_cranelift/src/lib.rs +++ b/compiler/rustc_codegen_cranelift/src/lib.rs @@ -124,6 +124,7 @@ impl String> Drop for PrintOnPanic { /// inside a single codegen unit with the exception of the Cranelift [`Module`](cranelift_module::Module). struct CodegenCx { output_filenames: Arc, + invocation_temp: Option, should_write_ir: bool, global_asm: String, inline_asm_index: usize, @@ -142,6 +143,7 @@ impl CodegenCx { }; CodegenCx { output_filenames: tcx.output_filenames(()).clone(), + invocation_temp: tcx.sess.invocation_temp.clone(), should_write_ir: crate::pretty_clif::should_write_ir(tcx), global_asm: String::new(), inline_asm_index: 0, diff --git a/compiler/rustc_codegen_cranelift/src/main_shim.rs b/compiler/rustc_codegen_cranelift/src/main_shim.rs index 6d5df2b00437..6eef97c14dd2 100644 --- a/compiler/rustc_codegen_cranelift/src/main_shim.rs +++ b/compiler/rustc_codegen_cranelift/src/main_shim.rs @@ -1,6 +1,6 @@ use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext}; use rustc_hir::LangItem; -use rustc_middle::ty::{AssocKind, GenericArg}; +use rustc_middle::ty::{AssocTag, GenericArg}; use rustc_session::config::EntryFnType; use rustc_span::{DUMMY_SP, Ident}; @@ -104,10 +104,10 @@ pub(crate) fn maybe_create_entry_wrapper( let termination_trait = tcx.require_lang_item(LangItem::Termination, None); let report = tcx .associated_items(termination_trait) - .find_by_name_and_kind( + .find_by_ident_and_kind( tcx, Ident::from_str("report"), - AssocKind::Fn, + AssocTag::Fn, termination_trait, ) .unwrap(); diff --git a/compiler/rustc_codegen_gcc/.github/workflows/ci.yml b/compiler/rustc_codegen_gcc/.github/workflows/ci.yml index f96912e6b7a8..ef024258ffc8 100644 --- a/compiler/rustc_codegen_gcc/.github/workflows/ci.yml +++ b/compiler/rustc_codegen_gcc/.github/workflows/ci.yml @@ -1,8 +1,10 @@ name: CI on: - - push - - pull_request + push: + branches: + - master + pull_request: permissions: contents: read @@ -121,3 +123,22 @@ jobs: run: | cd build_system cargo test + + # Summary job for the merge queue. + # ALL THE PREVIOUS JOBS NEED TO BE ADDED TO THE `needs` SECTION OF THIS JOB! + success: + needs: [build, duplicates, build_system] + # We need to ensure this job does *not* get skipped if its dependencies fail, + # because a skipped job is considered a success by GitHub. So we have to + # overwrite `if:`. We use `!cancelled()` to ensure the job does still not get run + # when the workflow is canceled manually. + if: ${{ !cancelled() }} + runs-on: ubuntu-latest + steps: + # Manually check the status of all dependencies. `if: failure()` does not work. + - name: Conclusion + run: | + # Print the dependent jobs to see them in the CI log + jq -C <<< '${{ toJson(needs) }}' + # Check if all jobs that we depend on (in the needs array) were successful. + jq --exit-status 'all(.result == "success")' <<< '${{ toJson(needs) }}' diff --git a/compiler/rustc_codegen_gcc/.github/workflows/failures.yml b/compiler/rustc_codegen_gcc/.github/workflows/failures.yml index d080bbfe91fe..bc42eb1468ea 100644 --- a/compiler/rustc_codegen_gcc/.github/workflows/failures.yml +++ b/compiler/rustc_codegen_gcc/.github/workflows/failures.yml @@ -2,7 +2,10 @@ name: Failures on: - - pull_request + push: + branches: + - master + pull_request: permissions: contents: read @@ -108,3 +111,22 @@ jobs: echo "Error: 'the compiler unexpectedly panicked' found in output logs. CI Error!!" exit 1 fi + + # Summary job for the merge queue. + # ALL THE PREVIOUS JOBS NEED TO BE ADDED TO THE `needs` SECTION OF THIS JOB! + success_failures: + needs: [build] + # We need to ensure this job does *not* get skipped if its dependencies fail, + # because a skipped job is considered a success by GitHub. So we have to + # overwrite `if:`. We use `!cancelled()` to ensure the job does still not get run + # when the workflow is canceled manually. + if: ${{ !cancelled() }} + runs-on: ubuntu-latest + steps: + # Manually check the status of all dependencies. `if: failure()` does not work. + - name: Conclusion + run: | + # Print the dependent jobs to see them in the CI log + jq -C <<< '${{ toJson(needs) }}' + # Check if all jobs that we depend on (in the needs array) were successful. + jq --exit-status 'all(.result == "success")' <<< '${{ toJson(needs) }}' diff --git a/compiler/rustc_codegen_gcc/.github/workflows/gcc12.yml b/compiler/rustc_codegen_gcc/.github/workflows/gcc12.yml index bb9e020dc6a4..da9a1506855c 100644 --- a/compiler/rustc_codegen_gcc/.github/workflows/gcc12.yml +++ b/compiler/rustc_codegen_gcc/.github/workflows/gcc12.yml @@ -1,8 +1,10 @@ name: CI libgccjit 12 on: - - push - - pull_request + push: + branches: + - master + pull_request: permissions: contents: read @@ -85,3 +87,22 @@ jobs: #- name: Run tests #run: | #./y.sh test --release --clean --build-sysroot ${{ matrix.commands }} --no-default-features + + # Summary job for the merge queue. + # ALL THE PREVIOUS JOBS NEED TO BE ADDED TO THE `needs` SECTION OF THIS JOB! + success_gcc12: + needs: [build] + # We need to ensure this job does *not* get skipped if its dependencies fail, + # because a skipped job is considered a success by GitHub. So we have to + # overwrite `if:`. We use `!cancelled()` to ensure the job does still not get run + # when the workflow is canceled manually. + if: ${{ !cancelled() }} + runs-on: ubuntu-latest + steps: + # Manually check the status of all dependencies. `if: failure()` does not work. + - name: Conclusion + run: | + # Print the dependent jobs to see them in the CI log + jq -C <<< '${{ toJson(needs) }}' + # Check if all jobs that we depend on (in the needs array) were successful. + jq --exit-status 'all(.result == "success")' <<< '${{ toJson(needs) }}' diff --git a/compiler/rustc_codegen_gcc/.github/workflows/m68k.yml b/compiler/rustc_codegen_gcc/.github/workflows/m68k.yml index ed1fc02bd913..21731f7087e2 100644 --- a/compiler/rustc_codegen_gcc/.github/workflows/m68k.yml +++ b/compiler/rustc_codegen_gcc/.github/workflows/m68k.yml @@ -3,8 +3,10 @@ name: m68k CI on: - - push - - pull_request + push: + branches: + - master + pull_request: permissions: contents: read @@ -105,3 +107,22 @@ jobs: - name: Run tests run: | ./y.sh test --release --clean --build-sysroot --sysroot-features compiler_builtins/no-f16-f128 ${{ matrix.commands }} + + # Summary job for the merge queue. + # ALL THE PREVIOUS JOBS NEED TO BE ADDED TO THE `needs` SECTION OF THIS JOB! + success_m68k: + needs: [build] + # We need to ensure this job does *not* get skipped if its dependencies fail, + # because a skipped job is considered a success by GitHub. So we have to + # overwrite `if:`. We use `!cancelled()` to ensure the job does still not get run + # when the workflow is canceled manually. + if: ${{ !cancelled() }} + runs-on: ubuntu-latest + steps: + # Manually check the status of all dependencies. `if: failure()` does not work. + - name: Conclusion + run: | + # Print the dependent jobs to see them in the CI log + jq -C <<< '${{ toJson(needs) }}' + # Check if all jobs that we depend on (in the needs array) were successful. + jq --exit-status 'all(.result == "success")' <<< '${{ toJson(needs) }}' diff --git a/compiler/rustc_codegen_gcc/.github/workflows/release.yml b/compiler/rustc_codegen_gcc/.github/workflows/release.yml index 886ce90b4713..47a40286554e 100644 --- a/compiler/rustc_codegen_gcc/.github/workflows/release.yml +++ b/compiler/rustc_codegen_gcc/.github/workflows/release.yml @@ -1,8 +1,10 @@ name: CI with sysroot compiled in release mode on: - - push - - pull_request + push: + branches: + - master + pull_request: permissions: contents: read @@ -82,3 +84,22 @@ jobs: echo "Test is done with LTO enabled, hence inlining should occur across crates" exit 1 fi + + # Summary job for the merge queue. + # ALL THE PREVIOUS JOBS NEED TO BE ADDED TO THE `needs` SECTION OF THIS JOB! + success_release: + needs: [build] + # We need to ensure this job does *not* get skipped if its dependencies fail, + # because a skipped job is considered a success by GitHub. So we have to + # overwrite `if:`. We use `!cancelled()` to ensure the job does still not get run + # when the workflow is canceled manually. + if: ${{ !cancelled() }} + runs-on: ubuntu-latest + steps: + # Manually check the status of all dependencies. `if: failure()` does not work. + - name: Conclusion + run: | + # Print the dependent jobs to see them in the CI log + jq -C <<< '${{ toJson(needs) }}' + # Check if all jobs that we depend on (in the needs array) were successful. + jq --exit-status 'all(.result == "success")' <<< '${{ toJson(needs) }}' diff --git a/compiler/rustc_codegen_gcc/.github/workflows/stdarch.yml b/compiler/rustc_codegen_gcc/.github/workflows/stdarch.yml index d5ae6144496f..4b9f48e7b183 100644 --- a/compiler/rustc_codegen_gcc/.github/workflows/stdarch.yml +++ b/compiler/rustc_codegen_gcc/.github/workflows/stdarch.yml @@ -1,8 +1,10 @@ name: stdarch tests with sysroot compiled in release mode on: - - push - - pull_request + push: + branches: + - master + pull_request: permissions: contents: read @@ -102,3 +104,22 @@ jobs: # TODO: remove --skip test_mm512_stream_ps when stdarch is updated in rustc. # TODO: remove --skip test_tile_ when it's implemented. STDARCH_TEST_EVERYTHING=1 CHANNEL=release CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_RUNNER="${{ matrix.cargo_runner }}" TARGET=x86_64-unknown-linux-gnu CG_RUSTFLAGS="-Ainternal_features --cfg stdarch_intel_sde" ./y.sh cargo test --manifest-path build/build_sysroot/sysroot_src/library/stdarch/Cargo.toml -- --skip rtm --skip tbm --skip sse4a --skip test_mm512_stream_ps --skip test_tile_ + + # Summary job for the merge queue. + # ALL THE PREVIOUS JOBS NEED TO BE ADDED TO THE `needs` SECTION OF THIS JOB! + success_stdarch: + needs: [build] + # We need to ensure this job does *not* get skipped if its dependencies fail, + # because a skipped job is considered a success by GitHub. So we have to + # overwrite `if:`. We use `!cancelled()` to ensure the job does still not get run + # when the workflow is canceled manually. + if: ${{ !cancelled() }} + runs-on: ubuntu-latest + steps: + # Manually check the status of all dependencies. `if: failure()` does not work. + - name: Conclusion + run: | + # Print the dependent jobs to see them in the CI log + jq -C <<< '${{ toJson(needs) }}' + # Check if all jobs that we depend on (in the needs array) were successful. + jq --exit-status 'all(.result == "success")' <<< '${{ toJson(needs) }}' diff --git a/compiler/rustc_codegen_gcc/Cargo.lock b/compiler/rustc_codegen_gcc/Cargo.lock index 636e75b94a3f..832603aa7925 100644 --- a/compiler/rustc_codegen_gcc/Cargo.lock +++ b/compiler/rustc_codegen_gcc/Cargo.lock @@ -56,18 +56,18 @@ dependencies = [ [[package]] name = "gccjit" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72fd91f4adbf02b53cfc73c97bc33c5f253009043f30c56a5ec08dd5c8094dc8" +checksum = "2895ddec764de7ac76fe6c056050c4801a80109c066f177a00a9cc8dee02b29b" dependencies = [ "gccjit_sys", ] [[package]] name = "gccjit_sys" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fb7b8f48a75e2cfe78c3d9a980b32771c34ffd12d196021ab3f98c49fbd2f0d" +checksum = "ac133db68db8a6a8b2c51ef4b18d8ea16682d5814c4641272fe37bbbc223d5f3" dependencies = [ "libc", ] diff --git a/compiler/rustc_codegen_gcc/Cargo.toml b/compiler/rustc_codegen_gcc/Cargo.toml index 63d37358561e..b50f2a626d57 100644 --- a/compiler/rustc_codegen_gcc/Cargo.toml +++ b/compiler/rustc_codegen_gcc/Cargo.toml @@ -22,7 +22,7 @@ master = ["gccjit/master"] default = ["master"] [dependencies] -gccjit = "2.4" +gccjit = "2.5" #gccjit = { git = "https://github.com/rust-lang/gccjit.rs" } # Local copy. diff --git a/compiler/rustc_codegen_gcc/Readme.md b/compiler/rustc_codegen_gcc/Readme.md index e92c16ece2f1..d0e4dbba6d35 100644 --- a/compiler/rustc_codegen_gcc/Readme.md +++ b/compiler/rustc_codegen_gcc/Readme.md @@ -23,7 +23,7 @@ A secondary goal is to check if using the gcc backend will provide any run-time ## Building **This requires a patched libgccjit in order to work. -You need to use my [fork of gcc](https://github.com/antoyo/gcc) which already includes these patches.** +You need to use my [fork of gcc](https://github.com/rust-lang/gcc) which already includes these patches.** ```bash $ cp config.example.toml config.toml @@ -40,7 +40,7 @@ to do a few more things. To build it (most of these instructions come from [here](https://gcc.gnu.org/onlinedocs/jit/internals/index.html), so don't hesitate to take a look there if you encounter an issue): ```bash -$ git clone https://github.com/antoyo/gcc +$ git clone https://github.com/rust-lang/gcc $ sudo apt install flex libmpfr-dev libgmp-dev libmpc3 libmpc-dev $ mkdir gcc-build gcc-install $ cd gcc-build diff --git a/compiler/rustc_codegen_gcc/build_system/src/clone_gcc.rs b/compiler/rustc_codegen_gcc/build_system/src/clone_gcc.rs index e28ee873eb6b..b49dd47f3521 100644 --- a/compiler/rustc_codegen_gcc/build_system/src/clone_gcc.rs +++ b/compiler/rustc_codegen_gcc/build_system/src/clone_gcc.rs @@ -61,7 +61,7 @@ pub fn run() -> Result<(), String> { return Ok(()); }; - let result = git_clone("https://github.com/antoyo/gcc", Some(&args.out_path), false)?; + let result = git_clone("https://github.com/rust-lang/gcc", Some(&args.out_path), false)?; if result.ran_clone { let gcc_commit = args.config_info.get_gcc_commit()?; println!("Checking out GCC commit `{}`...", gcc_commit); diff --git a/compiler/rustc_codegen_gcc/build_system/src/test.rs b/compiler/rustc_codegen_gcc/build_system/src/test.rs index 6c29c7d1825b..df4ac85233b0 100644 --- a/compiler/rustc_codegen_gcc/build_system/src/test.rs +++ b/compiler/rustc_codegen_gcc/build_system/src/test.rs @@ -529,20 +529,21 @@ fn asm_tests(env: &Env, args: &TestArg) -> Result<(), String> { env.insert("COMPILETEST_FORCE_STAGE0".to_string(), "1".to_string()); - let extra = - if args.is_using_gcc_master_branch() { "" } else { " -Csymbol-mangling-version=v0" }; - - let rustc_args = &format!( - r#"-Zpanic-abort-tests \ - -Zcodegen-backend="{pwd}/target/{channel}/librustc_codegen_gcc.{dylib_ext}" \ - --sysroot "{sysroot_dir}" -Cpanic=abort{extra}"#, + let codegen_backend_path = format!( + "{pwd}/target/{channel}/librustc_codegen_gcc.{dylib_ext}", pwd = std::env::current_dir() .map_err(|error| format!("`current_dir` failed: {:?}", error))? .display(), channel = args.config_info.channel.as_str(), dylib_ext = args.config_info.dylib_ext, - sysroot_dir = args.config_info.sysroot_path, - extra = extra, + ); + + let extra = + if args.is_using_gcc_master_branch() { "" } else { " -Csymbol-mangling-version=v0" }; + + let rustc_args = format!( + "-Zpanic-abort-tests -Zcodegen-backend={codegen_backend_path} --sysroot {} -Cpanic=abort{extra}", + args.config_info.sysroot_path ); run_command_with_env( @@ -677,7 +678,7 @@ fn test_projects(env: &Env, args: &TestArg) -> Result<(), String> { fn test_libcore(env: &Env, args: &TestArg) -> Result<(), String> { // FIXME: create a function "display_if_not_quiet" or something along the line. println!("[TEST] libcore"); - let path = get_sysroot_dir().join("sysroot_src/library/core/tests"); + let path = get_sysroot_dir().join("sysroot_src/library/coretests"); let _ = remove_dir_all(path.join("target")); run_cargo_command(&[&"test"], Some(&path), env, args)?; Ok(()) diff --git a/compiler/rustc_codegen_gcc/doc/add-attribute.md b/compiler/rustc_codegen_gcc/doc/add-attribute.md index ae3bcc5e2ebe..267c18195255 100644 --- a/compiler/rustc_codegen_gcc/doc/add-attribute.md +++ b/compiler/rustc_codegen_gcc/doc/add-attribute.md @@ -14,4 +14,4 @@ Finally, you need to update this repository by calling the relevant API you adde To test it, build `gcc`, run `cargo update -p gccjit` and then you can test the generated output for a given Rust crate. -[gccjit.rs]: https://github.com/antoyo/gccjit.rs +[gccjit.rs]: https://github.com/rust-lang/gccjit.rs diff --git a/compiler/rustc_codegen_gcc/example/mini_core.rs b/compiler/rustc_codegen_gcc/example/mini_core.rs index 5544aee9eaf1..c554a87b8256 100644 --- a/compiler/rustc_codegen_gcc/example/mini_core.rs +++ b/compiler/rustc_codegen_gcc/example/mini_core.rs @@ -51,6 +51,10 @@ impl LegacyReceiver for &T {} impl LegacyReceiver for &mut T {} impl LegacyReceiver for Box {} +#[lang = "receiver"] +trait Receiver { +} + #[lang = "copy"] pub trait Copy {} @@ -134,6 +138,14 @@ impl Mul for u8 { } } +impl Mul for i32 { + type Output = Self; + + fn mul(self, rhs: Self) -> Self::Output { + self * rhs + } +} + impl Mul for usize { type Output = Self; @@ -142,6 +154,14 @@ impl Mul for usize { } } +impl Mul for isize { + type Output = Self; + + fn mul(self, rhs: Self) -> Self::Output { + self * rhs + } +} + #[lang = "add"] pub trait Add { type Output; @@ -165,6 +185,14 @@ impl Add for i8 { } } +impl Add for i32 { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + impl Add for usize { type Output = Self; @@ -196,6 +224,14 @@ impl Sub for usize { } } +impl Sub for isize { + type Output = Self; + + fn sub(self, rhs: Self) -> Self { + self - rhs + } +} + impl Sub for u8 { type Output = Self; @@ -220,6 +256,14 @@ impl Sub for i16 { } } +impl Sub for i32 { + type Output = Self; + + fn sub(self, rhs: Self) -> Self { + self - rhs + } +} + #[lang = "rem"] pub trait Rem { type Output; @@ -628,6 +672,10 @@ pub mod libc { pub fn memcpy(dst: *mut u8, src: *const u8, size: usize); pub fn memmove(dst: *mut u8, src: *const u8, size: usize); pub fn strncpy(dst: *mut u8, src: *const u8, size: usize); + pub fn fflush(stream: *mut i32) -> i32; + pub fn exit(status: i32); + + pub static stdout: *mut i32; } } diff --git a/compiler/rustc_codegen_gcc/libgccjit.version b/compiler/rustc_codegen_gcc/libgccjit.version index 417fd5b03935..125b04004b07 100644 --- a/compiler/rustc_codegen_gcc/libgccjit.version +++ b/compiler/rustc_codegen_gcc/libgccjit.version @@ -1 +1 @@ -e607be166673a8de9fc07f6f02c60426e556c5f2 +0ea98a1365b81f7488073512c850e8ee951a4afd diff --git a/compiler/rustc_codegen_gcc/patches/0022-core-Disable-not-compiling-tests.patch b/compiler/rustc_codegen_gcc/patches/0022-core-Disable-not-compiling-tests.patch deleted file mode 100644 index 70e3e2ba7fee..000000000000 --- a/compiler/rustc_codegen_gcc/patches/0022-core-Disable-not-compiling-tests.patch +++ /dev/null @@ -1,44 +0,0 @@ -From af0e237f056fa838c77463381a19b0dc993c0a35 Mon Sep 17 00:00:00 2001 -From: None -Date: Sun, 1 Sep 2024 11:42:17 -0400 -Subject: [PATCH] Disable not compiling tests - ---- - library/core/tests/Cargo.toml | 14 ++++++++++++++ - library/core/tests/lib.rs | 1 + - 2 files changed, 15 insertions(+) - create mode 100644 library/core/tests/Cargo.toml - -diff --git a/library/core/tests/Cargo.toml b/library/core/tests/Cargo.toml -new file mode 100644 -index 0000000..ca326ac ---- /dev/null -+++ b/library/core/tests/Cargo.toml -@@ -0,0 +1,14 @@ -+[workspace] -+ -+[package] -+name = "coretests" -+version = "0.0.0" -+edition = "2021" -+ -+[lib] -+name = "coretests" -+path = "lib.rs" -+ -+[dependencies] -+rand = { version = "0.8.5", default-features = false } -+rand_xorshift = { version = "0.3.0", default-features = false } -diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs -index a4a7946..ecfe43f 100644 ---- a/library/core/tests/lib.rs -+++ b/library/core/tests/lib.rs -@@ -1,4 +1,5 @@ - // tidy-alphabetical-start -+#![cfg(test)] - #![cfg_attr(target_has_atomic = "128", feature(integer_atomics))] - #![cfg_attr(test, feature(cfg_match))] - #![feature(alloc_layout_extra)] --- -2.47.1 - diff --git a/compiler/rustc_codegen_gcc/patches/0028-core-Disable-long-running-tests.patch b/compiler/rustc_codegen_gcc/patches/0028-core-Disable-long-running-tests.patch index dc1beae6d2e7..20df4245cfdf 100644 --- a/compiler/rustc_codegen_gcc/patches/0028-core-Disable-long-running-tests.patch +++ b/compiler/rustc_codegen_gcc/patches/0028-core-Disable-long-running-tests.patch @@ -1,17 +1,17 @@ -From eb703e627e7a84f1cd8d0d87f0f69da1f0acf765 Mon Sep 17 00:00:00 2001 -From: bjorn3 -Date: Fri, 3 Dec 2021 12:16:30 +0100 +From ec2d0dc77fb484d926b45bb626b0db6a4bb0ab5c Mon Sep 17 00:00:00 2001 +From: None +Date: Thu, 27 Mar 2025 09:20:41 -0400 Subject: [PATCH] Disable long running tests --- - library/core/tests/slice.rs | 2 ++ + library/coretests/tests/slice.rs | 2 ++ 1 file changed, 2 insertions(+) -diff --git a/library/core/tests/slice.rs b/library/core/tests/slice.rs -index 8402833..84592e0 100644 ---- a/library/core/tests/slice.rs -+++ b/library/core/tests/slice.rs -@@ -2462,6 +2462,7 @@ take_tests! { +diff --git a/library/coretests/tests/slice.rs b/library/coretests/tests/slice.rs +index d17e681..fba5cd6 100644 +--- a/library/coretests/tests/slice.rs ++++ b/library/coretests/tests/slice.rs +@@ -2486,6 +2486,7 @@ split_off_tests! { #[cfg(not(miri))] // unused in Miri const EMPTY_MAX: &'static [()] = &[(); usize::MAX]; @@ -19,14 +19,14 @@ index 8402833..84592e0 100644 // can't be a constant due to const mutability rules #[cfg(not(miri))] // unused in Miri macro_rules! empty_max_mut { -@@ -2485,6 +2486,7 @@ take_tests! { - (take_mut_oob_max_range_to_inclusive, (..=usize::MAX), None, empty_max_mut!()), - (take_mut_in_bounds_max_range_from, (usize::MAX..), Some(&mut [] as _), empty_max_mut!()), +@@ -2509,6 +2510,7 @@ split_off_tests! { + (split_off_mut_oob_max_range_to_inclusive, (..=usize::MAX), None, empty_max_mut!()), + (split_off_mut_in_bounds_max_range_from, (usize::MAX..), Some(&mut [] as _), empty_max_mut!()), } +*/ #[test] fn test_slice_from_ptr_range() { -- -2.26.2.7.g19db9cfb68 +2.49.0 diff --git a/compiler/rustc_codegen_gcc/patches/cross_patches/0001-Disable-libstd-and-libtest-dylib.patch b/compiler/rustc_codegen_gcc/patches/cross_patches/0001-Disable-libstd-and-libtest-dylib.patch index c220f53040f0..fa360fe9e74e 100644 --- a/compiler/rustc_codegen_gcc/patches/cross_patches/0001-Disable-libstd-and-libtest-dylib.patch +++ b/compiler/rustc_codegen_gcc/patches/cross_patches/0001-Disable-libstd-and-libtest-dylib.patch @@ -1,19 +1,18 @@ -From 966beefe08be6045bfcca26079b76a7a80413080 Mon Sep 17 00:00:00 2001 +From b2911e732d1bf0e28872495c4c47af1dad3c7911 Mon Sep 17 00:00:00 2001 From: None -Date: Thu, 28 Sep 2023 17:37:38 -0400 +Date: Thu, 27 Mar 2025 14:30:10 -0400 Subject: [PATCH] Disable libstd and libtest dylib --- - library/std/Cargo.toml | 2 +- - library/test/Cargo.toml | 2 +- - 2 files changed, 2 insertions(+), 2 deletions(-) + library/std/Cargo.toml | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml -index 5b21355..cb0c49b 100644 +index 176da60..c183cdb 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml -@@ -9,7 +9,7 @@ description = "The Rust Standard Library" - edition = "2021" +@@ -10,7 +10,7 @@ edition = "2024" + autobenches = false [lib] -crate-type = ["dylib", "rlib"] @@ -21,3 +20,6 @@ index 5b21355..cb0c49b 100644 [dependencies] alloc = { path = "../alloc", public = true } +-- +2.49.0 + diff --git a/compiler/rustc_codegen_gcc/patches/libgccjit12/0001-core-Disable-portable-simd-test.patch b/compiler/rustc_codegen_gcc/patches/libgccjit12/0001-core-Disable-portable-simd-test.patch index 9ef5e0e4f467..9d5b2dc537d2 100644 --- a/compiler/rustc_codegen_gcc/patches/libgccjit12/0001-core-Disable-portable-simd-test.patch +++ b/compiler/rustc_codegen_gcc/patches/libgccjit12/0001-core-Disable-portable-simd-test.patch @@ -1,25 +1,17 @@ -From 124a11ce086952a5794d5cfbaa45175809497b81 Mon Sep 17 00:00:00 2001 +From 1a8f6b8e39f343959d4d2e6b6957a6d780ac3fc0 Mon Sep 17 00:00:00 2001 From: None -Date: Sat, 18 Nov 2023 10:50:36 -0500 -Subject: [PATCH] [core] Disable portable-simd test +Date: Thu, 27 Mar 2025 14:32:14 -0400 +Subject: [PATCH] Disable portable-simd test --- - library/core/tests/lib.rs | 2 -- - 1 file changed, 2 deletions(-) + library/coretests/tests/lib.rs | 1 - + 1 file changed, 1 deletion(-) -diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs -index b71786c..cf484d5 100644 ---- a/library/core/tests/lib.rs -+++ b/library/core/tests/lib.rs -@@ -87,7 +87,6 @@ - #![feature(numfmt)] - #![feature(pattern)] - #![feature(pointer_is_aligned_to)] --#![feature(portable_simd)] - #![feature(ptr_metadata)] - #![feature(slice_from_ptr_range)] - #![feature(slice_internals)] -@@ -155,7 +154,6 @@ mod pin; +diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs +index 79022fe..9223b2f 100644 +--- a/library/coretests/tests/lib.rs ++++ b/library/coretests/tests/lib.rs +@@ -165,7 +165,6 @@ mod pin; mod pin_macro; mod ptr; mod result; @@ -27,4 +19,6 @@ index b71786c..cf484d5 100644 mod slice; mod str; mod str_lossy; --- 2.45.2 +-- +2.49.0 + diff --git a/compiler/rustc_codegen_gcc/rust-toolchain b/compiler/rustc_codegen_gcc/rust-toolchain index 940b3de9f745..fd898c59707b 100644 --- a/compiler/rustc_codegen_gcc/rust-toolchain +++ b/compiler/rustc_codegen_gcc/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2025-01-12" +channel = "nightly-2025-04-17" components = ["rust-src", "rustc-dev", "llvm-tools-preview"] diff --git a/compiler/rustc_codegen_gcc/src/abi.rs b/compiler/rustc_codegen_gcc/src/abi.rs index 9fe6baa3d257..a96b18e01c08 100644 --- a/compiler/rustc_codegen_gcc/src/abi.rs +++ b/compiler/rustc_codegen_gcc/src/abi.rs @@ -9,6 +9,8 @@ use rustc_middle::ty::Ty; use rustc_middle::ty::layout::LayoutOf; #[cfg(feature = "master")] use rustc_session::config; +#[cfg(feature = "master")] +use rustc_target::callconv::Conv; use rustc_target::callconv::{ArgAttributes, CastTarget, FnAbi, PassMode}; use crate::builder::Builder; @@ -105,6 +107,8 @@ pub trait FnAbiGccExt<'gcc, 'tcx> { // TODO(antoyo): return a function pointer type instead? fn gcc_type(&self, cx: &CodegenCx<'gcc, 'tcx>) -> FnAbiGcc<'gcc>; fn ptr_to_gcc_type(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc>; + #[cfg(feature = "master")] + fn gcc_cconv(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Option>; } impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { @@ -227,4 +231,47 @@ impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { ); pointer_type } + + #[cfg(feature = "master")] + fn gcc_cconv(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Option> { + conv_to_fn_attribute(self.conv, &cx.tcx.sess.target.arch) + } +} + +#[cfg(feature = "master")] +pub fn conv_to_fn_attribute<'gcc>(conv: Conv, arch: &str) -> Option> { + // TODO: handle the calling conventions returning None. + let attribute = match conv { + Conv::C + | Conv::Rust + | Conv::CCmseNonSecureCall + | Conv::CCmseNonSecureEntry + | Conv::RiscvInterrupt { .. } => return None, + Conv::Cold => return None, + Conv::PreserveMost => return None, + Conv::PreserveAll => return None, + Conv::GpuKernel => { + // TODO(antoyo): remove clippy allow attribute when this is implemented. + #[allow(clippy::if_same_then_else)] + if arch == "amdgpu" { + return None; + } else if arch == "nvptx64" { + return None; + } else { + panic!("Architecture {} does not support GpuKernel calling convention", arch); + } + } + Conv::AvrInterrupt => return None, + Conv::AvrNonBlockingInterrupt => return None, + Conv::ArmAapcs => return None, + Conv::Msp430Intr => return None, + Conv::X86Fastcall => return None, + Conv::X86Intr => return None, + Conv::X86Stdcall => return None, + Conv::X86ThisCall => return None, + Conv::X86VectorCall => return None, + Conv::X86_64SysV => FnAttribute::SysvAbi, + Conv::X86_64Win64 => FnAttribute::MsAbi, + }; + Some(attribute) } diff --git a/compiler/rustc_codegen_gcc/src/asm.rs b/compiler/rustc_codegen_gcc/src/asm.rs index 415f8affab90..dbdf37ee6c9e 100644 --- a/compiler/rustc_codegen_gcc/src/asm.rs +++ b/compiler/rustc_codegen_gcc/src/asm.rs @@ -36,7 +36,8 @@ use crate::type_of::LayoutGccExt; // // 3. Clobbers. GCC has a separate list of clobbers, and clobbers don't have indexes. // Contrary, Rust expresses clobbers through "out" operands that aren't tied to -// a variable (`_`), and such "clobbers" do have index. +// a variable (`_`), and such "clobbers" do have index. Input operands cannot also +// be clobbered. // // 4. Furthermore, GCC Extended Asm does not support explicit register constraints // (like `out("eax")`) directly, offering so-called "local register variables" @@ -161,6 +162,16 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { // Also, we don't emit any asm operands immediately; we save them to // the one of the buffers to be emitted later. + let mut input_registers = vec![]; + + for op in rust_operands { + if let InlineAsmOperandRef::In { reg, .. } = *op { + if let ConstraintOrRegister::Register(reg_name) = reg_to_gcc(reg) { + input_registers.push(reg_name); + } + } + } + // 1. Normal variables (and saving operands to buffers). for (rust_idx, op) in rust_operands.iter().enumerate() { match *op { @@ -183,25 +194,39 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { continue; } (Register(reg_name), None) => { - // `clobber_abi` can add lots of clobbers that are not supported by the target, - // such as AVX-512 registers, so we just ignore unsupported registers - let is_target_supported = - reg.reg_class().supported_types(asm_arch, true).iter().any( - |&(_, feature)| { - if let Some(feature) = feature { - self.tcx - .asm_target_features(instance.def_id()) - .contains(&feature) - } else { - true // Register class is unconditionally supported - } - }, - ); + if input_registers.contains(®_name) { + // the `clobber_abi` operand is converted into a series of + // `lateout("reg") _` operands. Of course, a user could also + // explicitly define such an output operand. + // + // GCC does not allow input registers to be clobbered, so if this out register + // is also used as an in register, do not add it to the clobbers list. + // it will be treated as a lateout register with `out_place: None` + if !late { + bug!("input registers can only be used as lateout regisers"); + } + ("r", dummy_output_type(self.cx, reg.reg_class())) + } else { + // `clobber_abi` can add lots of clobbers that are not supported by the target, + // such as AVX-512 registers, so we just ignore unsupported registers + let is_target_supported = + reg.reg_class().supported_types(asm_arch, true).iter().any( + |&(_, feature)| { + if let Some(feature) = feature { + self.tcx + .asm_target_features(instance.def_id()) + .contains(&feature) + } else { + true // Register class is unconditionally supported + } + }, + ); - if is_target_supported && !clobbers.contains(®_name) { - clobbers.push(reg_name); + if is_target_supported && !clobbers.contains(®_name) { + clobbers.push(reg_name); + } + continue; } - continue; } }; @@ -230,13 +255,10 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { } InlineAsmOperandRef::InOut { reg, late, in_value, out_place } => { - let constraint = - if let ConstraintOrRegister::Constraint(constraint) = reg_to_gcc(reg) { - constraint - } else { - // left for the next pass - continue; - }; + let ConstraintOrRegister::Constraint(constraint) = reg_to_gcc(reg) else { + // left for the next pass + continue; + }; // Rustc frontend guarantees that input and output types are "compatible", // so we can just use input var's type for the output variable. @@ -589,114 +611,127 @@ fn estimate_template_length( } /// Converts a register class to a GCC constraint code. -fn reg_to_gcc(reg: InlineAsmRegOrRegClass) -> ConstraintOrRegister { - let constraint = match reg { - // For vector registers LLVM wants the register name to match the type size. +fn reg_to_gcc(reg_or_reg_class: InlineAsmRegOrRegClass) -> ConstraintOrRegister { + match reg_or_reg_class { InlineAsmRegOrRegClass::Reg(reg) => { - match reg { - InlineAsmReg::X86(_) => { - // TODO(antoyo): add support for vector register. - // - // // For explicit registers, we have to create a register variable: https://stackoverflow.com/a/31774784/389119 - return ConstraintOrRegister::Register(match reg.name() { - // Some of registers' names does not map 1-1 from rust to gcc - "st(0)" => "st", + ConstraintOrRegister::Register(explicit_reg_to_gcc(reg)) + } + InlineAsmRegOrRegClass::RegClass(reg_class) => { + ConstraintOrRegister::Constraint(reg_class_to_gcc(reg_class)) + } + } +} - name => name, - }); +fn explicit_reg_to_gcc(reg: InlineAsmReg) -> &'static str { + // For explicit registers, we have to create a register variable: https://stackoverflow.com/a/31774784/389119 + match reg { + InlineAsmReg::X86(reg) => { + // TODO(antoyo): add support for vector register. + match reg.reg_class() { + X86InlineAsmRegClass::reg_byte => { + // GCC does not support the `b` suffix, so we just strip it + // see https://github.com/rust-lang/rustc_codegen_gcc/issues/485 + reg.name().trim_end_matches('b') } + _ => match reg.name() { + // Some of registers' names does not map 1-1 from rust to gcc + "st(0)" => "st", - _ => unimplemented!(), + name => name, + }, } } - // They can be retrieved from https://gcc.gnu.org/onlinedocs/gcc/Machine-Constraints.html - InlineAsmRegOrRegClass::RegClass(reg) => match reg { - InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::reg) => "r", - InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg) => "w", - InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16) => "x", - InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::preg) => { - unreachable!("clobber-only") - } - InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg) => "r", - InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg) - | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg_low16) - | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low8) - | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg_low16) - | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg_low8) - | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low4) - | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg) - | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg) => "t", - InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg) => "r", - InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_upper) => "d", - InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_pair) => "r", - InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_iw) => "w", - InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_ptr) => "e", - InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::reg) => "r", - InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::wreg) => "w", - InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => "r", - InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::preg) => { - unreachable!("clobber-only") - } - InlineAsmRegClass::LoongArch(LoongArchInlineAsmRegClass::reg) => "r", - InlineAsmRegClass::LoongArch(LoongArchInlineAsmRegClass::freg) => "f", - InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg) => "r", - InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg_addr) => "a", - InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg_data) => "d", - InlineAsmRegClass::CSKY(CSKYInlineAsmRegClass::reg) => "r", - InlineAsmRegClass::CSKY(CSKYInlineAsmRegClass::freg) => "f", - InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg) => "d", // more specific than "r" - InlineAsmRegClass::Mips(MipsInlineAsmRegClass::freg) => "f", - InlineAsmRegClass::Msp430(Msp430InlineAsmRegClass::reg) => "r", - // https://github.com/gcc-mirror/gcc/blob/master/gcc/config/nvptx/nvptx.md -> look for - // "define_constraint". - InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg16) => "h", - InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg32) => "r", - InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg64) => "l", - InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg) => "r", - InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg_nonzero) => "b", - InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::freg) => "f", - InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::vreg) => "v", - InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::cr) - | InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::xer) => { - unreachable!("clobber-only") - } - InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) => "r", - InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => "f", - InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::vreg) => { - unreachable!("clobber-only") - } - InlineAsmRegClass::X86(X86InlineAsmRegClass::reg) => "r", - InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_abcd) => "Q", - InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_byte) => "q", - InlineAsmRegClass::X86(X86InlineAsmRegClass::xmm_reg) - | InlineAsmRegClass::X86(X86InlineAsmRegClass::ymm_reg) => "x", - InlineAsmRegClass::X86(X86InlineAsmRegClass::zmm_reg) => "v", - InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => "Yk", - InlineAsmRegClass::X86( - X86InlineAsmRegClass::kreg0 - | X86InlineAsmRegClass::x87_reg - | X86InlineAsmRegClass::mmx_reg - | X86InlineAsmRegClass::tmm_reg, - ) => unreachable!("clobber-only"), - InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => { - bug!("GCC backend does not support SPIR-V") - } - InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => "r", - InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg) => "r", - InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg_addr) => "a", - InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => "f", - InlineAsmRegClass::S390x(S390xInlineAsmRegClass::vreg) => "v", - InlineAsmRegClass::S390x(S390xInlineAsmRegClass::areg) => { - unreachable!("clobber-only") - } - InlineAsmRegClass::Sparc(SparcInlineAsmRegClass::reg) => "r", - InlineAsmRegClass::Sparc(SparcInlineAsmRegClass::yreg) => unreachable!("clobber-only"), - InlineAsmRegClass::Err => unreachable!(), - }, - }; + _ => unimplemented!(), + } +} - ConstraintOrRegister::Constraint(constraint) +/// They can be retrieved from https://gcc.gnu.org/onlinedocs/gcc/Machine-Constraints.html +fn reg_class_to_gcc(reg_class: InlineAsmRegClass) -> &'static str { + match reg_class { + InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::reg) => "r", + InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg) => "w", + InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16) => "x", + InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::preg) => { + unreachable!("clobber-only") + } + InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg) => "r", + InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg) + | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg_low16) + | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low8) + | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg_low16) + | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg_low8) + | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low4) + | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg) + | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg) => "t", + InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg) => "r", + InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_upper) => "d", + InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_pair) => "r", + InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_iw) => "w", + InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_ptr) => "e", + InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::reg) => "r", + InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::wreg) => "w", + InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => "r", + InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::preg) => { + unreachable!("clobber-only") + } + InlineAsmRegClass::LoongArch(LoongArchInlineAsmRegClass::reg) => "r", + InlineAsmRegClass::LoongArch(LoongArchInlineAsmRegClass::freg) => "f", + InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg) => "r", + InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg_addr) => "a", + InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg_data) => "d", + InlineAsmRegClass::CSKY(CSKYInlineAsmRegClass::reg) => "r", + InlineAsmRegClass::CSKY(CSKYInlineAsmRegClass::freg) => "f", + InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg) => "d", // more specific than "r" + InlineAsmRegClass::Mips(MipsInlineAsmRegClass::freg) => "f", + InlineAsmRegClass::Msp430(Msp430InlineAsmRegClass::reg) => "r", + // https://github.com/gcc-mirror/gcc/blob/master/gcc/config/nvptx/nvptx.md -> look for + // "define_constraint". + InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg16) => "h", + InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg32) => "r", + InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg64) => "l", + + InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg) => "r", + InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg_nonzero) => "b", + InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::freg) => "f", + InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::vreg) => "v", + InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::cr) + | InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::xer) => { + unreachable!("clobber-only") + } + InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) => "r", + InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => "f", + InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::vreg) => { + unreachable!("clobber-only") + } + InlineAsmRegClass::X86(X86InlineAsmRegClass::reg) => "r", + InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_abcd) => "Q", + InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_byte) => "q", + InlineAsmRegClass::X86(X86InlineAsmRegClass::xmm_reg) + | InlineAsmRegClass::X86(X86InlineAsmRegClass::ymm_reg) => "x", + InlineAsmRegClass::X86(X86InlineAsmRegClass::zmm_reg) => "v", + InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => "Yk", + InlineAsmRegClass::X86( + X86InlineAsmRegClass::kreg0 + | X86InlineAsmRegClass::x87_reg + | X86InlineAsmRegClass::mmx_reg + | X86InlineAsmRegClass::tmm_reg, + ) => unreachable!("clobber-only"), + InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => { + bug!("GCC backend does not support SPIR-V") + } + InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => "r", + InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg) => "r", + InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg_addr) => "a", + InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => "f", + InlineAsmRegClass::S390x(S390xInlineAsmRegClass::vreg) => "v", + InlineAsmRegClass::S390x(S390xInlineAsmRegClass::areg) => { + unreachable!("clobber-only") + } + InlineAsmRegClass::Sparc(SparcInlineAsmRegClass::reg) => "r", + InlineAsmRegClass::Sparc(SparcInlineAsmRegClass::yreg) => unreachable!("clobber-only"), + InlineAsmRegClass::Err => unreachable!(), + } } /// Type to use for outputs that are discarded. It doesn't really matter what diff --git a/compiler/rustc_codegen_gcc/src/back/write.rs b/compiler/rustc_codegen_gcc/src/back/write.rs index 51c5ba73e32b..16c895322e88 100644 --- a/compiler/rustc_codegen_gcc/src/back/write.rs +++ b/compiler/rustc_codegen_gcc/src/back/write.rs @@ -24,19 +24,23 @@ pub(crate) unsafe fn codegen( { let context = &module.module_llvm.context; - let module_name = module.name.clone(); - let should_combine_object_files = module.module_llvm.should_combine_object_files; - let module_name = Some(&module_name[..]); - // NOTE: Only generate object files with GIMPLE when this environment variable is set for // now because this requires a particular setup (same gcc/lto1/lto-wrapper commit as libgccjit). // TODO(antoyo): remove this environment variable. let fat_lto = env::var("EMBED_LTO_BITCODE").as_deref() == Ok("1"); - let bc_out = cgcx.output_filenames.temp_path(OutputType::Bitcode, module_name); - let obj_out = cgcx.output_filenames.temp_path(OutputType::Object, module_name); + let bc_out = cgcx.output_filenames.temp_path_for_cgu( + OutputType::Bitcode, + &module.name, + cgcx.invocation_temp.as_deref(), + ); + let obj_out = cgcx.output_filenames.temp_path_for_cgu( + OutputType::Object, + &module.name, + cgcx.invocation_temp.as_deref(), + ); if config.bitcode_needed() { if fat_lto { @@ -117,14 +121,22 @@ pub(crate) unsafe fn codegen( } if config.emit_ir { - let out = cgcx.output_filenames.temp_path(OutputType::LlvmAssembly, module_name); + let out = cgcx.output_filenames.temp_path_for_cgu( + OutputType::LlvmAssembly, + &module.name, + cgcx.invocation_temp.as_deref(), + ); std::fs::write(out, "").expect("write file"); } if config.emit_asm { let _timer = cgcx.prof.generic_activity_with_arg("GCC_module_codegen_emit_asm", &*module.name); - let path = cgcx.output_filenames.temp_path(OutputType::Assembly, module_name); + let path = cgcx.output_filenames.temp_path_for_cgu( + OutputType::Assembly, + &module.name, + cgcx.invocation_temp.as_deref(), + ); context.compile_to_file(OutputKind::Assembler, path.to_str().expect("path to str")); } @@ -238,6 +250,7 @@ pub(crate) unsafe fn codegen( config.emit_asm, config.emit_ir, &cgcx.output_filenames, + cgcx.invocation_temp.as_deref(), )) } diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs index 6573b5b165e6..5c70f4a7df93 100644 --- a/compiler/rustc_codegen_gcc/src/builder.rs +++ b/compiler/rustc_codegen_gcc/src/builder.rs @@ -368,16 +368,8 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let previous_arg_count = args.len(); let orig_args = args; let args = { - let function_address_names = self.function_address_names.borrow(); - let original_function_name = function_address_names.get(&func_ptr); func_ptr = llvm::adjust_function(self.context, &func_name, func_ptr, args); - llvm::adjust_intrinsic_arguments( - self, - gcc_func, - args.into(), - &func_name, - original_function_name, - ) + llvm::adjust_intrinsic_arguments(self, gcc_func, args.into(), &func_name) }; let args_adjusted = args.len() != previous_arg_count; let args = self.check_ptr_call("call", func_ptr, &args); @@ -1271,7 +1263,50 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { } fn fcmp(&mut self, op: RealPredicate, lhs: RValue<'gcc>, rhs: RValue<'gcc>) -> RValue<'gcc> { - self.context.new_comparison(self.location, op.to_gcc_comparison(), lhs, rhs) + // LLVM has a concept of "unordered compares", where eg ULT returns true if either the two + // arguments are unordered (i.e. either is NaN), or the lhs is less than the rhs. GCC does + // not natively have this concept, so in some cases we must manually handle NaNs + let must_handle_nan = match op { + RealPredicate::RealPredicateFalse => unreachable!(), + RealPredicate::RealOEQ => false, + RealPredicate::RealOGT => false, + RealPredicate::RealOGE => false, + RealPredicate::RealOLT => false, + RealPredicate::RealOLE => false, + RealPredicate::RealONE => false, + RealPredicate::RealORD => unreachable!(), + RealPredicate::RealUNO => unreachable!(), + RealPredicate::RealUEQ => false, + RealPredicate::RealUGT => true, + RealPredicate::RealUGE => true, + RealPredicate::RealULT => true, + RealPredicate::RealULE => true, + RealPredicate::RealUNE => false, + RealPredicate::RealPredicateTrue => unreachable!(), + }; + + let cmp = self.context.new_comparison(self.location, op.to_gcc_comparison(), lhs, rhs); + + if must_handle_nan { + let is_nan = self.context.new_binary_op( + self.location, + BinaryOp::LogicalOr, + self.cx.bool_type, + // compare a value to itself to check whether it is NaN + self.context.new_comparison(self.location, ComparisonOp::NotEquals, lhs, lhs), + self.context.new_comparison(self.location, ComparisonOp::NotEquals, rhs, rhs), + ); + + self.context.new_binary_op( + self.location, + BinaryOp::LogicalOr, + self.cx.bool_type, + is_nan, + cmp, + ) + } else { + cmp + } } /* Miscellaneous instructions */ diff --git a/compiler/rustc_codegen_gcc/src/context.rs b/compiler/rustc_codegen_gcc/src/context.rs index 1e1f577bb3a1..73718994e641 100644 --- a/compiler/rustc_codegen_gcc/src/context.rs +++ b/compiler/rustc_codegen_gcc/src/context.rs @@ -23,6 +23,8 @@ use rustc_target::spec::{ HasTargetSpec, HasWasmCAbiOpt, HasX86AbiOpt, Target, TlsModel, WasmCAbi, X86Abi, }; +#[cfg(feature = "master")] +use crate::abi::conv_to_fn_attribute; use crate::callee::get_fn; use crate::common::SignType; @@ -213,33 +215,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { let bool_type = context.new_type::(); let mut functions = FxHashMap::default(); - let builtins = [ - "__builtin_unreachable", - "abort", - "__builtin_expect", /*"__builtin_expect_with_probability",*/ - "__builtin_constant_p", - "__builtin_add_overflow", - "__builtin_mul_overflow", - "__builtin_saddll_overflow", - /*"__builtin_sadd_overflow",*/ - "__builtin_smulll_overflow", /*"__builtin_smul_overflow",*/ - "__builtin_ssubll_overflow", - /*"__builtin_ssub_overflow",*/ "__builtin_sub_overflow", - "__builtin_uaddll_overflow", - "__builtin_uadd_overflow", - "__builtin_umulll_overflow", - "__builtin_umul_overflow", - "__builtin_usubll_overflow", - "__builtin_usub_overflow", - "__builtin_powif", - "__builtin_powi", - "fabsf", - "fabs", - "copysignf", - "copysign", - "nearbyintf", - "nearbyint", - ]; + let builtins = ["abort"]; for builtin in builtins.iter() { functions.insert(builtin.to_string(), context.get_builtin_function(builtin)); @@ -509,7 +485,11 @@ impl<'gcc, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { fn declare_c_main(&self, fn_type: Self::Type) -> Option { let entry_name = self.sess().target.entry_name.as_ref(); if !self.functions.borrow().contains_key(entry_name) { - Some(self.declare_entry_fn(entry_name, fn_type, ())) + #[cfg(feature = "master")] + let conv = conv_to_fn_attribute(self.sess().target.entry_abi, &self.sess().target.arch); + #[cfg(not(feature = "master"))] + let conv = None; + Some(self.declare_entry_fn(entry_name, fn_type, conv)) } else { // If the symbol already exists, it is an error: for example, the user wrote // #[no_mangle] extern "C" fn main(..) {..} @@ -605,7 +585,10 @@ impl<'b, 'tcx> CodegenCx<'b, 'tcx> { let mut name = String::with_capacity(prefix.len() + 6); name.push_str(prefix); name.push('.'); - name.push_str(&(idx as u64).to_base(ALPHANUMERIC_ONLY)); + // Offset the index by the base so that always at least two characters + // are generated. This avoids cases where the suffix is interpreted as + // size by the assembler (for m68k: .b, .w, .l). + name.push_str(&(idx as u64 + ALPHANUMERIC_ONLY as u64).to_base(ALPHANUMERIC_ONLY)); name } } diff --git a/compiler/rustc_codegen_gcc/src/declare.rs b/compiler/rustc_codegen_gcc/src/declare.rs index 7cdbe3c0c629..c1ca3eb849e8 100644 --- a/compiler/rustc_codegen_gcc/src/declare.rs +++ b/compiler/rustc_codegen_gcc/src/declare.rs @@ -58,7 +58,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { variadic: bool, ) -> Function<'gcc> { self.linkage.set(FunctionType::Extern); - declare_raw_fn(self, name, () /*llvm::CCallConv*/, return_type, params, variadic) + declare_raw_fn(self, name, None, return_type, params, variadic) } pub fn declare_global( @@ -92,7 +92,8 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { &self, name: &str, _fn_type: Type<'gcc>, - callconv: (), /*llvm::CCallConv*/ + #[cfg(feature = "master")] callconv: Option>, + #[cfg(not(feature = "master"))] callconv: Option<()>, ) -> RValue<'gcc> { // TODO(antoyo): use the fn_type parameter. let const_string = self.context.new_type::().make_pointer().make_pointer(); @@ -123,14 +124,11 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { #[cfg(feature = "master")] fn_attributes, } = fn_abi.gcc_type(self); - let func = declare_raw_fn( - self, - name, - (), /*fn_abi.llvm_cconv()*/ - return_type, - &arguments_type, - is_c_variadic, - ); + #[cfg(feature = "master")] + let conv = fn_abi.gcc_cconv(self); + #[cfg(not(feature = "master"))] + let conv = None; + let func = declare_raw_fn(self, name, conv, return_type, &arguments_type, is_c_variadic); self.on_stack_function_params.borrow_mut().insert(func, on_stack_param_indices); #[cfg(feature = "master")] for fn_attr in fn_attributes { @@ -162,7 +160,8 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { fn declare_raw_fn<'gcc>( cx: &CodegenCx<'gcc, '_>, name: &str, - _callconv: (), /*llvm::CallConv*/ + #[cfg(feature = "master")] callconv: Option>, + #[cfg(not(feature = "master"))] _callconv: Option<()>, return_type: Type<'gcc>, param_types: &[Type<'gcc>], variadic: bool, @@ -192,6 +191,10 @@ fn declare_raw_fn<'gcc>( let name = &mangle_name(name); let func = cx.context.new_function(None, cx.linkage.get(), return_type, ¶ms, name, variadic); + #[cfg(feature = "master")] + if let Some(attribute) = callconv { + func.add_attribute(attribute); + } cx.functions.borrow_mut().insert(name.to_string(), func); #[cfg(feature = "master")] diff --git a/compiler/rustc_codegen_gcc/src/gcc_util.rs b/compiler/rustc_codegen_gcc/src/gcc_util.rs index 6eae0c24f48a..202764d56491 100644 --- a/compiler/rustc_codegen_gcc/src/gcc_util.rs +++ b/compiler/rustc_codegen_gcc/src/gcc_util.rs @@ -194,6 +194,7 @@ pub fn to_gcc_features<'a>(sess: &Session, s: &'a str) -> SmallVec<[&'a str; 2]> fn arch_to_gcc(name: &str) -> &str { match name { + "M68000" => "68000", "M68020" => "68020", _ => name, } diff --git a/compiler/rustc_codegen_gcc/src/int.rs b/compiler/rustc_codegen_gcc/src/int.rs index f3552d9b12fc..9b5b0fde6e2f 100644 --- a/compiler/rustc_codegen_gcc/src/int.rs +++ b/compiler/rustc_codegen_gcc/src/int.rs @@ -404,7 +404,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let ret_indirect = matches!(fn_abi.ret.mode, PassMode::Indirect { .. }); - let result = if ret_indirect { + let call = if ret_indirect { let res_value = self.current_func().new_local(self.location, res_type, "result_value"); let res_addr = res_value.get_address(self.location); let res_param_type = res_type.make_pointer(); @@ -432,8 +432,17 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { ); self.context.new_call(self.location, func, &[lhs, rhs, overflow_addr]) }; + // NOTE: we must assign the result of the operation to a variable at this point to make + // sure it will be evaluated by libgccjit now. + // Otherwise, it will only be evaluated when the rvalue for the call is used somewhere else + // and overflow_value will not be initialized at the correct point in the program. + let result = self.current_func().new_local(self.location, res_type, "result"); + self.block.add_assignment(self.location, result, call); - (result, self.context.new_cast(self.location, overflow_value, self.bool_type).to_rvalue()) + ( + result.to_rvalue(), + self.context.new_cast(self.location, overflow_value, self.bool_type).to_rvalue(), + ) } pub fn gcc_icmp( @@ -865,6 +874,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { let value_type = value.get_type(); if self.is_native_int_type_or_bool(dest_typ) && self.is_native_int_type_or_bool(value_type) { + // TODO: use self.location. self.context.new_cast(None, value, dest_typ) } else if self.is_native_int_type_or_bool(dest_typ) { self.context.new_cast(None, self.low(value), dest_typ) @@ -905,6 +915,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { let name_suffix = match self.type_kind(dest_typ) { TypeKind::Float => "tisf", TypeKind::Double => "tidf", + TypeKind::FP128 => "tixf", kind => panic!("cannot cast a non-native integer to type {:?}", kind), }; let sign = if signed { "" } else { "un" }; diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/llvm.rs b/compiler/rustc_codegen_gcc/src/intrinsic/llvm.rs index 2d731f88d7d3..0eebd21001a9 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/llvm.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/llvm.rs @@ -1,11 +1,90 @@ use std::borrow::Cow; -use gccjit::{CType, Context, Function, FunctionPtrType, RValue, ToRValue, UnaryOp}; +use gccjit::{CType, Context, Field, Function, FunctionPtrType, RValue, ToRValue, Type}; use rustc_codegen_ssa::traits::BuilderMethods; use crate::builder::Builder; use crate::context::CodegenCx; +fn encode_key_128_type<'a, 'gcc, 'tcx>( + builder: &Builder<'a, 'gcc, 'tcx>, +) -> (Type<'gcc>, Field<'gcc>, Field<'gcc>) { + let m128i = builder.context.new_vector_type(builder.i64_type, 2); + let field1 = builder.context.new_field(None, builder.u32_type, "field1"); + let field2 = builder.context.new_field(None, m128i, "field2"); + let field3 = builder.context.new_field(None, m128i, "field3"); + let field4 = builder.context.new_field(None, m128i, "field4"); + let field5 = builder.context.new_field(None, m128i, "field5"); + let field6 = builder.context.new_field(None, m128i, "field6"); + let field7 = builder.context.new_field(None, m128i, "field7"); + let encode_type = builder.context.new_struct_type( + None, + "EncodeKey128Output", + &[field1, field2, field3, field4, field5, field6, field7], + ); + #[cfg(feature = "master")] + encode_type.as_type().set_packed(); + (encode_type.as_type(), field1, field2) +} + +fn encode_key_256_type<'a, 'gcc, 'tcx>( + builder: &Builder<'a, 'gcc, 'tcx>, +) -> (Type<'gcc>, Field<'gcc>, Field<'gcc>) { + let m128i = builder.context.new_vector_type(builder.i64_type, 2); + let field1 = builder.context.new_field(None, builder.u32_type, "field1"); + let field2 = builder.context.new_field(None, m128i, "field2"); + let field3 = builder.context.new_field(None, m128i, "field3"); + let field4 = builder.context.new_field(None, m128i, "field4"); + let field5 = builder.context.new_field(None, m128i, "field5"); + let field6 = builder.context.new_field(None, m128i, "field6"); + let field7 = builder.context.new_field(None, m128i, "field7"); + let field8 = builder.context.new_field(None, m128i, "field8"); + let encode_type = builder.context.new_struct_type( + None, + "EncodeKey256Output", + &[field1, field2, field3, field4, field5, field6, field7, field8], + ); + #[cfg(feature = "master")] + encode_type.as_type().set_packed(); + (encode_type.as_type(), field1, field2) +} + +fn aes_output_type<'a, 'gcc, 'tcx>( + builder: &Builder<'a, 'gcc, 'tcx>, +) -> (Type<'gcc>, Field<'gcc>, Field<'gcc>) { + let m128i = builder.context.new_vector_type(builder.i64_type, 2); + let field1 = builder.context.new_field(None, builder.u8_type, "field1"); + let field2 = builder.context.new_field(None, m128i, "field2"); + let aes_output_type = builder.context.new_struct_type(None, "AesOutput", &[field1, field2]); + let typ = aes_output_type.as_type(); + #[cfg(feature = "master")] + typ.set_packed(); + (typ, field1, field2) +} + +fn wide_aes_output_type<'a, 'gcc, 'tcx>( + builder: &Builder<'a, 'gcc, 'tcx>, +) -> (Type<'gcc>, Field<'gcc>, Field<'gcc>) { + let m128i = builder.context.new_vector_type(builder.i64_type, 2); + let field1 = builder.context.new_field(None, builder.u8_type, "field1"); + let field2 = builder.context.new_field(None, m128i, "field2"); + let field3 = builder.context.new_field(None, m128i, "field3"); + let field4 = builder.context.new_field(None, m128i, "field4"); + let field5 = builder.context.new_field(None, m128i, "field5"); + let field6 = builder.context.new_field(None, m128i, "field6"); + let field7 = builder.context.new_field(None, m128i, "field7"); + let field8 = builder.context.new_field(None, m128i, "field8"); + let field9 = builder.context.new_field(None, m128i, "field9"); + let aes_output_type = builder.context.new_struct_type( + None, + "WideAesOutput", + &[field1, field2, field3, field4, field5, field6, field7, field8, field9], + ); + #[cfg(feature = "master")] + aes_output_type.as_type().set_packed(); + (aes_output_type.as_type(), field1, field2) +} + #[cfg_attr(not(feature = "master"), allow(unused_variables))] pub fn adjust_function<'gcc>( context: &'gcc Context<'gcc>, @@ -43,7 +122,6 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>( gcc_func: FunctionPtrType<'gcc>, mut args: Cow<'b, [RValue<'gcc>]>, func_name: &str, - original_function_name: Option<&String>, ) -> Cow<'b, [RValue<'gcc>]> { // TODO: this might not be a good way to workaround the missing tile builtins. if func_name == "__builtin_trap" { @@ -504,6 +582,72 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>( let arg4 = builder.context.new_rvalue_from_int(arg4_type, -1); args = vec![a, b, c, arg4, new_args[3]].into(); } + "__builtin_ia32_encodekey128_u32" => { + let mut new_args = args.to_vec(); + let m128i = builder.context.new_vector_type(builder.i64_type, 2); + let array_type = builder.context.new_array_type(None, m128i, 6); + let result = builder.current_func().new_local(None, array_type, "result"); + new_args.push(result.get_address(None)); + args = new_args.into(); + } + "__builtin_ia32_encodekey256_u32" => { + let mut new_args = args.to_vec(); + let m128i = builder.context.new_vector_type(builder.i64_type, 2); + let array_type = builder.context.new_array_type(None, m128i, 7); + let result = builder.current_func().new_local(None, array_type, "result"); + new_args.push(result.get_address(None)); + args = new_args.into(); + } + "__builtin_ia32_aesenc128kl_u8" + | "__builtin_ia32_aesdec128kl_u8" + | "__builtin_ia32_aesenc256kl_u8" + | "__builtin_ia32_aesdec256kl_u8" => { + let mut new_args = vec![]; + let m128i = builder.context.new_vector_type(builder.i64_type, 2); + let result = builder.current_func().new_local(None, m128i, "result"); + new_args.push(result.get_address(None)); + new_args.extend(args.to_vec()); + args = new_args.into(); + } + "__builtin_ia32_aesencwide128kl_u8" + | "__builtin_ia32_aesdecwide128kl_u8" + | "__builtin_ia32_aesencwide256kl_u8" + | "__builtin_ia32_aesdecwide256kl_u8" => { + let mut new_args = vec![]; + + let mut old_args = args.to_vec(); + let handle = old_args.swap_remove(0); // Called __P in GCC. + let first_value = old_args.swap_remove(0); + + let element_type = first_value.get_type(); + let array_type = builder.context.new_array_type(None, element_type, 8); + let result = builder.current_func().new_local(None, array_type, "result"); + new_args.push(result.get_address(None)); + + let array = builder.current_func().new_local(None, array_type, "array"); + let input = builder.context.new_array_constructor( + None, + array_type, + &[ + first_value, + old_args.swap_remove(0), + old_args.swap_remove(0), + old_args.swap_remove(0), + old_args.swap_remove(0), + old_args.swap_remove(0), + old_args.swap_remove(0), + old_args.swap_remove(0), + ], + ); + builder.llbb().add_assignment(None, array, input); + let input_ptr = array.get_address(None); + let arg2_type = gcc_func.get_param_type(1); + let input_ptr = builder.context.new_cast(None, input_ptr, arg2_type); + new_args.push(input_ptr); + + new_args.push(handle); + args = new_args.into(); + } _ => (), } } else { @@ -541,33 +685,6 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>( let c = builder.context.new_rvalue_from_vector(None, arg3_type, &[new_args[2]; 2]); args = vec![a, b, c, new_args[3]].into(); } - "__builtin_ia32_vfmaddsubpd256" - | "__builtin_ia32_vfmaddsubps" - | "__builtin_ia32_vfmaddsubps256" - | "__builtin_ia32_vfmaddsubpd" => { - if let Some(original_function_name) = original_function_name { - match &**original_function_name { - "llvm.x86.fma.vfmsubadd.pd.256" - | "llvm.x86.fma.vfmsubadd.ps" - | "llvm.x86.fma.vfmsubadd.ps.256" - | "llvm.x86.fma.vfmsubadd.pd" => { - // NOTE: since both llvm.x86.fma.vfmsubadd.ps and llvm.x86.fma.vfmaddsub.ps maps to - // __builtin_ia32_vfmaddsubps, only add minus if this comes from a - // subadd LLVM intrinsic, e.g. _mm256_fmsubadd_pd. - let mut new_args = args.to_vec(); - let arg3 = &mut new_args[2]; - *arg3 = builder.context.new_unary_op( - None, - UnaryOp::Minus, - arg3.get_type(), - *arg3, - ); - args = new_args.into(); - } - _ => (), - } - } - } "__builtin_ia32_ldmxcsr" => { // The builtin __builtin_ia32_ldmxcsr takes an integer value while llvm.x86.sse.ldmxcsr takes a pointer, // so dereference the pointer. @@ -728,6 +845,96 @@ pub fn adjust_intrinsic_return_value<'a, 'gcc, 'tcx>( let f16_type = builder.context.new_c_type(CType::Float16); return_value = builder.context.new_cast(None, return_value, f16_type); } + "__builtin_ia32_encodekey128_u32" => { + // The builtin __builtin_ia32_encodekey128_u32 writes the result in its pointer argument while + // llvm.x86.encodekey128 returns a value. + // We added a result pointer argument and now need to assign its value to the return_value expected by + // the LLVM intrinsic. + let (encode_type, field1, field2) = encode_key_128_type(builder); + let result = builder.current_func().new_local(None, encode_type, "result"); + let field1 = result.access_field(None, field1); + builder.llbb().add_assignment(None, field1, return_value); + let field2 = result.access_field(None, field2); + let field2_type = field2.to_rvalue().get_type(); + let array_type = builder.context.new_array_type(None, field2_type, 6); + let ptr = builder.context.new_cast(None, args[2], array_type.make_pointer()); + let field2_ptr = + builder.context.new_cast(None, field2.get_address(None), array_type.make_pointer()); + builder.llbb().add_assignment( + None, + field2_ptr.dereference(None), + ptr.dereference(None), + ); + return_value = result.to_rvalue(); + } + "__builtin_ia32_encodekey256_u32" => { + // The builtin __builtin_ia32_encodekey256_u32 writes the result in its pointer argument while + // llvm.x86.encodekey256 returns a value. + // We added a result pointer argument and now need to assign its value to the return_value expected by + // the LLVM intrinsic. + let (encode_type, field1, field2) = encode_key_256_type(builder); + let result = builder.current_func().new_local(None, encode_type, "result"); + let field1 = result.access_field(None, field1); + builder.llbb().add_assignment(None, field1, return_value); + let field2 = result.access_field(None, field2); + let field2_type = field2.to_rvalue().get_type(); + let array_type = builder.context.new_array_type(None, field2_type, 7); + let ptr = builder.context.new_cast(None, args[3], array_type.make_pointer()); + let field2_ptr = + builder.context.new_cast(None, field2.get_address(None), array_type.make_pointer()); + builder.llbb().add_assignment( + None, + field2_ptr.dereference(None), + ptr.dereference(None), + ); + return_value = result.to_rvalue(); + } + "__builtin_ia32_aesdec128kl_u8" + | "__builtin_ia32_aesenc128kl_u8" + | "__builtin_ia32_aesdec256kl_u8" + | "__builtin_ia32_aesenc256kl_u8" => { + // The builtin for aesdec/aesenc writes the result in its pointer argument while + // llvm.x86.aesdec128kl returns a value. + // We added a result pointer argument and now need to assign its value to the return_value expected by + // the LLVM intrinsic. + let (aes_output_type, field1, field2) = aes_output_type(builder); + let result = builder.current_func().new_local(None, aes_output_type, "result"); + let field1 = result.access_field(None, field1); + builder.llbb().add_assignment(None, field1, return_value); + let field2 = result.access_field(None, field2); + let ptr = builder.context.new_cast( + None, + args[0], + field2.to_rvalue().get_type().make_pointer(), + ); + builder.llbb().add_assignment(None, field2, ptr.dereference(None)); + return_value = result.to_rvalue(); + } + "__builtin_ia32_aesencwide128kl_u8" + | "__builtin_ia32_aesdecwide128kl_u8" + | "__builtin_ia32_aesencwide256kl_u8" + | "__builtin_ia32_aesdecwide256kl_u8" => { + // The builtin for aesdecwide/aesencwide writes the result in its pointer argument while + // llvm.x86.aesencwide128kl returns a value. + // We added a result pointer argument and now need to assign its value to the return_value expected by + // the LLVM intrinsic. + let (aes_output_type, field1, field2) = wide_aes_output_type(builder); + let result = builder.current_func().new_local(None, aes_output_type, "result"); + let field1 = result.access_field(None, field1); + builder.llbb().add_assignment(None, field1, return_value); + let field2 = result.access_field(None, field2); + let field2_type = field2.to_rvalue().get_type(); + let array_type = builder.context.new_array_type(None, field2_type, 8); + let ptr = builder.context.new_cast(None, args[0], array_type.make_pointer()); + let field2_ptr = + builder.context.new_cast(None, field2.get_address(None), array_type.make_pointer()); + builder.llbb().add_assignment( + None, + field2_ptr.dereference(None), + ptr.dereference(None), + ); + return_value = result.to_rvalue(); + } _ => (), } @@ -915,16 +1122,6 @@ pub fn intrinsic<'gcc, 'tcx>(name: &str, cx: &CodegenCx<'gcc, 'tcx>) -> Function "llvm.ctlz.v4i64" => "__builtin_ia32_vplzcntq_256_mask", "llvm.ctlz.v2i64" => "__builtin_ia32_vplzcntq_128_mask", "llvm.ctpop.v32i16" => "__builtin_ia32_vpopcountw_v32hi", - "llvm.x86.fma.vfmsub.sd" => "__builtin_ia32_vfmsubsd3", - "llvm.x86.fma.vfmsub.ss" => "__builtin_ia32_vfmsubss3", - "llvm.x86.fma.vfmsubadd.pd" => "__builtin_ia32_vfmaddsubpd", - "llvm.x86.fma.vfmsubadd.pd.256" => "__builtin_ia32_vfmaddsubpd256", - "llvm.x86.fma.vfmsubadd.ps" => "__builtin_ia32_vfmaddsubps", - "llvm.x86.fma.vfmsubadd.ps.256" => "__builtin_ia32_vfmaddsubps256", - "llvm.x86.fma.vfnmadd.sd" => "__builtin_ia32_vfnmaddsd3", - "llvm.x86.fma.vfnmadd.ss" => "__builtin_ia32_vfnmaddss3", - "llvm.x86.fma.vfnmsub.sd" => "__builtin_ia32_vfnmsubsd3", - "llvm.x86.fma.vfnmsub.ss" => "__builtin_ia32_vfnmsubss3", "llvm.x86.avx512.conflict.d.512" => "__builtin_ia32_vpconflictsi_512_mask", "llvm.x86.avx512.conflict.d.256" => "__builtin_ia32_vpconflictsi_256_mask", "llvm.x86.avx512.conflict.d.128" => "__builtin_ia32_vpconflictsi_128_mask", @@ -1002,8 +1199,6 @@ pub fn intrinsic<'gcc, 'tcx>(name: &str, cx: &CodegenCx<'gcc, 'tcx>) -> Function "llvm.fshr.v32i16" => "__builtin_ia32_vpshrdv_v32hi", "llvm.fshr.v16i16" => "__builtin_ia32_vpshrdv_v16hi", "llvm.fshr.v8i16" => "__builtin_ia32_vpshrdv_v8hi", - "llvm.x86.fma.vfmadd.sd" => "__builtin_ia32_vfmaddsd3", - "llvm.x86.fma.vfmadd.ss" => "__builtin_ia32_vfmaddss3", "llvm.x86.rdrand.64" => "__builtin_ia32_rdrand64_step", // The above doc points to unknown builtins for the following, so override them: @@ -1324,6 +1519,16 @@ pub fn intrinsic<'gcc, 'tcx>(name: &str, cx: &CodegenCx<'gcc, 'tcx>) -> Function "llvm.x86.avx512fp16.mask.vfmadd.cph.256" => "__builtin_ia32_vfmaddcph256_mask3", "llvm.x86.avx512fp16.mask.vfcmadd.cph.128" => "__builtin_ia32_vfcmaddcph128_mask3", "llvm.x86.avx512fp16.mask.vfmadd.cph.128" => "__builtin_ia32_vfmaddcph128_mask3", + "llvm.x86.encodekey128" => "__builtin_ia32_encodekey128_u32", + "llvm.x86.encodekey256" => "__builtin_ia32_encodekey256_u32", + "llvm.x86.aesenc128kl" => "__builtin_ia32_aesenc128kl_u8", + "llvm.x86.aesdec128kl" => "__builtin_ia32_aesdec128kl_u8", + "llvm.x86.aesenc256kl" => "__builtin_ia32_aesenc256kl_u8", + "llvm.x86.aesdec256kl" => "__builtin_ia32_aesdec256kl_u8", + "llvm.x86.aesencwide128kl" => "__builtin_ia32_aesencwide128kl_u8", + "llvm.x86.aesdecwide128kl" => "__builtin_ia32_aesdecwide128kl_u8", + "llvm.x86.aesencwide256kl" => "__builtin_ia32_aesencwide256kl_u8", + "llvm.x86.aesdecwide256kl" => "__builtin_ia32_aesdecwide256kl_u8", // TODO: support the tile builtins: "llvm.x86.ldtilecfg" => "__builtin_trap", diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs index f38622074f18..d22f4229e237 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs @@ -78,6 +78,7 @@ fn get_simple_intrinsic<'gcc, 'tcx>( sym::maxnumf64 => "fmax", sym::copysignf32 => "copysignf", sym::copysignf64 => "copysign", + sym::copysignf128 => "copysignl", sym::floorf32 => "floorf", sym::floorf64 => "floor", sym::ceilf32 => "ceilf", diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs index 8b454ab2a424..6d40d5297f1a 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs @@ -399,7 +399,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( } #[cfg(feature = "master")] - if name == sym::simd_insert { + if name == sym::simd_insert || name == sym::simd_insert_dyn { require!( in_elem == arg_tys[2], InvalidMonomorphization::InsertedType { @@ -410,6 +410,8 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( out_ty: arg_tys[2] } ); + + // TODO(antoyo): For simd_insert, check if the index is a constant of the correct size. let vector = args[0].immediate(); let index = args[1].immediate(); let value = args[2].immediate(); @@ -422,13 +424,15 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( } #[cfg(feature = "master")] - if name == sym::simd_extract { + if name == sym::simd_extract || name == sym::simd_extract_dyn { require!( ret_ty == in_elem, InvalidMonomorphization::ReturnType { span, name, in_elem, in_ty, ret_ty } ); + // TODO(antoyo): For simd_extract, check if the index is a constant of the correct size. let vector = args[0].immediate(); - return Ok(bx.context.new_vector_access(None, vector, args[1].immediate()).to_rvalue()); + let index = args[1].immediate(); + return Ok(bx.context.new_vector_access(None, vector, index).to_rvalue()); } if name == sym::simd_select { diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index bfa23174a19d..624fdb4043c7 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -188,10 +188,10 @@ impl CodegenBackend for GccCodegenBackend { crate::DEFAULT_LOCALE_RESOURCE } - fn init(&self, sess: &Session) { + fn init(&self, _sess: &Session) { #[cfg(feature = "master")] { - let target_cpu = target_cpu(sess); + let target_cpu = target_cpu(_sess); // Get the second TargetInfo with the correct CPU features by setting the arch. let context = Context::default(); diff --git a/compiler/rustc_codegen_gcc/tests/failing-ui-tests.txt b/compiler/rustc_codegen_gcc/tests/failing-ui-tests.txt index 082958bfe1f8..499c1a962311 100644 --- a/compiler/rustc_codegen_gcc/tests/failing-ui-tests.txt +++ b/compiler/rustc_codegen_gcc/tests/failing-ui-tests.txt @@ -1,11 +1,9 @@ tests/ui/allocator/no_std-alloc-error-handler-custom.rs tests/ui/allocator/no_std-alloc-error-handler-default.rs tests/ui/asm/may_unwind.rs -tests/ui/asm/x86_64/multiple-clobber-abi.rs tests/ui/functions-closures/parallel-codegen-closures.rs tests/ui/linkage-attr/linkage1.rs tests/ui/lto/dylib-works.rs -tests/ui/numbers-arithmetic/saturating-float-casts.rs tests/ui/sepcomp/sepcomp-cci.rs tests/ui/sepcomp/sepcomp-extern.rs tests/ui/sepcomp/sepcomp-fns-backwards.rs @@ -33,7 +31,6 @@ tests/ui/unwind-no-uwtable.rs tests/ui/parser/unclosed-delimiter-in-dep.rs tests/ui/consts/missing_span_in_backtrace.rs tests/ui/drop/dynamic-drop.rs -tests/ui/issues/issue-40883.rs tests/ui/issues/issue-43853.rs tests/ui/issues/issue-47364.rs tests/ui/macros/rfc-2011-nicer-assert-messages/assert-without-captures-does-not-create-unnecessary-code.rs @@ -102,14 +99,12 @@ tests/ui/codegen/equal-pointers-unequal/as-cast/basic.rs tests/ui/codegen/equal-pointers-unequal/as-cast/inline1.rs tests/ui/codegen/equal-pointers-unequal/as-cast/print.rs tests/ui/codegen/equal-pointers-unequal/as-cast/inline2.rs -tests/ui/codegen/equal-pointers-unequal/as-cast/print3.rs tests/ui/codegen/equal-pointers-unequal/as-cast/segfault.rs tests/ui/codegen/equal-pointers-unequal/exposed-provenance/function.rs tests/ui/codegen/equal-pointers-unequal/exposed-provenance/basic.rs tests/ui/codegen/equal-pointers-unequal/as-cast/zero.rs tests/ui/codegen/equal-pointers-unequal/exposed-provenance/inline1.rs tests/ui/codegen/equal-pointers-unequal/exposed-provenance/print.rs -tests/ui/codegen/equal-pointers-unequal/exposed-provenance/print3.rs tests/ui/codegen/equal-pointers-unequal/exposed-provenance/inline2.rs tests/ui/codegen/equal-pointers-unequal/exposed-provenance/segfault.rs tests/ui/codegen/equal-pointers-unequal/exposed-provenance/zero.rs @@ -117,8 +112,9 @@ tests/ui/codegen/equal-pointers-unequal/strict-provenance/basic.rs tests/ui/codegen/equal-pointers-unequal/strict-provenance/function.rs tests/ui/codegen/equal-pointers-unequal/strict-provenance/print.rs tests/ui/codegen/equal-pointers-unequal/strict-provenance/inline1.rs -tests/ui/codegen/equal-pointers-unequal/strict-provenance/print3.rs tests/ui/codegen/equal-pointers-unequal/strict-provenance/inline2.rs tests/ui/codegen/equal-pointers-unequal/strict-provenance/segfault.rs tests/ui/codegen/equal-pointers-unequal/strict-provenance/zero.rs tests/ui/simd/simd-bitmask-notpow2.rs +tests/ui/codegen/StackColoring-not-blowup-stack-issue-40883.rs +tests/ui/uninhabited/uninhabited-transparent-return-abi.rs diff --git a/compiler/rustc_codegen_gcc/tests/run/abort1.rs b/compiler/rustc_codegen_gcc/tests/run/abort1.rs index fe46d9ae4184..ff2bb75ece22 100644 --- a/compiler/rustc_codegen_gcc/tests/run/abort1.rs +++ b/compiler/rustc_codegen_gcc/tests/run/abort1.rs @@ -3,45 +3,13 @@ // Run-time: // status: signal -#![feature(auto_traits, lang_items, no_core, intrinsics, rustc_attrs)] -#![allow(internal_features)] - +#![feature(no_core)] #![no_std] #![no_core] #![no_main] -/* - * Core - */ - -// Because we don't have core yet. -#[lang = "sized"] -pub trait Sized {} - -#[lang = "copy"] -trait Copy { -} - -impl Copy for isize {} - -#[lang = "receiver"] -trait Receiver { -} - -#[lang = "freeze"] -pub(crate) unsafe auto trait Freeze {} - -mod intrinsics { - use super::Sized; - - #[rustc_nounwind] - #[rustc_intrinsic] - pub fn abort() -> !; -} - -/* - * Code - */ +extern crate mini_core; +use mini_core::*; fn test_fail() -> ! { unsafe { intrinsics::abort() }; diff --git a/compiler/rustc_codegen_gcc/tests/run/abort2.rs b/compiler/rustc_codegen_gcc/tests/run/abort2.rs index 4123f4f4beeb..781f518e0b22 100644 --- a/compiler/rustc_codegen_gcc/tests/run/abort2.rs +++ b/compiler/rustc_codegen_gcc/tests/run/abort2.rs @@ -3,45 +3,13 @@ // Run-time: // status: signal -#![feature(auto_traits, lang_items, no_core, intrinsics, rustc_attrs)] -#![allow(internal_features)] - +#![feature(no_core)] #![no_std] #![no_core] #![no_main] -/* - * Core - */ - -// Because we don't have core yet. -#[lang = "sized"] -pub trait Sized {} - -#[lang = "copy"] -trait Copy { -} - -impl Copy for isize {} - -#[lang = "receiver"] -trait Receiver { -} - -#[lang = "freeze"] -pub(crate) unsafe auto trait Freeze {} - -mod intrinsics { - use super::Sized; - - #[rustc_nounwind] - #[rustc_intrinsic] - pub fn abort() -> !; -} - -/* - * Code - */ +extern crate mini_core; +use mini_core::*; fn fail() -> i32 { unsafe { intrinsics::abort() }; diff --git a/compiler/rustc_codegen_gcc/tests/run/array.rs b/compiler/rustc_codegen_gcc/tests/run/array.rs index e18a4ced6bc4..3ab0c309fdea 100644 --- a/compiler/rustc_codegen_gcc/tests/run/array.rs +++ b/compiler/rustc_codegen_gcc/tests/run/array.rs @@ -8,20 +8,12 @@ // 10 #![feature(no_core)] - #![no_std] #![no_core] #![no_main] extern crate mini_core; - -mod libc { - #[link(name = "c")] - extern "C" { - pub fn printf(format: *const i8, ...) -> i32; - pub fn puts(s: *const u8) -> i32; - } -} +use mini_core::*; static mut ONE: usize = 1; diff --git a/compiler/rustc_codegen_gcc/tests/run/asm.rs b/compiler/rustc_codegen_gcc/tests/run/asm.rs index 4e05d026868e..2dbf43be664d 100644 --- a/compiler/rustc_codegen_gcc/tests/run/asm.rs +++ b/compiler/rustc_codegen_gcc/tests/run/asm.rs @@ -174,6 +174,59 @@ fn asm() { mem_cpy(array2.as_mut_ptr(), array1.as_ptr(), 3); } assert_eq!(array1, array2); + + // in and clobber registers cannot overlap. This tests that the lateout register without an + // output place (indicated by the `_`) is not added to the list of clobbered registers + let x = 8; + let y: i32; + unsafe { + asm!( + "mov rax, rdi", + in("rdi") x, + lateout("rdi") _, + out("rax") y, + ); + } + assert_eq!((x, y), (8, 8)); + + // sysv64 is the default calling convention on unix systems. The rdi register is + // used to pass arguments in the sysv64 calling convention, so this register will be clobbered + #[cfg(unix)] + { + let x = 16; + let y: i32; + unsafe { + asm!( + "mov rax, rdi", + in("rdi") x, + out("rax") y, + clobber_abi("sysv64"), + ); + } + assert_eq!((x, y), (16, 16)); + } + + // the `b` suffix for registers in the `reg_byte` register class is not supported in GCC + // and needs to be stripped in order to use these registers. + unsafe { + core::arch::asm!( + "", + out("al") _, + out("bl") _, + out("cl") _, + out("dl") _, + out("sil") _, + out("dil") _, + out("r8b") _, + out("r9b") _, + out("r10b") _, + out("r11b") _, + out("r12b") _, + out("r13b") _, + out("r14b") _, + out("r15b") _, + ); + } } #[cfg(not(target_arch = "x86_64"))] diff --git a/compiler/rustc_codegen_gcc/tests/run/assign.rs b/compiler/rustc_codegen_gcc/tests/run/assign.rs index 286155852d50..4535ab5778e9 100644 --- a/compiler/rustc_codegen_gcc/tests/run/assign.rs +++ b/compiler/rustc_codegen_gcc/tests/run/assign.rs @@ -5,130 +5,13 @@ // 7 8 // 10 -#![allow(internal_features, unused_attributes)] -#![feature(auto_traits, lang_items, no_core, intrinsics, rustc_attrs, track_caller)] - +#![feature(no_core)] #![no_std] #![no_core] #![no_main] -/* - * Core - */ - -// Because we don't have core yet. -#[lang = "sized"] -pub trait Sized {} - -#[lang = "copy"] -trait Copy { -} - -impl Copy for isize {} -impl Copy for *mut i32 {} -impl Copy for usize {} -impl Copy for u8 {} -impl Copy for i8 {} -impl Copy for i32 {} - -#[lang = "receiver"] -trait Receiver { -} - -#[lang = "freeze"] -pub(crate) unsafe auto trait Freeze {} - -#[lang = "panic_location"] -struct PanicLocation { - file: &'static str, - line: u32, - column: u32, -} - -mod libc { - #[link(name = "c")] - extern "C" { - pub fn puts(s: *const u8) -> i32; - pub fn fflush(stream: *mut i32) -> i32; - pub fn printf(format: *const i8, ...) -> i32; - - pub static stdout: *mut i32; - } -} - -mod intrinsics { - #[rustc_nounwind] - #[rustc_intrinsic] - pub fn abort() -> !; -} - -#[lang = "panic"] -#[track_caller] -#[no_mangle] -pub fn panic(_msg: &'static str) -> ! { - unsafe { - libc::puts("Panicking\0" as *const str as *const u8); - libc::fflush(libc::stdout); - intrinsics::abort(); - } -} - -#[lang = "add"] -trait Add { - type Output; - - fn add(self, rhs: RHS) -> Self::Output; -} - -impl Add for u8 { - type Output = Self; - - fn add(self, rhs: Self) -> Self { - self + rhs - } -} - -impl Add for i8 { - type Output = Self; - - fn add(self, rhs: Self) -> Self { - self + rhs - } -} - -impl Add for i32 { - type Output = Self; - - fn add(self, rhs: Self) -> Self { - self + rhs - } -} - -impl Add for usize { - type Output = Self; - - fn add(self, rhs: Self) -> Self { - self + rhs - } -} - -impl Add for isize { - type Output = Self; - - fn add(self, rhs: Self) -> Self { - self + rhs - } -} - -#[track_caller] -#[lang = "panic_const_add_overflow"] -pub fn panic_const_add_overflow() -> ! { - panic("attempt to add with overflow"); -} - -/* - * Code - */ +extern crate mini_core; +use mini_core::*; fn inc_ref(num: &mut isize) -> isize { *num = *num + 5; @@ -139,9 +22,8 @@ fn inc(num: isize) -> isize { num + 1 } - #[no_mangle] -extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 { +extern "C" fn main(mut argc: isize, _argv: *const *const u8) -> i32 { argc = inc(argc); unsafe { libc::printf(b"%ld\n\0" as *const u8 as *const i8, argc); diff --git a/compiler/rustc_codegen_gcc/tests/run/closure.rs b/compiler/rustc_codegen_gcc/tests/run/closure.rs index c7a236f74f9e..a8a3fadfed47 100644 --- a/compiler/rustc_codegen_gcc/tests/run/closure.rs +++ b/compiler/rustc_codegen_gcc/tests/run/closure.rs @@ -9,55 +9,38 @@ // Both args: 11 #![feature(no_core)] - #![no_std] #![no_core] #![no_main] extern crate mini_core; - -mod libc { - #[link(name = "c")] - extern "C" { - pub fn printf(format: *const i8, ...) -> i32; - } -} +use mini_core::*; #[no_mangle] -extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 { +extern "C" fn main(argc: isize, _argv: *const *const u8) -> i32 { let string = "Arg: %d\n\0"; - let mut closure = || { - unsafe { - libc::printf(string as *const str as *const i8, argc); - } + let mut closure = || unsafe { + libc::printf(string as *const str as *const i8, argc); }; closure(); - let mut closure = || { - unsafe { - libc::printf("Argument: %d\n\0" as *const str as *const i8, argc); - } + let mut closure = || unsafe { + libc::printf("Argument: %d\n\0" as *const str as *const i8, argc); }; closure(); - let mut closure = |string| { - unsafe { - libc::printf(string as *const str as *const i8, argc); - } + let mut closure = |string| unsafe { + libc::printf(string as *const str as *const i8, argc); }; closure("String arg: %d\n\0"); - let mut closure = |arg: isize| { - unsafe { - libc::printf("Int argument: %d\n\0" as *const str as *const i8, arg); - } + let mut closure = |arg: isize| unsafe { + libc::printf("Int argument: %d\n\0" as *const str as *const i8, arg); }; closure(argc + 1); - let mut closure = |string, arg: isize| { - unsafe { - libc::printf(string as *const str as *const i8, arg); - } + let mut closure = |string, arg: isize| unsafe { + libc::printf(string as *const str as *const i8, arg); }; closure("Both args: %d\n\0", argc + 10); diff --git a/compiler/rustc_codegen_gcc/tests/run/condition.rs b/compiler/rustc_codegen_gcc/tests/run/condition.rs index b02359702ed2..bd3b6f7497fb 100644 --- a/compiler/rustc_codegen_gcc/tests/run/condition.rs +++ b/compiler/rustc_codegen_gcc/tests/run/condition.rs @@ -6,19 +6,12 @@ // 1 #![feature(no_core)] - #![no_std] #![no_core] #![no_main] extern crate mini_core; - -mod libc { - #[link(name = "c")] - extern "C" { - pub fn printf(format: *const i8, ...) -> i32; - } -} +use mini_core::*; #[no_mangle] extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 { @@ -27,15 +20,14 @@ extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 { libc::printf(b"true\n\0" as *const u8 as *const i8); } - let string = - match argc { - 1 => b"1\n\0", - 2 => b"2\n\0", - 3 => b"3\n\0", - 4 => b"4\n\0", - 5 => b"5\n\0", - _ => b"_\n\0", - }; + let string = match argc { + 1 => b"1\n\0", + 2 => b"2\n\0", + 3 => b"3\n\0", + 4 => b"4\n\0", + 5 => b"5\n\0", + _ => b"_\n\0", + }; libc::printf(string as *const u8 as *const i8); } 0 diff --git a/compiler/rustc_codegen_gcc/tests/run/empty_main.rs b/compiler/rustc_codegen_gcc/tests/run/empty_main.rs index 042e44080c53..fe3df5a2389c 100644 --- a/compiler/rustc_codegen_gcc/tests/run/empty_main.rs +++ b/compiler/rustc_codegen_gcc/tests/run/empty_main.rs @@ -3,37 +3,13 @@ // Run-time: // status: 0 -#![feature(auto_traits, lang_items, no_core)] -#![allow(internal_features)] - +#![feature(no_core)] #![no_std] #![no_core] #![no_main] -/* - * Core - */ - -// Because we don't have core yet. -#[lang = "sized"] -pub trait Sized {} - -#[lang = "copy"] -trait Copy { -} - -impl Copy for isize {} - -#[lang = "receiver"] -trait Receiver { -} - -#[lang = "freeze"] -pub(crate) unsafe auto trait Freeze {} - -/* - * Code - */ +extern crate mini_core; +use mini_core::*; #[no_mangle] extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 { diff --git a/compiler/rustc_codegen_gcc/tests/run/exit.rs b/compiler/rustc_codegen_gcc/tests/run/exit.rs index 9a7c91c0adb2..e0a59174bd38 100644 --- a/compiler/rustc_codegen_gcc/tests/run/exit.rs +++ b/compiler/rustc_codegen_gcc/tests/run/exit.rs @@ -3,44 +3,13 @@ // Run-time: // status: 2 -#![feature(auto_traits, lang_items, no_core, intrinsics)] -#![allow(internal_features)] - +#![feature(no_core)] #![no_std] #![no_core] #![no_main] -mod libc { - #[link(name = "c")] - extern "C" { - pub fn exit(status: i32); - } -} - -/* - * Core - */ - -// Because we don't have core yet. -#[lang = "sized"] -pub trait Sized {} - -#[lang = "copy"] -trait Copy { -} - -impl Copy for isize {} - -#[lang = "receiver"] -trait Receiver { -} - -#[lang = "freeze"] -pub(crate) unsafe auto trait Freeze {} - -/* - * Code - */ +extern crate mini_core; +use mini_core::*; #[no_mangle] extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 { diff --git a/compiler/rustc_codegen_gcc/tests/run/exit_code.rs b/compiler/rustc_codegen_gcc/tests/run/exit_code.rs index c50d2b0d7107..376824da845c 100644 --- a/compiler/rustc_codegen_gcc/tests/run/exit_code.rs +++ b/compiler/rustc_codegen_gcc/tests/run/exit_code.rs @@ -3,37 +3,13 @@ // Run-time: // status: 1 -#![feature(auto_traits, lang_items, no_core)] -#![allow(internal_features)] - +#![feature(no_core)] #![no_std] #![no_core] #![no_main] -/* - * Core - */ - -// Because we don't have core yet. -#[lang = "sized"] -pub trait Sized {} - -#[lang = "copy"] -trait Copy { -} - -impl Copy for isize {} - -#[lang = "receiver"] -trait Receiver { -} - -#[lang = "freeze"] -pub(crate) unsafe auto trait Freeze {} - -/* - * Code - */ +extern crate mini_core; +use mini_core::*; #[no_mangle] extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 { diff --git a/compiler/rustc_codegen_gcc/tests/run/float.rs b/compiler/rustc_codegen_gcc/tests/run/float.rs new file mode 100644 index 000000000000..424fa1cf4ad5 --- /dev/null +++ b/compiler/rustc_codegen_gcc/tests/run/float.rs @@ -0,0 +1,28 @@ +// Compiler: +// +// Run-time: +// status: 0 + +#![feature(const_black_box)] + +fn main() { + use std::hint::black_box; + + macro_rules! check { + ($ty:ty, $expr:expr) => {{ + const EXPECTED: $ty = $expr; + assert_eq!($expr, EXPECTED); + }}; + } + + check!(i32, (black_box(0.0f32) as i32)); + + check!(u64, (black_box(f32::NAN) as u64)); + check!(u128, (black_box(f32::NAN) as u128)); + + check!(i64, (black_box(f64::NAN) as i64)); + check!(u64, (black_box(f64::NAN) as u64)); + + check!(i16, (black_box(f32::MIN) as i16)); + check!(i16, (black_box(f32::MAX) as i16)); +} diff --git a/compiler/rustc_codegen_gcc/tests/run/fun_ptr.rs b/compiler/rustc_codegen_gcc/tests/run/fun_ptr.rs index 98b351e50449..93b9baee1b24 100644 --- a/compiler/rustc_codegen_gcc/tests/run/fun_ptr.rs +++ b/compiler/rustc_codegen_gcc/tests/run/fun_ptr.rs @@ -5,19 +5,12 @@ // stdout: 1 #![feature(no_core)] - #![no_std] #![no_core] #![no_main] extern crate mini_core; - -mod libc { - #[link(name = "c")] - extern "C" { - pub fn printf(format: *const i8, ...) -> i32; - } -} +use mini_core::*; fn i16_as_i8(a: i16) -> i8 { a as i8 diff --git a/compiler/rustc_codegen_gcc/tests/run/int.rs b/compiler/rustc_codegen_gcc/tests/run/int.rs index 58a26801b678..47b5dea46f8d 100644 --- a/compiler/rustc_codegen_gcc/tests/run/int.rs +++ b/compiler/rustc_codegen_gcc/tests/run/int.rs @@ -3,9 +3,7 @@ // Run-time: // status: 0 -/* - * Code - */ +#![feature(const_black_box)] fn main() { use std::hint::black_box; diff --git a/compiler/rustc_codegen_gcc/tests/run/mut_ref.rs b/compiler/rustc_codegen_gcc/tests/run/mut_ref.rs index b0215860406e..fa50d5bc5d3d 100644 --- a/compiler/rustc_codegen_gcc/tests/run/mut_ref.rs +++ b/compiler/rustc_codegen_gcc/tests/run/mut_ref.rs @@ -1,4 +1,3 @@ - // Compiler: // // Run-time: @@ -7,139 +6,20 @@ // 6 // 11 -#![allow(internal_features, unused_attributes)] -#![feature(auto_traits, lang_items, no_core, intrinsics, rustc_attrs, track_caller)] - +#![feature(no_core)] #![no_std] #![no_core] #![no_main] -/* - * Core - */ - -// Because we don't have core yet. -#[lang = "sized"] -pub trait Sized {} - -#[lang = "copy"] -trait Copy { -} - -impl Copy for isize {} -impl Copy for *mut i32 {} -impl Copy for usize {} -impl Copy for u8 {} -impl Copy for i8 {} -impl Copy for i32 {} - -#[lang = "receiver"] -trait Receiver { -} - -#[lang = "freeze"] -pub(crate) unsafe auto trait Freeze {} - -#[lang = "panic_location"] -struct PanicLocation { - file: &'static str, - line: u32, - column: u32, -} - -mod libc { - #[link(name = "c")] - extern "C" { - pub fn puts(s: *const u8) -> i32; - pub fn fflush(stream: *mut i32) -> i32; - pub fn printf(format: *const i8, ...) -> i32; - - pub static stdout: *mut i32; - } -} - -mod intrinsics { - #[rustc_nounwind] - #[rustc_intrinsic] - pub fn abort() -> !; -} - -#[lang = "panic"] -#[track_caller] -#[no_mangle] -pub fn panic(_msg: &'static str) -> ! { - unsafe { - libc::puts("Panicking\0" as *const str as *const u8); - libc::fflush(libc::stdout); - intrinsics::abort(); - } -} - -#[lang = "add"] -trait Add { - type Output; - - fn add(self, rhs: RHS) -> Self::Output; -} - -impl Add for u8 { - type Output = Self; - - fn add(self, rhs: Self) -> Self { - self + rhs - } -} - -impl Add for i8 { - type Output = Self; - - fn add(self, rhs: Self) -> Self { - self + rhs - } -} - -impl Add for i32 { - type Output = Self; - - fn add(self, rhs: Self) -> Self { - self + rhs - } -} - -impl Add for usize { - type Output = Self; - - fn add(self, rhs: Self) -> Self { - self + rhs - } -} - -impl Add for isize { - type Output = Self; - - fn add(self, rhs: Self) -> Self { - self + rhs - } -} - -#[track_caller] -#[lang = "panic_const_add_overflow"] -pub fn panic_const_add_overflow() -> ! { - panic("attempt to add with overflow"); -} - -/* - * Code - */ +extern crate mini_core; +use mini_core::*; struct Test { field: isize, } fn test(num: isize) -> Test { - Test { - field: num + 1, - } + Test { field: num + 1 } } fn update_num(num: &mut isize) { @@ -147,7 +27,7 @@ fn update_num(num: &mut isize) { } #[no_mangle] -extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 { +extern "C" fn main(mut argc: isize, _argv: *const *const u8) -> i32 { let mut test = test(argc); unsafe { libc::printf(b"%ld\n\0" as *const u8 as *const i8, test.field); diff --git a/compiler/rustc_codegen_gcc/tests/run/operations.rs b/compiler/rustc_codegen_gcc/tests/run/operations.rs index 8ba7a4c5ed8c..a1b0772f76b6 100644 --- a/compiler/rustc_codegen_gcc/tests/run/operations.rs +++ b/compiler/rustc_codegen_gcc/tests/run/operations.rs @@ -5,229 +5,13 @@ // 39 // 10 -#![allow(internal_features, unused_attributes)] -#![feature(auto_traits, lang_items, no_core, intrinsics, arbitrary_self_types, rustc_attrs)] - +#![feature(no_core)] #![no_std] #![no_core] #![no_main] -/* - * Core - */ - -// Because we don't have core yet. -#[lang = "sized"] -pub trait Sized {} - -#[lang = "copy"] -trait Copy { -} - -impl Copy for isize {} -impl Copy for *mut i32 {} -impl Copy for usize {} -impl Copy for u8 {} -impl Copy for i8 {} -impl Copy for i16 {} -impl Copy for i32 {} - -#[lang = "deref"] -pub trait Deref { - type Target: ?Sized; - - fn deref(&self) -> &Self::Target; -} - -#[lang = "legacy_receiver"] -trait LegacyReceiver { -} - -#[lang = "freeze"] -pub(crate) unsafe auto trait Freeze {} - -#[lang = "panic_location"] -struct PanicLocation { - file: &'static str, - line: u32, - column: u32, -} - -mod libc { - #[link(name = "c")] - extern "C" { - pub fn printf(format: *const i8, ...) -> i32; - pub fn puts(s: *const u8) -> i32; - pub fn fflush(stream: *mut i32) -> i32; - - pub static stdout: *mut i32; - } -} - -mod intrinsics { - #[rustc_nounwind] - #[rustc_intrinsic] - pub fn abort() -> !; -} - -#[lang = "panic"] -#[track_caller] -#[no_mangle] -pub fn panic(_msg: &'static str) -> ! { - unsafe { - libc::puts("Panicking\0" as *const str as *const u8); - libc::fflush(libc::stdout); - intrinsics::abort(); - } -} - -#[lang = "add"] -trait Add { - type Output; - - fn add(self, rhs: RHS) -> Self::Output; -} - -impl Add for u8 { - type Output = Self; - - fn add(self, rhs: Self) -> Self { - self + rhs - } -} - -impl Add for i8 { - type Output = Self; - - fn add(self, rhs: Self) -> Self { - self + rhs - } -} - -impl Add for i32 { - type Output = Self; - - fn add(self, rhs: Self) -> Self { - self + rhs - } -} - -impl Add for usize { - type Output = Self; - - fn add(self, rhs: Self) -> Self { - self + rhs - } -} - -impl Add for isize { - type Output = Self; - - fn add(self, rhs: Self) -> Self { - self + rhs - } -} - -#[lang = "sub"] -pub trait Sub { - type Output; - - fn sub(self, rhs: RHS) -> Self::Output; -} - -impl Sub for usize { - type Output = Self; - - fn sub(self, rhs: Self) -> Self { - self - rhs - } -} - -impl Sub for isize { - type Output = Self; - - fn sub(self, rhs: Self) -> Self { - self - rhs - } -} - -impl Sub for u8 { - type Output = Self; - - fn sub(self, rhs: Self) -> Self { - self - rhs - } -} - -impl Sub for i8 { - type Output = Self; - - fn sub(self, rhs: Self) -> Self { - self - rhs - } -} - -impl Sub for i16 { - type Output = Self; - - fn sub(self, rhs: Self) -> Self { - self - rhs - } -} - -#[lang = "mul"] -pub trait Mul { - type Output; - - #[must_use] - fn mul(self, rhs: RHS) -> Self::Output; -} - -impl Mul for u8 { - type Output = Self; - - fn mul(self, rhs: Self) -> Self::Output { - self * rhs - } -} - -impl Mul for usize { - type Output = Self; - - fn mul(self, rhs: Self) -> Self::Output { - self * rhs - } -} - -impl Mul for isize { - type Output = Self; - - fn mul(self, rhs: Self) -> Self::Output { - self * rhs - } -} - -#[track_caller] -#[lang = "panic_const_add_overflow"] -pub fn panic_const_add_overflow() -> ! { - panic("attempt to add with overflow"); -} - -#[track_caller] -#[lang = "panic_const_sub_overflow"] -pub fn panic_const_sub_overflow() -> ! { - panic("attempt to subtract with overflow"); -} - -#[track_caller] -#[lang = "panic_const_mul_overflow"] -pub fn panic_const_mul_overflow() -> ! { - panic("attempt to multiply with overflow"); -} - -/* - * Code - */ +extern crate mini_core; +use mini_core::*; #[no_mangle] extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 { diff --git a/compiler/rustc_codegen_gcc/tests/run/ptr_cast.rs b/compiler/rustc_codegen_gcc/tests/run/ptr_cast.rs index 0ba49e7187fc..c1254c51ce91 100644 --- a/compiler/rustc_codegen_gcc/tests/run/ptr_cast.rs +++ b/compiler/rustc_codegen_gcc/tests/run/ptr_cast.rs @@ -2,35 +2,32 @@ // // Run-time: // status: 0 -// stdout: 1 +// stdout: 10 +// 10 +// 42 #![feature(no_core)] - #![no_std] #![no_core] #![no_main] extern crate mini_core; +use mini_core::*; -mod libc { - #[link(name = "c")] - extern "C" { - pub fn printf(format: *const i8, ...) -> i32; - } -} - -static mut ONE: usize = 1; - -fn make_array() -> [u8; 3] { - [42, 10, 5] +fn int_cast(a: u16, b: i16) -> (u8, u16, u32, usize, i8, i16, i32, isize, u8, u32) { + ( + a as u8, a as u16, a as u32, a as usize, a as i8, a as i16, a as i32, a as isize, b as u8, + b as u32, + ) } #[no_mangle] extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 { + let (a, b, c, d, e, f, g, h, i, j) = int_cast(10, 42); unsafe { - let ptr = ONE as *mut usize; - let value = ptr as usize; - libc::printf(b"%ld\n\0" as *const u8 as *const i8, value); + libc::printf(b"%d\n\0" as *const u8 as *const i8, c); + libc::printf(b"%ld\n\0" as *const u8 as *const i8, d); + libc::printf(b"%ld\n\0" as *const u8 as *const i8, j); } 0 } diff --git a/compiler/rustc_codegen_gcc/tests/run/return-tuple.rs b/compiler/rustc_codegen_gcc/tests/run/return-tuple.rs index 3cc1e274001e..c1254c51ce91 100644 --- a/compiler/rustc_codegen_gcc/tests/run/return-tuple.rs +++ b/compiler/rustc_codegen_gcc/tests/run/return-tuple.rs @@ -6,54 +6,13 @@ // 10 // 42 -#![feature(auto_traits, lang_items, no_core, intrinsics)] -#![allow(internal_features)] - +#![feature(no_core)] #![no_std] #![no_core] #![no_main] -#[lang = "copy"] -pub unsafe trait Copy {} - -impl Copy for bool {} -impl Copy for u8 {} -impl Copy for u16 {} -impl Copy for u32 {} -impl Copy for u64 {} -impl Copy for usize {} -impl Copy for i8 {} -impl Copy for i16 {} -impl Copy for i32 {} -impl Copy for isize {} -impl Copy for f32 {} -impl Copy for char {} - -mod libc { - #[link(name = "c")] - extern "C" { - pub fn printf(format: *const i8, ...) -> i32; - } -} - -/* - * Core - */ - -// Because we don't have core yet. -#[lang = "sized"] -pub trait Sized {} - -#[lang = "legacy_receiver"] -trait LegacyReceiver { -} - -#[lang = "freeze"] -pub(crate) unsafe auto trait Freeze {} - -/* - * Code - */ +extern crate mini_core; +use mini_core::*; fn int_cast(a: u16, b: i16) -> (u8, u16, u32, usize, i8, i16, i32, isize, u8, u32) { ( diff --git a/compiler/rustc_codegen_gcc/tests/run/slice.rs b/compiler/rustc_codegen_gcc/tests/run/slice.rs index 825fcb8a081e..449ccabef7fe 100644 --- a/compiler/rustc_codegen_gcc/tests/run/slice.rs +++ b/compiler/rustc_codegen_gcc/tests/run/slice.rs @@ -5,26 +5,17 @@ // stdout: 5 #![feature(no_core)] - #![no_std] #![no_core] #![no_main] extern crate mini_core; - -mod libc { - #[link(name = "c")] - extern "C" { - pub fn printf(format: *const i8, ...) -> i32; - } -} +use mini_core::*; static mut TWO: usize = 2; fn index_slice(s: &[u32]) -> u32 { - unsafe { - s[TWO] - } + unsafe { s[TWO] } } #[no_mangle] diff --git a/compiler/rustc_codegen_gcc/tests/run/static.rs b/compiler/rustc_codegen_gcc/tests/run/static.rs index c3c8121b1e19..1e36cf4f3d31 100644 --- a/compiler/rustc_codegen_gcc/tests/run/static.rs +++ b/compiler/rustc_codegen_gcc/tests/run/static.rs @@ -9,70 +9,13 @@ // 12 // 1 -#![feature(auto_traits, lang_items, no_core, intrinsics, rustc_attrs)] -#![allow(internal_features)] - +#![feature(no_core)] #![no_std] #![no_core] #![no_main] -/* - * Core - */ - -// Because we don't have core yet. -#[lang = "sized"] -pub trait Sized {} - -#[lang = "destruct"] -pub trait Destruct {} - -#[lang = "drop"] -pub trait Drop {} - -#[lang = "copy"] -trait Copy { -} - -impl Copy for isize {} -impl Copy for *mut T {} - -#[lang = "receiver"] -trait Receiver { -} - -#[lang = "freeze"] -pub(crate) unsafe auto trait Freeze {} - -mod intrinsics { - use super::Sized; - - #[rustc_nounwind] - #[rustc_intrinsic] - pub fn abort() -> !; -} - -mod libc { - #[link(name = "c")] - extern "C" { - pub fn printf(format: *const i8, ...) -> i32; - } -} - -#[lang = "structural_peq"] -pub trait StructuralPartialEq {} - -#[lang = "drop_in_place"] -#[allow(unconditional_recursion)] -pub unsafe fn drop_in_place(to_drop: *mut T) { - // Code here does not matter - this is replaced by the - // real drop glue by the compiler. - drop_in_place(to_drop); -} - -/* - * Code - */ +extern crate mini_core; +use mini_core::*; struct Test { field: isize, @@ -84,20 +27,14 @@ struct WithRef { static mut CONSTANT: isize = 10; -static mut TEST: Test = Test { - field: 12, -}; +static mut TEST: Test = Test { field: 12 }; -static mut TEST2: Test = Test { - field: 14, -}; +static mut TEST2: Test = Test { field: 14 }; -static mut WITH_REF: WithRef = WithRef { - refe: unsafe { &TEST }, -}; +static mut WITH_REF: WithRef = WithRef { refe: unsafe { &TEST } }; #[no_mangle] -extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 { +extern "C" fn main(argc: isize, _argv: *const *const u8) -> i32 { unsafe { libc::printf(b"%ld\n\0" as *const u8 as *const i8, CONSTANT); libc::printf(b"%ld\n\0" as *const u8 as *const i8, TEST2.field); diff --git a/compiler/rustc_codegen_gcc/tests/run/structs.rs b/compiler/rustc_codegen_gcc/tests/run/structs.rs index 59b8f358863f..da73cbed9ae9 100644 --- a/compiler/rustc_codegen_gcc/tests/run/structs.rs +++ b/compiler/rustc_codegen_gcc/tests/run/structs.rs @@ -5,44 +5,13 @@ // stdout: 1 // 2 -#![feature(auto_traits, lang_items, no_core, intrinsics)] -#![allow(internal_features)] - +#![feature(no_core)] #![no_std] #![no_core] #![no_main] -/* - * Core - */ - -// Because we don't have core yet. -#[lang = "sized"] -pub trait Sized {} - -#[lang = "copy"] -trait Copy { -} - -impl Copy for isize {} - -#[lang = "receiver"] -trait Receiver { -} - -#[lang = "freeze"] -pub(crate) unsafe auto trait Freeze {} - -mod libc { - #[link(name = "c")] - extern "C" { - pub fn printf(format: *const i8, ...) -> i32; - } -} - -/* - * Code - */ +extern crate mini_core; +use mini_core::*; struct Test { field: isize, diff --git a/compiler/rustc_codegen_gcc/tests/run/tuple.rs b/compiler/rustc_codegen_gcc/tests/run/tuple.rs index ed60a56a68c4..e0f2e95f6289 100644 --- a/compiler/rustc_codegen_gcc/tests/run/tuple.rs +++ b/compiler/rustc_codegen_gcc/tests/run/tuple.rs @@ -4,44 +4,13 @@ // status: 0 // stdout: 3 -#![feature(auto_traits, lang_items, no_core, intrinsics)] -#![allow(internal_features)] - +#![feature(no_core)] #![no_std] #![no_core] #![no_main] -/* - * Core - */ - -// Because we don't have core yet. -#[lang = "sized"] -pub trait Sized {} - -#[lang = "copy"] -trait Copy { -} - -impl Copy for isize {} - -#[lang = "receiver"] -trait Receiver { -} - -#[lang = "freeze"] -pub(crate) unsafe auto trait Freeze {} - -mod libc { - #[link(name = "c")] - extern "C" { - pub fn printf(format: *const i8, ...) -> i32; - } -} - -/* - * Code - */ +extern crate mini_core; +use mini_core::*; #[no_mangle] extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 { diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index bf6138142b64..18d221d232e8 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -119,14 +119,18 @@ pub(crate) fn create_target_machine(tcx: TyCtxt<'_>, mod_name: &str) -> OwnedTar tcx.output_filenames(()).split_dwarf_path( tcx.sess.split_debuginfo(), tcx.sess.opts.unstable_opts.split_dwarf_kind, - Some(mod_name), + mod_name, + tcx.sess.invocation_temp.as_deref(), ) } else { None }; - let output_obj_file = - Some(tcx.output_filenames(()).temp_path(OutputType::Object, Some(mod_name))); + let output_obj_file = Some(tcx.output_filenames(()).temp_path_for_cgu( + OutputType::Object, + mod_name, + tcx.sess.invocation_temp.as_deref(), + )); let config = TargetMachineFactoryConfig { split_dwarf_file, output_obj_file }; target_machine_factory( @@ -330,8 +334,11 @@ pub(crate) fn save_temp_bitcode( return; } let ext = format!("{name}.bc"); - let cgu = Some(&module.name[..]); - let path = cgcx.output_filenames.temp_path_ext(&ext, cgu); + let path = cgcx.output_filenames.temp_path_ext_for_cgu( + &ext, + &module.name, + cgcx.invocation_temp.as_deref(), + ); write_bitcode_to_file(module, &path) } @@ -439,12 +446,9 @@ fn report_inline_asm( let span = if cookie == 0 || matches!(cgcx.lto, Lto::Fat | Lto::Thin) { SpanData::default() } else { - let lo = BytePos::from_u32(cookie as u32); - let hi = BytePos::from_u32((cookie >> 32) as u32); SpanData { - lo, - // LLVM version < 19 silently truncates the cookie to 32 bits in some situations. - hi: if hi.to_u32() != 0 { hi } else { lo }, + lo: BytePos::from_u32(cookie as u32), + hi: BytePos::from_u32((cookie >> 32) as u32), ctxt: SyntaxContext::root(), parent: None, } @@ -697,11 +701,12 @@ pub(crate) unsafe fn optimize( let llcx = &*module.module_llvm.llcx; let _handlers = DiagnosticHandlers::new(cgcx, dcx, llcx, module, CodegenDiagnosticsStage::Opt); - let module_name = module.name.clone(); - let module_name = Some(&module_name[..]); - if config.emit_no_opt_bc { - let out = cgcx.output_filenames.temp_path_ext("no-opt.bc", module_name); + let out = cgcx.output_filenames.temp_path_ext_for_cgu( + "no-opt.bc", + &module.name, + cgcx.invocation_temp.as_deref(), + ); write_bitcode_to_file(module, &out) } @@ -746,8 +751,11 @@ pub(crate) unsafe fn optimize( if let Some(thin_lto_buffer) = thin_lto_buffer { let thin_lto_buffer = unsafe { ThinBuffer::from_raw_ptr(thin_lto_buffer) }; module.thin_lto_buffer = Some(thin_lto_buffer.data().to_vec()); - let bc_summary_out = - cgcx.output_filenames.temp_path(OutputType::ThinLinkBitcode, module_name); + let bc_summary_out = cgcx.output_filenames.temp_path_for_cgu( + OutputType::ThinLinkBitcode, + &module.name, + cgcx.invocation_temp.as_deref(), + ); if config.emit_thin_lto_summary && let Some(thin_link_bitcode_filename) = bc_summary_out.file_name() { @@ -804,8 +812,6 @@ pub(crate) unsafe fn codegen( let llmod = module.module_llvm.llmod(); let llcx = &*module.module_llvm.llcx; let tm = &*module.module_llvm.tm; - let module_name = module.name.clone(); - let module_name = Some(&module_name[..]); let _handlers = DiagnosticHandlers::new(cgcx, dcx, llcx, &module, CodegenDiagnosticsStage::Codegen); @@ -817,8 +823,16 @@ pub(crate) unsafe fn codegen( // copy it to the .o file, and delete the bitcode if it wasn't // otherwise requested. - let bc_out = cgcx.output_filenames.temp_path(OutputType::Bitcode, module_name); - let obj_out = cgcx.output_filenames.temp_path(OutputType::Object, module_name); + let bc_out = cgcx.output_filenames.temp_path_for_cgu( + OutputType::Bitcode, + &module.name, + cgcx.invocation_temp.as_deref(), + ); + let obj_out = cgcx.output_filenames.temp_path_for_cgu( + OutputType::Object, + &module.name, + cgcx.invocation_temp.as_deref(), + ); if config.bitcode_needed() { if config.emit_bc || config.emit_obj == EmitObj::Bitcode { @@ -860,7 +874,11 @@ pub(crate) unsafe fn codegen( if config.emit_ir { let _timer = cgcx.prof.generic_activity_with_arg("LLVM_module_codegen_emit_ir", &*module.name); - let out = cgcx.output_filenames.temp_path(OutputType::LlvmAssembly, module_name); + let out = cgcx.output_filenames.temp_path_for_cgu( + OutputType::LlvmAssembly, + &module.name, + cgcx.invocation_temp.as_deref(), + ); let out_c = path_to_c_string(&out); extern "C" fn demangle_callback( @@ -902,7 +920,11 @@ pub(crate) unsafe fn codegen( if config.emit_asm { let _timer = cgcx.prof.generic_activity_with_arg("LLVM_module_codegen_emit_asm", &*module.name); - let path = cgcx.output_filenames.temp_path(OutputType::Assembly, module_name); + let path = cgcx.output_filenames.temp_path_for_cgu( + OutputType::Assembly, + &module.name, + cgcx.invocation_temp.as_deref(), + ); // We can't use the same module for asm and object code output, // because that triggers various errors like invalid IR or broken @@ -932,7 +954,9 @@ pub(crate) unsafe fn codegen( .prof .generic_activity_with_arg("LLVM_module_codegen_emit_obj", &*module.name); - let dwo_out = cgcx.output_filenames.temp_path_dwo(module_name); + let dwo_out = cgcx + .output_filenames + .temp_path_dwo_for_cgu(&module.name, cgcx.invocation_temp.as_deref()); let dwo_out = match (cgcx.split_debuginfo, cgcx.split_dwarf_kind) { // Don't change how DWARF is emitted when disabled. (SplitDebuginfo::Off, _) => None, @@ -997,6 +1021,7 @@ pub(crate) unsafe fn codegen( config.emit_asm, config.emit_ir, &cgcx.output_filenames, + cgcx.invocation_temp.as_deref(), )) } diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 35134e9f5a05..27f7f95f100e 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -123,7 +123,7 @@ impl<'a, 'll, CX: Borrow>> GenericBuilder<'a, 'll, CX> { /// Empty string, to be used where LLVM expects an instruction name, indicating /// that the instruction is to be left unnamed (i.e. numbered, in textual IR). // FIXME(eddyb) pass `&CStr` directly to FFI once it's a thin pointer. -const UNNAMED: *const c_char = c"".as_ptr(); +pub(crate) const UNNAMED: *const c_char = c"".as_ptr(); impl<'ll, CX: Borrow>> BackendTypes for GenericBuilder<'_, 'll, CX> { type Value = as BackendTypes>::Value; diff --git a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs index 7d264ba4d00c..e7c071d05aa8 100644 --- a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs +++ b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs @@ -10,7 +10,7 @@ use rustc_middle::bug; use tracing::{debug, trace}; use crate::back::write::llvm_err; -use crate::builder::SBuilder; +use crate::builder::{SBuilder, UNNAMED}; use crate::context::SimpleCx; use crate::declare::declare_simple_fn; use crate::errors::{AutoDiffWithoutEnable, LlvmError}; @@ -51,6 +51,7 @@ fn has_sret(fnc: &Value) -> bool { // using iterators and peek()? fn match_args_from_caller_to_enzyme<'ll>( cx: &SimpleCx<'ll>, + builder: &SBuilder<'ll, 'll>, width: u32, args: &mut Vec<&'ll llvm::Value>, inputs: &[DiffActivity], @@ -78,7 +79,9 @@ fn match_args_from_caller_to_enzyme<'ll>( let enzyme_const = cx.create_metadata("enzyme_const".to_string()).unwrap(); let enzyme_out = cx.create_metadata("enzyme_out".to_string()).unwrap(); let enzyme_dup = cx.create_metadata("enzyme_dup".to_string()).unwrap(); + let enzyme_dupv = cx.create_metadata("enzyme_dupv".to_string()).unwrap(); let enzyme_dupnoneed = cx.create_metadata("enzyme_dupnoneed".to_string()).unwrap(); + let enzyme_dupnoneedv = cx.create_metadata("enzyme_dupnoneedv".to_string()).unwrap(); while activity_pos < inputs.len() { let diff_activity = inputs[activity_pos as usize]; @@ -90,13 +93,34 @@ fn match_args_from_caller_to_enzyme<'ll>( DiffActivity::Active => (enzyme_out, false), DiffActivity::ActiveOnly => (enzyme_out, false), DiffActivity::Dual => (enzyme_dup, true), + DiffActivity::Dualv => (enzyme_dupv, true), DiffActivity::DualOnly => (enzyme_dupnoneed, true), + DiffActivity::DualvOnly => (enzyme_dupnoneedv, true), DiffActivity::Duplicated => (enzyme_dup, true), DiffActivity::DuplicatedOnly => (enzyme_dupnoneed, true), - DiffActivity::FakeActivitySize => (enzyme_const, false), + DiffActivity::FakeActivitySize(_) => (enzyme_const, false), }; let outer_arg = outer_args[outer_pos]; args.push(cx.get_metadata_value(activity)); + if matches!(diff_activity, DiffActivity::Dualv) { + let next_outer_arg = outer_args[outer_pos + 1]; + let elem_bytes_size: u64 = match inputs[activity_pos + 1] { + DiffActivity::FakeActivitySize(Some(s)) => s.into(), + _ => bug!("incorrect Dualv handling recognized."), + }; + // stride: sizeof(T) * n_elems. + // n_elems is the next integer. + // Now we multiply `4 * next_outer_arg` to get the stride. + let mul = unsafe { + llvm::LLVMBuildMul( + builder.llbuilder, + cx.get_const_i64(elem_bytes_size), + next_outer_arg, + UNNAMED, + ) + }; + args.push(mul); + } args.push(outer_arg); if duplicated { // We know that duplicated args by construction have a following argument, @@ -114,7 +138,7 @@ fn match_args_from_caller_to_enzyme<'ll>( } else { let next_activity = inputs[activity_pos + 1]; // We analyze the MIR types and add this dummy activity if we visit a slice. - next_activity == DiffActivity::FakeActivitySize + matches!(next_activity, DiffActivity::FakeActivitySize(_)) } }; if slice { @@ -125,7 +149,10 @@ fn match_args_from_caller_to_enzyme<'ll>( // int2 >= int1, which means the shadow vector is large enough to store the gradient. assert_eq!(cx.type_kind(next_outer_ty), TypeKind::Integer); - for i in 0..(width as usize) { + let iterations = + if matches!(diff_activity, DiffActivity::Dualv) { 1 } else { width as usize }; + + for i in 0..iterations { let next_outer_arg2 = outer_args[outer_pos + 2 * (i + 1)]; let next_outer_ty2 = cx.val_ty(next_outer_arg2); assert_eq!(cx.type_kind(next_outer_ty2), TypeKind::Pointer); @@ -136,7 +163,7 @@ fn match_args_from_caller_to_enzyme<'ll>( } args.push(cx.get_metadata_value(enzyme_const)); args.push(next_outer_arg); - outer_pos += 2 + 2 * width as usize; + outer_pos += 2 + 2 * iterations; activity_pos += 2; } else { // A duplicated pointer will have the following two outer_fn arguments: @@ -201,7 +228,23 @@ fn compute_enzyme_fn_ty<'ll>( } if attrs.width == 1 { - todo!("Handle sret for scalar ad"); + // Enzyme returns a struct of style: + // `{ original_ret(if requested), float, float, ... }` + let mut struct_elements = vec![]; + if attrs.has_primal_ret() { + struct_elements.push(inner_ret_ty); + } + // Next, we push the list of active floats, since they will be lowered to `enzyme_out`, + // and therefore part of the return struct. + let param_tys = cx.func_params_types(fn_ty); + for (act, param_ty) in attrs.input_activity.iter().zip(param_tys) { + if matches!(act, DiffActivity::Active) { + // Now find the float type at position i based on the fn_ty, + // to know what (f16/f32/f64/...) to add to the struct. + struct_elements.push(param_ty); + } + } + ret_ty = cx.type_struct(&struct_elements, false); } else { // First we check if we also have to deal with the primal return. match attrs.mode { @@ -344,6 +387,7 @@ fn generate_enzyme_call<'ll>( let outer_args: Vec<&llvm::Value> = get_params(outer_fn); match_args_from_caller_to_enzyme( &cx, + &builder, attrs.width, &mut args, &attrs.input_activity, @@ -388,7 +432,11 @@ fn generate_enzyme_call<'ll>( // now store the result of the enzyme call into the sret pointer. let sret_ptr = outer_args[0]; let call_ty = cx.val_ty(call); - assert_eq!(cx.type_kind(call_ty), TypeKind::Array); + if attrs.width == 1 { + assert_eq!(cx.type_kind(call_ty), TypeKind::Struct); + } else { + assert_eq!(cx.type_kind(call_ty), TypeKind::Array); + } llvm::LLVMBuildStore(&builder.llbuilder, call, sret_ptr); } builder.ret_void(); diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index 457e5452ce94..a6f277e4455b 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -4,8 +4,8 @@ use std::borrow::Borrow; use libc::{c_char, c_uint}; use rustc_abi as abi; +use rustc_abi::HasDataLayout; use rustc_abi::Primitive::Pointer; -use rustc_abi::{AddressSpace, HasDataLayout}; use rustc_ast::Mutability; use rustc_codegen_ssa::common::TypeKind; use rustc_codegen_ssa::traits::*; @@ -269,7 +269,8 @@ impl<'ll, 'tcx> ConstCodegenMethods for CodegenCx<'ll, 'tcx> { } Scalar::Ptr(ptr, _size) => { let (prov, offset) = ptr.into_parts(); - let (base_addr, base_addr_space) = match self.tcx.global_alloc(prov.alloc_id()) { + let global_alloc = self.tcx.global_alloc(prov.alloc_id()); + let base_addr = match global_alloc { GlobalAlloc::Memory(alloc) => { // For ZSTs directly codegen an aligned pointer. // This avoids generating a zero-sized constant value and actually needing a @@ -301,12 +302,10 @@ impl<'ll, 'tcx> ConstCodegenMethods for CodegenCx<'ll, 'tcx> { format!("alloc_{hash:032x}").as_bytes(), ); } - (value, AddressSpace::DATA) + value } } - GlobalAlloc::Function { instance, .. } => { - (self.get_fn_addr(instance), self.data_layout().instruction_address_space) - } + GlobalAlloc::Function { instance, .. } => self.get_fn_addr(instance), GlobalAlloc::VTable(ty, dyn_ty) => { let alloc = self .tcx @@ -319,14 +318,15 @@ impl<'ll, 'tcx> ConstCodegenMethods for CodegenCx<'ll, 'tcx> { .unwrap_memory(); let init = const_alloc_to_llvm(self, alloc, /*static*/ false); let value = self.static_addr_of_impl(init, alloc.inner().align, None); - (value, AddressSpace::DATA) + value } GlobalAlloc::Static(def_id) => { assert!(self.tcx.is_static(def_id)); assert!(!self.tcx.is_thread_local_static(def_id)); - (self.get_static(def_id), AddressSpace::DATA) + self.get_static(def_id) } }; + let base_addr_space = global_alloc.address_space(self); let llval = unsafe { llvm::LLVMConstInBoundsGEP2( self.type_i8(), diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs index 9a2473d6cf23..55b1e728b70d 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs @@ -5,15 +5,11 @@ use rustc_abi::Align; use rustc_codegen_ssa::traits::{ BaseTypeCodegenMethods, ConstCodegenMethods, StaticCodegenMethods, }; -use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; -use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_data_structures::fx::FxIndexMap; use rustc_index::IndexVec; -use rustc_middle::mir; -use rustc_middle::mir::mono::MonoItemPartitions; -use rustc_middle::ty::{self, TyCtxt}; +use rustc_middle::ty::TyCtxt; use rustc_session::RemapFileNameExt; use rustc_session::config::RemapPathScopeComponents; -use rustc_span::def_id::DefIdSet; use rustc_span::{SourceFile, StableSourceFileId}; use tracing::debug; @@ -24,6 +20,7 @@ use crate::llvm; mod covfun; mod spans; +mod unused; /// Generates and exports the coverage map, which is embedded in special /// linker sections in the final binary. @@ -56,13 +53,6 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) { None => return, }; - // The order of entries in this global file table needs to be deterministic, - // and ideally should also be independent of the details of stable-hashing, - // because coverage tests snapshots (`.cov-map`) can observe the order and - // would need to be re-blessed if it changes. As long as those requirements - // are satisfied, the order can be arbitrary. - let mut global_file_table = GlobalFileTable::new(); - let mut covfun_records = instances_used .iter() .copied() @@ -70,18 +60,13 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) { // order that doesn't depend on the stable-hash-based order in which // instances were visited during codegen. .sorted_by_cached_key(|&instance| tcx.symbol_name(instance).name) - .filter_map(|instance| prepare_covfun_record(tcx, &mut global_file_table, instance, true)) + .filter_map(|instance| prepare_covfun_record(tcx, instance, true)) .collect::>(); // In a single designated CGU, also prepare covfun records for functions // in this crate that were instrumented for coverage, but are unused. if cx.codegen_unit.is_code_coverage_dead_code_cgu() { - let mut unused_instances = gather_unused_function_instances(cx); - // Sort the unused instances by symbol name, for the same reason as the used ones. - unused_instances.sort_by_cached_key(|&instance| tcx.symbol_name(instance).name); - covfun_records.extend(unused_instances.into_iter().filter_map(|instance| { - prepare_covfun_record(tcx, &mut global_file_table, instance, false) - })); + unused::prepare_covfun_records_for_unused_functions(cx, &mut covfun_records); } // If there are no covfun records for this CGU, don't generate a covmap record. @@ -93,91 +78,88 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) { return; } - // Encode all filenames referenced by coverage mappings in this CGU. - let filenames_buffer = global_file_table.make_filenames_buffer(tcx); - // The `llvm-cov` tool uses this hash to associate each covfun record with - // its corresponding filenames table, since the final binary will typically - // contain multiple covmap records from different compilation units. - let filenames_hash = llvm_cov::hash_bytes(&filenames_buffer); - - let mut unused_function_names = vec![]; + // Prepare the global file table for this CGU, containing all paths needed + // by one or more covfun records. + let global_file_table = + GlobalFileTable::build(tcx, covfun_records.iter().flat_map(|c| c.all_source_files())); for covfun in &covfun_records { - unused_function_names.extend(covfun.mangled_function_name_if_unused()); - - covfun::generate_covfun_record(cx, filenames_hash, covfun) - } - - // For unused functions, we need to take their mangled names and store them - // in a specially-named global array. LLVM's `InstrProfiling` pass will - // detect this global and include those names in its `__llvm_prf_names` - // section. (See `llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp`.) - if !unused_function_names.is_empty() { - assert!(cx.codegen_unit.is_code_coverage_dead_code_cgu()); - - let name_globals = unused_function_names - .into_iter() - .map(|mangled_function_name| cx.const_str(mangled_function_name).0) - .collect::>(); - let initializer = cx.const_array(cx.type_ptr(), &name_globals); - - let array = llvm::add_global(cx.llmod, cx.val_ty(initializer), c"__llvm_coverage_names"); - llvm::set_global_constant(array, true); - llvm::set_linkage(array, llvm::Linkage::InternalLinkage); - llvm::set_initializer(array, initializer); + covfun::generate_covfun_record(cx, &global_file_table, covfun) } // Generate the coverage map header, which contains the filenames used by // this CGU's coverage mappings, and store it in a well-known global. // (This is skipped if we returned early due to having no covfun records.) - generate_covmap_record(cx, covmap_version, &filenames_buffer); + generate_covmap_record(cx, covmap_version, &global_file_table.filenames_buffer); } -/// Maps "global" (per-CGU) file ID numbers to their underlying source files. +/// Maps "global" (per-CGU) file ID numbers to their underlying source file paths. +#[derive(Debug)] struct GlobalFileTable { /// This "raw" table doesn't include the working dir, so a file's /// global ID is its index in this set **plus one**. - raw_file_table: FxIndexMap>, + raw_file_table: FxIndexMap, + + /// The file table in encoded form (possibly compressed), which can be + /// included directly in this CGU's `__llvm_covmap` record. + filenames_buffer: Vec, + + /// Truncated hash of the bytes in `filenames_buffer`. + /// + /// The `llvm-cov` tool uses this hash to associate each covfun record with + /// its corresponding filenames table, since the final binary will typically + /// contain multiple covmap records from different compilation units. + filenames_hash: u64, } impl GlobalFileTable { - fn new() -> Self { - Self { raw_file_table: FxIndexMap::default() } - } + /// Builds a "global file table" for this CGU, mapping numeric IDs to + /// path strings. + fn build<'a>(tcx: TyCtxt<'_>, all_files: impl Iterator) -> Self { + let mut raw_file_table = FxIndexMap::default(); - fn global_file_id_for_file(&mut self, file: &Arc) -> GlobalFileId { - // Ensure the given file has a table entry, and get its index. - let entry = self.raw_file_table.entry(file.stable_id); - let raw_id = entry.index(); - entry.or_insert_with(|| Arc::clone(file)); + for file in all_files { + raw_file_table.entry(file.stable_id).or_insert_with(|| { + file.name + .for_scope(tcx.sess, RemapPathScopeComponents::MACRO) + .to_string_lossy() + .into_owned() + }); + } - // The raw file table doesn't include an entry for the working dir - // (which has ID 0), so add 1 to get the correct ID. - GlobalFileId::from_usize(raw_id + 1) - } + // FIXME(Zalathar): Consider sorting the file table here, but maybe + // only after adding filename support to coverage-dump, so that the + // table order isn't directly visible in `.coverage-map` snapshots. - fn make_filenames_buffer(&self, tcx: TyCtxt<'_>) -> Vec { - let mut table = Vec::with_capacity(self.raw_file_table.len() + 1); + let mut table = Vec::with_capacity(raw_file_table.len() + 1); - // LLVM Coverage Mapping Format version 6 (zero-based encoded as 5) - // requires setting the first filename to the compilation directory. - // Since rustc generates coverage maps with relative paths, the - // compilation directory can be combined with the relative paths - // to get absolute paths, if needed. - table.push( - tcx.sess - .opts - .working_dir - .for_scope(tcx.sess, RemapPathScopeComponents::MACRO) - .to_string_lossy(), - ); + // Since version 6 of the LLVM coverage mapping format, the first entry + // in the global file table is treated as a base directory, used to + // resolve any other entries that are stored as relative paths. + let base_dir = tcx + .sess + .opts + .working_dir + .for_scope(tcx.sess, RemapPathScopeComponents::MACRO) + .to_string_lossy(); + table.push(base_dir.as_ref()); // Add the regular entries after the base directory. - table.extend(self.raw_file_table.values().map(|file| { - file.name.for_scope(tcx.sess, RemapPathScopeComponents::MACRO).to_string_lossy() - })); + table.extend(raw_file_table.values().map(|name| name.as_str())); - llvm_cov::write_filenames_to_buffer(&table) + // Encode the file table into a buffer, and get the hash of its encoded + // bytes, so that we can embed that hash in `__llvm_covfun` records. + let filenames_buffer = llvm_cov::write_filenames_to_buffer(&table); + let filenames_hash = llvm_cov::hash_bytes(&filenames_buffer); + + Self { raw_file_table, filenames_buffer, filenames_hash } + } + + fn get_existing_id(&self, file: &SourceFile) -> Option { + let raw_id = self.raw_file_table.get_index_of(&file.stable_id)?; + // The raw file table doesn't include an entry for the base dir + // (which has ID 0), so add 1 to get the correct ID. + Some(GlobalFileId::from_usize(raw_id + 1)) } } @@ -193,26 +175,31 @@ rustc_index::newtype_index! { struct LocalFileId {} } -/// Holds a mapping from "local" (per-function) file IDs to "global" (per-CGU) -/// file IDs. +/// Holds a mapping from "local" (per-function) file IDs to their corresponding +/// source files. #[derive(Debug, Default)] struct VirtualFileMapping { - local_to_global: IndexVec, - global_to_local: FxIndexMap, + local_file_table: IndexVec>, } impl VirtualFileMapping { - fn local_id_for_global(&mut self, global_file_id: GlobalFileId) -> LocalFileId { - *self - .global_to_local - .entry(global_file_id) - .or_insert_with(|| self.local_to_global.push(global_file_id)) + fn push_file(&mut self, source_file: &Arc) -> LocalFileId { + self.local_file_table.push(Arc::clone(source_file)) } - fn to_vec(&self) -> Vec { - // This clone could be avoided by transmuting `&[GlobalFileId]` to `&[u32]`, - // but it isn't hot or expensive enough to justify the extra unsafety. - self.local_to_global.iter().map(|&global| GlobalFileId::as_u32(global)).collect() + /// Resolves all of the filenames in this local file mapping to a list of + /// global file IDs in its CGU, for inclusion in this function's + /// `__llvm_covfun` record. + /// + /// The global file IDs are returned as `u32` to make FFI easier. + fn resolve_all(&self, global_file_table: &GlobalFileTable) -> Option> { + self.local_file_table + .iter() + .map(|file| try { + let id = global_file_table.get_existing_id(file)?; + GlobalFileId::as_u32(id) + }) + .collect::>>() } } @@ -249,121 +236,3 @@ fn generate_covmap_record<'ll>(cx: &CodegenCx<'ll, '_>, version: u32, filenames_ cx.add_used_global(covmap_global); } - -/// Each CGU will normally only emit coverage metadata for the functions that it actually generates. -/// But since we don't want unused functions to disappear from coverage reports, we also scan for -/// functions that were instrumented but are not participating in codegen. -/// -/// These unused functions don't need to be codegenned, but we do need to add them to the function -/// coverage map (in a single designated CGU) so that we still emit coverage mappings for them. -/// We also end up adding their symbol names to a special global array that LLVM will include in -/// its embedded coverage data. -fn gather_unused_function_instances<'tcx>(cx: &CodegenCx<'_, 'tcx>) -> Vec> { - assert!(cx.codegen_unit.is_code_coverage_dead_code_cgu()); - - let tcx = cx.tcx; - let usage = prepare_usage_sets(tcx); - - let is_unused_fn = |def_id: LocalDefId| -> bool { - // Usage sets expect `DefId`, so convert from `LocalDefId`. - let d: DefId = LocalDefId::to_def_id(def_id); - // To be potentially eligible for "unused function" mappings, a definition must: - // - Be eligible for coverage instrumentation - // - Not participate directly in codegen (or have lost all its coverage statements) - // - Not have any coverage statements inlined into codegenned functions - tcx.is_eligible_for_coverage(def_id) - && (!usage.all_mono_items.contains(&d) || usage.missing_own_coverage.contains(&d)) - && !usage.used_via_inlining.contains(&d) - }; - - // FIXME(#79651): Consider trying to filter out dummy instantiations of - // unused generic functions from library crates, because they can produce - // "unused instantiation" in coverage reports even when they are actually - // used by some downstream crate in the same binary. - - tcx.mir_keys(()) - .iter() - .copied() - .filter(|&def_id| is_unused_fn(def_id)) - .map(|def_id| make_dummy_instance(tcx, def_id)) - .collect::>() -} - -struct UsageSets<'tcx> { - all_mono_items: &'tcx DefIdSet, - used_via_inlining: FxHashSet, - missing_own_coverage: FxHashSet, -} - -/// Prepare sets of definitions that are relevant to deciding whether something -/// is an "unused function" for coverage purposes. -fn prepare_usage_sets<'tcx>(tcx: TyCtxt<'tcx>) -> UsageSets<'tcx> { - let MonoItemPartitions { all_mono_items, codegen_units, .. } = - tcx.collect_and_partition_mono_items(()); - - // Obtain a MIR body for each function participating in codegen, via an - // arbitrary instance. - let mut def_ids_seen = FxHashSet::default(); - let def_and_mir_for_all_mono_fns = codegen_units - .iter() - .flat_map(|cgu| cgu.items().keys()) - .filter_map(|item| match item { - mir::mono::MonoItem::Fn(instance) => Some(instance), - mir::mono::MonoItem::Static(_) | mir::mono::MonoItem::GlobalAsm(_) => None, - }) - // We only need one arbitrary instance per definition. - .filter(move |instance| def_ids_seen.insert(instance.def_id())) - .map(|instance| { - // We don't care about the instance, just its underlying MIR. - let body = tcx.instance_mir(instance.def); - (instance.def_id(), body) - }); - - // Functions whose coverage statements were found inlined into other functions. - let mut used_via_inlining = FxHashSet::default(); - // Functions that were instrumented, but had all of their coverage statements - // removed by later MIR transforms (e.g. UnreachablePropagation). - let mut missing_own_coverage = FxHashSet::default(); - - for (def_id, body) in def_and_mir_for_all_mono_fns { - let mut saw_own_coverage = false; - - // Inspect every coverage statement in the function's MIR. - for stmt in body - .basic_blocks - .iter() - .flat_map(|block| &block.statements) - .filter(|stmt| matches!(stmt.kind, mir::StatementKind::Coverage(_))) - { - if let Some(inlined) = stmt.source_info.scope.inlined_instance(&body.source_scopes) { - // This coverage statement was inlined from another function. - used_via_inlining.insert(inlined.def_id()); - } else { - // Non-inlined coverage statements belong to the enclosing function. - saw_own_coverage = true; - } - } - - if !saw_own_coverage && body.function_coverage_info.is_some() { - missing_own_coverage.insert(def_id); - } - } - - UsageSets { all_mono_items, used_via_inlining, missing_own_coverage } -} - -fn make_dummy_instance<'tcx>(tcx: TyCtxt<'tcx>, local_def_id: LocalDefId) -> ty::Instance<'tcx> { - let def_id = local_def_id.to_def_id(); - - // Make a dummy instance that fills in all generics with placeholders. - ty::Instance::new( - def_id, - ty::GenericArgs::for_item(tcx, def_id, |param, _| { - if let ty::GenericParamDefKind::Lifetime = param.kind { - tcx.lifetimes.re_erased.into() - } else { - tcx.mk_param_from_def(param) - } - }), - ) -} diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs index 048e1988c327..7bdbc6859529 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs @@ -5,6 +5,7 @@ //! [^win]: On Windows the section name is `.lcovfun`. use std::ffi::CString; +use std::sync::Arc; use rustc_abi::Align; use rustc_codegen_ssa::traits::{ @@ -15,7 +16,7 @@ use rustc_middle::mir::coverage::{ MappingKind, Op, }; use rustc_middle::ty::{Instance, TyCtxt}; -use rustc_span::Span; +use rustc_span::{SourceFile, Span}; use rustc_target::spec::HasTargetSpec; use tracing::debug; @@ -38,16 +39,15 @@ pub(crate) struct CovfunRecord<'tcx> { } impl<'tcx> CovfunRecord<'tcx> { - /// FIXME(Zalathar): Make this the responsibility of the code that determines - /// which functions are unused. - pub(crate) fn mangled_function_name_if_unused(&self) -> Option<&'tcx str> { - (!self.is_used).then_some(self.mangled_function_name) + /// Iterator that yields all source files referred to by this function's + /// coverage mappings. Used to build the global file table for the CGU. + pub(crate) fn all_source_files(&self) -> impl Iterator { + self.virtual_file_mapping.local_file_table.iter().map(Arc::as_ref) } } pub(crate) fn prepare_covfun_record<'tcx>( tcx: TyCtxt<'tcx>, - global_file_table: &mut GlobalFileTable, instance: Instance<'tcx>, is_used: bool, ) -> Option> { @@ -65,7 +65,7 @@ pub(crate) fn prepare_covfun_record<'tcx>( regions: ffi::Regions::default(), }; - fill_region_tables(tcx, global_file_table, fn_cov_info, ids_info, &mut covfun); + fill_region_tables(tcx, fn_cov_info, ids_info, &mut covfun); if covfun.regions.has_no_regions() { debug!(?covfun, "function has no mappings to embed; skipping"); @@ -100,7 +100,6 @@ fn prepare_expressions(ids_info: &CoverageIdsInfo) -> Vec( tcx: TyCtxt<'tcx>, - global_file_table: &mut GlobalFileTable, fn_cov_info: &'tcx FunctionCoverageInfo, ids_info: &'tcx CoverageIdsInfo, covfun: &mut CovfunRecord<'tcx>, @@ -114,11 +113,7 @@ fn fill_region_tables<'tcx>( }; let source_file = source_map.lookup_source_file(first_span.lo()); - // Look up the global file ID for that file. - let global_file_id = global_file_table.global_file_id_for_file(&source_file); - - // Associate that global file ID with a local file ID for this function. - let local_file_id = covfun.virtual_file_mapping.local_id_for_global(global_file_id); + let local_file_id = covfun.virtual_file_mapping.push_file(&source_file); // In rare cases, _all_ of a function's spans are discarded, and coverage // codegen needs to handle that gracefully to avoid #133606. @@ -187,7 +182,7 @@ fn fill_region_tables<'tcx>( /// as a global variable in the `__llvm_covfun` section. pub(crate) fn generate_covfun_record<'tcx>( cx: &CodegenCx<'_, 'tcx>, - filenames_hash: u64, + global_file_table: &GlobalFileTable, covfun: &CovfunRecord<'tcx>, ) { let &CovfunRecord { @@ -199,12 +194,19 @@ pub(crate) fn generate_covfun_record<'tcx>( ref regions, } = covfun; + let Some(local_file_table) = virtual_file_mapping.resolve_all(global_file_table) else { + debug_assert!( + false, + "all local files should be present in the global file table: \ + global_file_table = {global_file_table:?}, \ + virtual_file_mapping = {virtual_file_mapping:?}" + ); + return; + }; + // Encode the function's coverage mappings into a buffer. - let coverage_mapping_buffer = llvm_cov::write_function_mappings_to_buffer( - &virtual_file_mapping.to_vec(), - expressions, - regions, - ); + let coverage_mapping_buffer = + llvm_cov::write_function_mappings_to_buffer(&local_file_table, expressions, regions); // A covfun record consists of four target-endian integers, followed by the // encoded mapping data in bytes. Note that the length field is 32 bits. @@ -217,7 +219,7 @@ pub(crate) fn generate_covfun_record<'tcx>( cx.const_u64(func_name_hash), cx.const_u32(coverage_mapping_buffer.len() as u32), cx.const_u64(source_hash), - cx.const_u64(filenames_hash), + cx.const_u64(global_file_table.filenames_hash), cx.const_bytes(&coverage_mapping_buffer), ], // This struct needs to be packed, so that the 32-bit length field diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/unused.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/unused.rs new file mode 100644 index 000000000000..68f60f169b5b --- /dev/null +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/unused.rs @@ -0,0 +1,170 @@ +use rustc_codegen_ssa::traits::{BaseTypeCodegenMethods, ConstCodegenMethods}; +use rustc_data_structures::fx::FxHashSet; +use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_middle::mir; +use rustc_middle::mir::mono::MonoItemPartitions; +use rustc_middle::ty::{self, TyCtxt}; +use rustc_span::def_id::DefIdSet; + +use crate::common::CodegenCx; +use crate::coverageinfo::mapgen::covfun::{CovfunRecord, prepare_covfun_record}; +use crate::llvm; + +/// Each CGU will normally only emit coverage metadata for the functions that it actually generates. +/// But since we don't want unused functions to disappear from coverage reports, we also scan for +/// functions that were instrumented but are not participating in codegen. +/// +/// These unused functions don't need to be codegenned, but we do need to add them to the function +/// coverage map (in a single designated CGU) so that we still emit coverage mappings for them. +/// We also end up adding their symbol names to a special global array that LLVM will include in +/// its embedded coverage data. +pub(crate) fn prepare_covfun_records_for_unused_functions<'tcx>( + cx: &CodegenCx<'_, 'tcx>, + covfun_records: &mut Vec>, +) { + assert!(cx.codegen_unit.is_code_coverage_dead_code_cgu()); + + let mut unused_instances = gather_unused_function_instances(cx); + // Sort the unused instances by symbol name, so that their order isn't hash-sensitive. + unused_instances.sort_by_key(|instance| instance.symbol_name); + + // Try to create a covfun record for each unused function. + let mut name_globals = Vec::with_capacity(unused_instances.len()); + covfun_records.extend(unused_instances.into_iter().filter_map(|unused| try { + let record = prepare_covfun_record(cx.tcx, unused.instance, false)?; + // If successful, also store its symbol name in a global constant. + name_globals.push(cx.const_str(unused.symbol_name.name).0); + record + })); + + // Store the names of unused functions in a specially-named global array. + // LLVM's `InstrProfilling` pass will detect this array, and include the + // referenced names in its `__llvm_prf_names` section. + // (See `llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp`.) + if !name_globals.is_empty() { + let initializer = cx.const_array(cx.type_ptr(), &name_globals); + + let array = llvm::add_global(cx.llmod, cx.val_ty(initializer), c"__llvm_coverage_names"); + llvm::set_global_constant(array, true); + llvm::set_linkage(array, llvm::Linkage::InternalLinkage); + llvm::set_initializer(array, initializer); + } +} + +/// Holds a dummy function instance along with its symbol name, to avoid having +/// to repeatedly query for the name. +struct UnusedInstance<'tcx> { + instance: ty::Instance<'tcx>, + symbol_name: ty::SymbolName<'tcx>, +} + +fn gather_unused_function_instances<'tcx>(cx: &CodegenCx<'_, 'tcx>) -> Vec> { + assert!(cx.codegen_unit.is_code_coverage_dead_code_cgu()); + + let tcx = cx.tcx; + let usage = prepare_usage_sets(tcx); + + let is_unused_fn = |def_id: LocalDefId| -> bool { + // Usage sets expect `DefId`, so convert from `LocalDefId`. + let d: DefId = LocalDefId::to_def_id(def_id); + // To be potentially eligible for "unused function" mappings, a definition must: + // - Be eligible for coverage instrumentation + // - Not participate directly in codegen (or have lost all its coverage statements) + // - Not have any coverage statements inlined into codegenned functions + tcx.is_eligible_for_coverage(def_id) + && (!usage.all_mono_items.contains(&d) || usage.missing_own_coverage.contains(&d)) + && !usage.used_via_inlining.contains(&d) + }; + + // FIXME(#79651): Consider trying to filter out dummy instantiations of + // unused generic functions from library crates, because they can produce + // "unused instantiation" in coverage reports even when they are actually + // used by some downstream crate in the same binary. + + tcx.mir_keys(()) + .iter() + .copied() + .filter(|&def_id| is_unused_fn(def_id)) + .map(|def_id| make_dummy_instance(tcx, def_id)) + .map(|instance| UnusedInstance { instance, symbol_name: tcx.symbol_name(instance) }) + .collect::>() +} + +struct UsageSets<'tcx> { + all_mono_items: &'tcx DefIdSet, + used_via_inlining: FxHashSet, + missing_own_coverage: FxHashSet, +} + +/// Prepare sets of definitions that are relevant to deciding whether something +/// is an "unused function" for coverage purposes. +fn prepare_usage_sets<'tcx>(tcx: TyCtxt<'tcx>) -> UsageSets<'tcx> { + let MonoItemPartitions { all_mono_items, codegen_units, .. } = + tcx.collect_and_partition_mono_items(()); + + // Obtain a MIR body for each function participating in codegen, via an + // arbitrary instance. + let mut def_ids_seen = FxHashSet::default(); + let def_and_mir_for_all_mono_fns = codegen_units + .iter() + .flat_map(|cgu| cgu.items().keys()) + .filter_map(|item| match item { + mir::mono::MonoItem::Fn(instance) => Some(instance), + mir::mono::MonoItem::Static(_) | mir::mono::MonoItem::GlobalAsm(_) => None, + }) + // We only need one arbitrary instance per definition. + .filter(move |instance| def_ids_seen.insert(instance.def_id())) + .map(|instance| { + // We don't care about the instance, just its underlying MIR. + let body = tcx.instance_mir(instance.def); + (instance.def_id(), body) + }); + + // Functions whose coverage statements were found inlined into other functions. + let mut used_via_inlining = FxHashSet::default(); + // Functions that were instrumented, but had all of their coverage statements + // removed by later MIR transforms (e.g. UnreachablePropagation). + let mut missing_own_coverage = FxHashSet::default(); + + for (def_id, body) in def_and_mir_for_all_mono_fns { + let mut saw_own_coverage = false; + + // Inspect every coverage statement in the function's MIR. + for stmt in body + .basic_blocks + .iter() + .flat_map(|block| &block.statements) + .filter(|stmt| matches!(stmt.kind, mir::StatementKind::Coverage(_))) + { + if let Some(inlined) = stmt.source_info.scope.inlined_instance(&body.source_scopes) { + // This coverage statement was inlined from another function. + used_via_inlining.insert(inlined.def_id()); + } else { + // Non-inlined coverage statements belong to the enclosing function. + saw_own_coverage = true; + } + } + + if !saw_own_coverage && body.function_coverage_info.is_some() { + missing_own_coverage.insert(def_id); + } + } + + UsageSets { all_mono_items, used_via_inlining, missing_own_coverage } +} + +fn make_dummy_instance<'tcx>(tcx: TyCtxt<'tcx>, local_def_id: LocalDefId) -> ty::Instance<'tcx> { + let def_id = local_def_id.to_def_id(); + + // Make a dummy instance that fills in all generics with placeholders. + ty::Instance::new( + def_id, + ty::GenericArgs::for_item(tcx, def_id, |param, _| { + if let ty::GenericParamDefKind::Lifetime = param.kind { + tcx.lifetimes.re_erased.into() + } else { + tcx.mk_param_from_def(param) + } + }), + ) +} diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs index f52991b36979..d2591139d6ed 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs @@ -3,7 +3,6 @@ use std::collections::hash_map::Entry; use rustc_codegen_ssa::mir::debuginfo::{DebugScope, FunctionDebugContext}; use rustc_codegen_ssa::traits::*; use rustc_data_structures::fx::FxHashMap; -use rustc_index::Idx; use rustc_index::bit_set::DenseBitSet; use rustc_middle::mir::{Body, SourceScope}; use rustc_middle::ty::layout::{FnAbiOf, HasTypingEnv}; @@ -43,8 +42,7 @@ pub(crate) fn compute_mir_scopes<'ll, 'tcx>( let mut instantiated = DenseBitSet::new_empty(mir.source_scopes.len()); let mut discriminators = FxHashMap::default(); // Instantiate all scopes. - for idx in 0..mir.source_scopes.len() { - let scope = SourceScope::new(idx); + for scope in mir.source_scopes.indices() { make_mir_scope( cx, instance, diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 2eaaf127e41e..7f3e486ca310 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -910,7 +910,8 @@ pub(crate) fn build_compile_unit_di_node<'ll, 'tcx>( && let Some(f) = output_filenames.split_dwarf_path( tcx.sess.split_debuginfo(), tcx.sess.opts.unstable_opts.split_dwarf_kind, - Some(codegen_unit_name), + codegen_unit_name, + tcx.sess.invocation_temp.as_deref(), ) { // We get a path relative to the working directory from split_dwarf_path Some(tcx.sess.source_map().path_mapping().to_real_filename(f)) @@ -1314,31 +1315,21 @@ fn build_generic_type_param_di_nodes<'ll, 'tcx>( ty: Ty<'tcx>, ) -> SmallVec> { if let ty::Adt(def, args) = *ty.kind() { - let generics = cx.tcx.generics_of(def.did()); - return get_template_parameters(cx, generics, args); - } - - return smallvec![]; -} - -pub(super) fn get_template_parameters<'ll, 'tcx>( - cx: &CodegenCx<'ll, 'tcx>, - generics: &ty::Generics, - args: ty::GenericArgsRef<'tcx>, -) -> SmallVec> { - if args.types().next().is_some() { - let names = get_parameter_names(cx, generics); - let template_params: SmallVec<_> = iter::zip(args, names) - .filter_map(|(kind, name)| { - kind.as_type().map(|ty| { - let actual_type = cx.tcx.normalize_erasing_regions(cx.typing_env(), ty); - let actual_type_di_node = type_di_node(cx, actual_type); - Some(cx.create_template_type_parameter(name.as_str(), actual_type_di_node)) + if args.types().next().is_some() { + let generics = cx.tcx.generics_of(def.did()); + let names = get_parameter_names(cx, generics); + let template_params: SmallVec<_> = iter::zip(args, names) + .filter_map(|(kind, name)| { + kind.as_type().map(|ty| { + let actual_type = cx.tcx.normalize_erasing_regions(cx.typing_env(), ty); + let actual_type_di_node = type_di_node(cx, actual_type); + Some(cx.create_template_type_parameter(name.as_str(), actual_type_di_node)) + }) }) - }) - .collect(); + .collect(); - return template_params; + return template_params; + } } return smallvec![]; diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs index 6792c307fdc4..7c701926d2c5 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs @@ -363,7 +363,6 @@ fn build_coroutine_variant_struct_type_di_node<'ll, 'tcx>( state_specific_fields.into_iter().chain(common_fields).collect() }, - // FIXME: this is a no-op. `build_generic_type_param_di_nodes` only works for Adts. |cx| build_generic_type_param_di_nodes(cx, coroutine_type_and_layout.ty), ) .di_node 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 ae2ab32ef533..56fb12d3c22e 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs @@ -247,6 +247,16 @@ pub(super) fn stub<'ll, 'tcx>( StubInfo { metadata, unique_type_id } } +struct AdtStackPopGuard<'ll, 'tcx, 'a> { + cx: &'a CodegenCx<'ll, 'tcx>, +} + +impl<'ll, 'tcx, 'a> Drop for AdtStackPopGuard<'ll, 'tcx, 'a> { + fn drop(&mut self) { + debug_context(self.cx).adt_stack.borrow_mut().pop(); + } +} + /// This function enables creating debuginfo nodes that can recursively refer to themselves. /// It will first insert the given stub into the type map and only then execute the `members` /// and `generics` closures passed in. These closures have access to the stub so they can @@ -261,6 +271,44 @@ pub(super) fn build_type_with_children<'ll, 'tcx>( ) -> DINodeCreationResult<'ll> { assert_eq!(debug_context(cx).type_map.di_node_for_unique_id(stub_info.unique_type_id), None); + let mut _adt_stack_pop_guard = None; + if let UniqueTypeId::Ty(ty, ..) = stub_info.unique_type_id + && let ty::Adt(adt_def, args) = ty.kind() + { + let def_id = adt_def.did(); + // If any sub type reference the original type definition and the sub type has a type + // parameter that strictly contains the original parameter, the original type is a recursive + // type that can expanding indefinitely. Example, + // ``` + // enum Recursive { + // Recurse(*const Recursive>), + // Item(T), + // } + // ``` + let is_expanding_recursive = + debug_context(cx).adt_stack.borrow().iter().any(|(parent_def_id, parent_args)| { + if def_id == *parent_def_id { + args.iter().zip(parent_args.iter()).any(|(arg, parent_arg)| { + if let (Some(arg), Some(parent_arg)) = (arg.as_type(), parent_arg.as_type()) + { + arg != parent_arg && arg.contains(parent_arg) + } else { + false + } + }) + } else { + false + } + }); + if is_expanding_recursive { + // FIXME: indicate that this is an expanding recursive type in stub metadata? + return DINodeCreationResult::new(stub_info.metadata, false); + } else { + debug_context(cx).adt_stack.borrow_mut().push((def_id, args)); + _adt_stack_pop_guard = Some(AdtStackPopGuard { cx }); + } + } + debug_context(cx).type_map.insert(stub_info.unique_type_id, stub_info.metadata); let members: SmallVec<_> = diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index ae7d080db66f..c50859279234 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -2,8 +2,8 @@ use std::cell::{OnceCell, RefCell}; use std::ops::Range; -use std::ptr; use std::sync::Arc; +use std::{iter, ptr}; use libc::c_uint; use metadata::create_subroutine_type; @@ -66,6 +66,7 @@ pub(crate) struct CodegenUnitDebugContext<'ll, 'tcx> { created_files: RefCell, &'ll DIFile>>, type_map: metadata::TypeMap<'ll, 'tcx>, + adt_stack: RefCell)>>, namespace_map: RefCell>, recursion_marker_type: OnceCell<&'ll DIType>, } @@ -80,6 +81,7 @@ impl<'ll, 'tcx> CodegenUnitDebugContext<'ll, 'tcx> { builder, created_files: Default::default(), type_map: Default::default(), + adt_stack: Default::default(), namespace_map: RefCell::new(Default::default()), recursion_marker_type: OnceCell::new(), } @@ -486,10 +488,40 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { generics: &ty::Generics, args: GenericArgsRef<'tcx>, ) -> &'ll DIArray { - let template_params = metadata::get_template_parameters(cx, generics, args); + if args.types().next().is_none() { + return create_DIArray(DIB(cx), &[]); + } + + // Again, only create type information if full debuginfo is enabled + let template_params: Vec<_> = if cx.sess().opts.debuginfo == DebugInfo::Full { + let names = get_parameter_names(cx, generics); + iter::zip(args, names) + .filter_map(|(kind, name)| { + kind.as_type().map(|ty| { + let actual_type = cx.tcx.normalize_erasing_regions(cx.typing_env(), ty); + let actual_type_metadata = type_di_node(cx, actual_type); + Some(cx.create_template_type_parameter( + name.as_str(), + actual_type_metadata, + )) + }) + }) + .collect() + } else { + vec![] + }; + create_DIArray(DIB(cx), &template_params) } + fn get_parameter_names(cx: &CodegenCx<'_, '_>, generics: &ty::Generics) -> Vec { + let mut names = generics.parent.map_or_else(Vec::new, |def_id| { + get_parameter_names(cx, cx.tcx.generics_of(def_id)) + }); + names.extend(generics.own_params.iter().map(|param| param.name)); + names + } + /// Returns a scope, plus `true` if that's a type scope for "class" methods, /// otherwise `false` for plain namespace scopes. fn get_containing_scope<'ll, 'tcx>( diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 67135fcc3080..d1d6bcebd33a 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -1421,7 +1421,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>( return Ok(bx.shuffle_vector(args[0].immediate(), args[1].immediate(), indices)); } - if name == sym::simd_insert { + if name == sym::simd_insert || name == sym::simd_insert_dyn { require!( in_elem == arg_tys[2], InvalidMonomorphization::InsertedType { @@ -1432,40 +1432,49 @@ fn generic_simd_intrinsic<'ll, 'tcx>( out_ty: arg_tys[2] } ); - let idx = bx - .const_to_opt_u128(args[1].immediate(), false) - .expect("typeck should have ensure that this is a const"); - if idx >= in_len.into() { - return_error!(InvalidMonomorphization::SimdIndexOutOfBounds { - span, - name, - arg_idx: 1, - total_len: in_len.into(), - }); - } - return Ok(bx.insert_element( - args[0].immediate(), - args[2].immediate(), - bx.const_i32(idx as i32), - )); + + let index_imm = if name == sym::simd_insert { + let idx = bx + .const_to_opt_u128(args[1].immediate(), false) + .expect("typeck should have ensure that this is a const"); + if idx >= in_len.into() { + return_error!(InvalidMonomorphization::SimdIndexOutOfBounds { + span, + name, + arg_idx: 1, + total_len: in_len.into(), + }); + } + bx.const_i32(idx as i32) + } else { + args[1].immediate() + }; + + return Ok(bx.insert_element(args[0].immediate(), args[2].immediate(), index_imm)); } - if name == sym::simd_extract { + if name == sym::simd_extract || name == sym::simd_extract_dyn { require!( ret_ty == in_elem, InvalidMonomorphization::ReturnType { span, name, in_elem, in_ty, ret_ty } ); - let idx = bx - .const_to_opt_u128(args[1].immediate(), false) - .expect("typeck should have ensure that this is a const"); - if idx >= in_len.into() { - return_error!(InvalidMonomorphization::SimdIndexOutOfBounds { - span, - name, - arg_idx: 1, - total_len: in_len.into(), - }); - } - return Ok(bx.extract_element(args[0].immediate(), bx.const_i32(idx as i32))); + let index_imm = if name == sym::simd_extract { + let idx = bx + .const_to_opt_u128(args[1].immediate(), false) + .expect("typeck should have ensure that this is a const"); + if idx >= in_len.into() { + return_error!(InvalidMonomorphization::SimdIndexOutOfBounds { + span, + name, + arg_idx: 1, + total_len: in_len.into(), + }); + } + bx.const_i32(idx as i32) + } else { + args[1].immediate() + }; + + return Ok(bx.extract_element(args[0].immediate(), index_imm)); } if name == sym::simd_select { diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 1d05c4eee4d1..8de68925cabb 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -112,8 +112,12 @@ pub fn link_binary( codegen_results.crate_info.local_crate_name, ); let crate_name = format!("{}", codegen_results.crate_info.local_crate_name); - let out_filename = - output.file_for_writing(outputs, OutputType::Exe, Some(crate_name.as_str())); + let out_filename = output.file_for_writing( + outputs, + OutputType::Exe, + &crate_name, + sess.invocation_temp.as_deref(), + ); match crate_type { CrateType::Rlib => { let _timer = sess.timer("link_rlib"); diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index e816e71379aa..0fd4ed8475b4 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -306,14 +306,18 @@ impl TargetMachineFactoryConfig { cgcx.output_filenames.split_dwarf_path( cgcx.split_debuginfo, cgcx.split_dwarf_kind, - Some(module_name), + module_name, + cgcx.invocation_temp.as_deref(), ) } else { None }; - let output_obj_file = - Some(cgcx.output_filenames.temp_path(OutputType::Object, Some(module_name))); + let output_obj_file = Some(cgcx.output_filenames.temp_path_for_cgu( + OutputType::Object, + module_name, + cgcx.invocation_temp.as_deref(), + )); TargetMachineFactoryConfig { split_dwarf_file, output_obj_file } } } @@ -344,6 +348,7 @@ pub struct CodegenContext { pub crate_types: Vec, pub each_linked_rlib_for_lto: Vec<(CrateNum, PathBuf)>, pub output_filenames: Arc, + pub invocation_temp: Option, pub regular_module_config: Arc, pub metadata_module_config: Arc, pub allocator_module_config: Arc, @@ -582,8 +587,11 @@ fn produce_final_output_artifacts( if let [module] = &compiled_modules.modules[..] { // 1) Only one codegen unit. In this case it's no difficulty // to copy `foo.0.x` to `foo.x`. - let module_name = Some(&module.name[..]); - let path = crate_output.temp_path(output_type, module_name); + let path = crate_output.temp_path_for_cgu( + output_type, + &module.name, + sess.invocation_temp.as_deref(), + ); let output = crate_output.path(output_type); if !output_type.is_text_output() && output.is_tty() { sess.dcx() @@ -596,22 +604,15 @@ fn produce_final_output_artifacts( ensure_removed(sess.dcx(), &path); } } else { - let extension = crate_output - .temp_path(output_type, None) - .extension() - .unwrap() - .to_str() - .unwrap() - .to_owned(); - if crate_output.outputs.contains_explicit_name(&output_type) { // 2) Multiple codegen units, with `--emit foo=some_name`. We have // no good solution for this case, so warn the user. - sess.dcx().emit_warn(errors::IgnoringEmitPath { extension }); + sess.dcx() + .emit_warn(errors::IgnoringEmitPath { extension: output_type.extension() }); } else if crate_output.single_output_file.is_some() { // 3) Multiple codegen units, with `-o some_name`. We have // no good solution for this case, so warn the user. - sess.dcx().emit_warn(errors::IgnoringOutput { extension }); + sess.dcx().emit_warn(errors::IgnoringOutput { extension: output_type.extension() }); } else { // 4) Multiple codegen units, but no explicit name. We // just leave the `foo.0.x` files in place. @@ -967,7 +968,12 @@ fn execute_copy_from_cache_work_item( 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)) + .split_dwarf_path( + cgcx.split_debuginfo, + cgcx.split_dwarf_kind, + &module.name, + cgcx.invocation_temp.as_deref(), + ) .expect( "saved dwarf object in work product but `split_dwarf_path` returned `None`", ); @@ -977,7 +983,11 @@ fn execute_copy_from_cache_work_item( let mut load_from_incr_cache = |perform, output_type: OutputType| { if perform { let saved_file = module.source.saved_files.get(output_type.extension())?; - let output_path = cgcx.output_filenames.temp_path(output_type, Some(&module.name)); + let output_path = cgcx.output_filenames.temp_path_for_cgu( + output_type, + &module.name, + cgcx.invocation_temp.as_deref(), + ); load_from_incr_comp_dir(output_path, &saved_file) } else { None @@ -1222,6 +1232,7 @@ fn start_executing_work( split_dwarf_kind: tcx.sess.opts.unstable_opts.split_dwarf_kind, parallel: backend.supports_parallel() && !sess.opts.unstable_opts.no_parallel_backend, pointer_size: tcx.data_layout.pointer_size, + invocation_temp: sess.invocation_temp.clone(), }; // This is the "main loop" of parallel work happening for parallel codegen. diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 1985b3b71706..12b7a4874556 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -10,7 +10,7 @@ use rustc_ast::expand::allocator::{ALLOCATOR_METHODS, AllocatorKind, global_fn_n use rustc_attr_parsing::OptimizeAttr; use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry}; -use rustc_data_structures::sync::par_map; +use rustc_data_structures::sync::{IntoDynSyncSend, par_map}; use rustc_data_structures::unord::UnordMap; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_hir::lang_items::LangItem; @@ -640,8 +640,11 @@ pub fn codegen_crate( let metadata_cgu_name = cgu_name_builder.build_cgu_name(LOCAL_CRATE, &["crate"], Some("metadata")).to_string(); tcx.sess.time("write_compressed_metadata", || { - let file_name = - tcx.output_filenames(()).temp_path(OutputType::Metadata, Some(&metadata_cgu_name)); + let file_name = tcx.output_filenames(()).temp_path_for_cgu( + OutputType::Metadata, + &metadata_cgu_name, + tcx.sess.invocation_temp.as_deref(), + ); let data = create_compressed_metadata_file( tcx.sess, &metadata, @@ -757,7 +760,7 @@ pub fn codegen_crate( let pre_compiled_cgus = par_map(cgus, |(i, _)| { let module = backend.compile_codegen_unit(tcx, codegen_units[i].name()); - (i, module) + (i, IntoDynSyncSend(module)) }); total_codegen_time += start_time.elapsed(); @@ -777,7 +780,7 @@ pub fn codegen_crate( match cgu_reuse { CguReuse::No => { let (module, cost) = if let Some(cgu) = pre_compiled_cgus.remove(&i) { - cgu + cgu.0 } else { let start_time = Instant::now(); let module = backend.compile_codegen_unit(tcx, cgu.name()); diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index ddb611889833..b0c53ec93ce1 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -114,7 +114,8 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { AttributeKind::Repr(reprs) => { codegen_fn_attrs.alignment = reprs .iter() - .find_map(|(r, _)| if let ReprAlign(x) = r { Some(*x) } else { None }); + .filter_map(|(r, _)| if let ReprAlign(x) = r { Some(*x) } else { None }) + .max(); } _ => {} @@ -345,20 +346,26 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { no_sanitize_span = Some(attr.span()); if let Some(list) = attr.meta_item_list() { for item in list.iter() { - match item.name_or_empty() { - sym::address => { + match item.name() { + Some(sym::address) => { codegen_fn_attrs.no_sanitize |= SanitizerSet::ADDRESS | SanitizerSet::KERNELADDRESS } - sym::cfi => codegen_fn_attrs.no_sanitize |= SanitizerSet::CFI, - sym::kcfi => codegen_fn_attrs.no_sanitize |= SanitizerSet::KCFI, - sym::memory => codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMORY, - sym::memtag => codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMTAG, - sym::shadow_call_stack => { + Some(sym::cfi) => codegen_fn_attrs.no_sanitize |= SanitizerSet::CFI, + Some(sym::kcfi) => codegen_fn_attrs.no_sanitize |= SanitizerSet::KCFI, + Some(sym::memory) => { + codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMORY + } + Some(sym::memtag) => { + codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMTAG + } + Some(sym::shadow_call_stack) => { codegen_fn_attrs.no_sanitize |= SanitizerSet::SHADOWCALLSTACK } - sym::thread => codegen_fn_attrs.no_sanitize |= SanitizerSet::THREAD, - sym::hwaddress => { + Some(sym::thread) => { + codegen_fn_attrs.no_sanitize |= SanitizerSet::THREAD + } + Some(sym::hwaddress) => { codegen_fn_attrs.no_sanitize |= SanitizerSet::HWADDRESS } _ => { @@ -419,9 +426,9 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { continue; }; - let attrib_to_write = match meta_item.name_or_empty() { - sym::prefix_nops => &mut prefix, - sym::entry_nops => &mut entry, + let attrib_to_write = match meta_item.name() { + Some(sym::prefix_nops) => &mut prefix, + Some(sym::entry_nops) => &mut entry, _ => { tcx.dcx().emit_err(errors::UnexpectedParameterName { span: item.span(), @@ -785,8 +792,7 @@ impl<'a> MixedExportNameAndNoMangleState<'a> { fn autodiff_attrs(tcx: TyCtxt<'_>, id: DefId) -> Option { let attrs = tcx.get_attrs(id, sym::rustc_autodiff); - let attrs = - attrs.filter(|attr| attr.name_or_empty() == sym::rustc_autodiff).collect::>(); + let attrs = attrs.filter(|attr| attr.has_name(sym::rustc_autodiff)).collect::>(); // check for exactly one autodiff attribute on placeholder functions. // There should only be one, since we generate a new placeholder per ad macro. diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index b33de8802d83..42cea5c86d4a 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -277,13 +277,13 @@ pub struct BinaryOutputToTty { #[derive(Diagnostic)] #[diag(codegen_ssa_ignoring_emit_path)] pub struct IgnoringEmitPath { - pub extension: String, + pub extension: &'static str, } #[derive(Diagnostic)] #[diag(codegen_ssa_ignoring_output)] pub struct IgnoringOutput { - pub extension: String, + pub extension: &'static str, } #[derive(Diagnostic)] diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index 67217927a872..5b2ed69535b9 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -2,7 +2,6 @@ #![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] -#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(assert_matches)] @@ -105,13 +104,19 @@ impl ModuleCodegen { emit_asm: bool, emit_ir: bool, outputs: &OutputFilenames, + invocation_temp: Option<&str>, ) -> CompiledModule { - let object = emit_obj.then(|| outputs.temp_path(OutputType::Object, Some(&self.name))); - let dwarf_object = emit_dwarf_obj.then(|| outputs.temp_path_dwo(Some(&self.name))); - let bytecode = emit_bc.then(|| outputs.temp_path(OutputType::Bitcode, Some(&self.name))); - let assembly = emit_asm.then(|| outputs.temp_path(OutputType::Assembly, Some(&self.name))); - let llvm_ir = - emit_ir.then(|| outputs.temp_path(OutputType::LlvmAssembly, Some(&self.name))); + let object = emit_obj + .then(|| outputs.temp_path_for_cgu(OutputType::Object, &self.name, invocation_temp)); + let dwarf_object = + emit_dwarf_obj.then(|| outputs.temp_path_dwo_for_cgu(&self.name, invocation_temp)); + let bytecode = emit_bc + .then(|| outputs.temp_path_for_cgu(OutputType::Bitcode, &self.name, invocation_temp)); + let assembly = emit_asm + .then(|| outputs.temp_path_for_cgu(OutputType::Assembly, &self.name, invocation_temp)); + let llvm_ir = emit_ir.then(|| { + outputs.temp_path_for_cgu(OutputType::LlvmAssembly, &self.name, invocation_temp) + }); CompiledModule { name: self.name.clone(), diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index 0758e5d04567..6a37889217ab 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -3,7 +3,7 @@ use std::iter; use rustc_index::IndexVec; use rustc_index::bit_set::DenseBitSet; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; -use rustc_middle::mir::{Local, UnwindTerminateReason, traversal}; +use rustc_middle::mir::{Body, Local, UnwindTerminateReason, traversal}; use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, HasTypingEnv, TyAndLayout}; use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypeFoldable, TypeVisitableExt}; use rustc_middle::{bug, mir, span_bug}; @@ -170,19 +170,29 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( ) { assert!(!instance.args.has_infer()); + let tcx = cx.tcx(); let llfn = cx.get_fn(instance); - let mir = cx.tcx().instance_mir(instance.def); + let mut mir = tcx.instance_mir(instance.def); let fn_abi = cx.fn_abi_of_instance(instance, ty::List::empty()); debug!("fn_abi: {:?}", fn_abi); - if cx.tcx().codegen_fn_attrs(instance.def_id()).flags.contains(CodegenFnAttrFlags::NAKED) { + if tcx.codegen_fn_attrs(instance.def_id()).flags.contains(CodegenFnAttrFlags::NAKED) { crate::mir::naked_asm::codegen_naked_asm::(cx, &mir, instance); return; } - let debug_context = cx.create_function_debug_context(instance, fn_abi, llfn, mir); + if tcx.features().ergonomic_clones() { + let monomorphized_mir = instance.instantiate_mir_and_normalize_erasing_regions( + tcx, + ty::TypingEnv::fully_monomorphized(), + ty::EarlyBinder::bind(mir.clone()), + ); + mir = tcx.arena.alloc(optimize_use_clone::(cx, monomorphized_mir)); + } + + let debug_context = cx.create_function_debug_context(instance, fn_abi, llfn, &mir); let start_llbb = Bx::append_block(cx, llfn, "start"); let mut start_bx = Bx::build(cx, start_llbb); @@ -194,7 +204,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( } let cleanup_kinds = - base::wants_new_eh_instructions(cx.tcx().sess).then(|| analyze::cleanup_kinds(mir)); + base::wants_new_eh_instructions(tcx.sess).then(|| analyze::cleanup_kinds(&mir)); let cached_llbbs: IndexVec> = mir.basic_blocks @@ -217,7 +227,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( cleanup_kinds, landing_pads: IndexVec::from_elem(None, &mir.basic_blocks), funclets: IndexVec::from_fn_n(|_| None, mir.basic_blocks.len()), - cold_blocks: find_cold_blocks(cx.tcx(), mir), + cold_blocks: find_cold_blocks(tcx, mir), locals: locals::Locals::empty(), debug_context, per_local_var_debug_info: None, @@ -233,7 +243,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( fx.compute_per_local_var_debug_info(&mut start_bx).unzip(); fx.per_local_var_debug_info = per_local_var_debug_info; - let traversal_order = traversal::mono_reachable_reverse_postorder(mir, cx.tcx(), instance); + let traversal_order = traversal::mono_reachable_reverse_postorder(mir, tcx, instance); let memory_locals = analyze::non_ssa_locals(&fx, &traversal_order); // Allocate variable and temp allocas @@ -310,6 +320,61 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( } } +// FIXME: Move this function to mir::transform when post-mono MIR passes land. +fn optimize_use_clone<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( + cx: &'a Bx::CodegenCx, + mut mir: Body<'tcx>, +) -> Body<'tcx> { + let tcx = cx.tcx(); + + if tcx.features().ergonomic_clones() { + for bb in mir.basic_blocks.as_mut() { + let mir::TerminatorKind::Call { + args, + destination, + target, + call_source: mir::CallSource::Use, + .. + } = &bb.terminator().kind + else { + continue; + }; + + // CallSource::Use calls always use 1 argument. + assert_eq!(args.len(), 1); + let arg = &args[0]; + + // These types are easily available from locals, so check that before + // doing DefId lookups to figure out what we're actually calling. + let arg_ty = arg.node.ty(&mir.local_decls, tcx); + + let ty::Ref(_region, inner_ty, mir::Mutability::Not) = *arg_ty.kind() else { continue }; + + if !tcx.type_is_copy_modulo_regions(cx.typing_env(), inner_ty) { + continue; + } + + let Some(arg_place) = arg.node.place() else { continue }; + + let destination_block = target.unwrap(); + + bb.statements.push(mir::Statement { + source_info: bb.terminator().source_info, + kind: mir::StatementKind::Assign(Box::new(( + *destination, + mir::Rvalue::Use(mir::Operand::Copy( + arg_place.project_deeper(&[mir::ProjectionElem::Deref], tcx), + )), + ))), + }); + + bb.terminator_mut().kind = mir::TerminatorKind::Goto { target: destination_block }; + } + } + + mir +} + /// Produces, for each argument, a `Value` pointing at the /// argument's value. As arguments are places, these are always /// indirect. diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index 7e355b6406ae..eade9e52de95 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -9,6 +9,7 @@ use rustc_middle::mir::{self, ConstValue}; use rustc_middle::ty::Ty; use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; use rustc_middle::{bug, span_bug}; +use rustc_session::config::OptLevel; use tracing::{debug, instrument}; use super::place::{PlaceRef, PlaceValue}; @@ -496,6 +497,18 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { _ => (tag_imm, bx.cx().immediate_backend_type(tag_op.layout)), }; + // Layout ensures that we only get here for cases where the discriminant + // value and the variant index match, since that's all `Niche` can encode. + // But for emphasis and debugging, let's double-check one anyway. + debug_assert_eq!( + self.layout + .ty + .discriminant_for_variant(bx.tcx(), untagged_variant) + .unwrap() + .val, + u128::from(untagged_variant.as_u32()), + ); + let relative_max = niche_variants.end().as_u32() - niche_variants.start().as_u32(); // We have a subrange `niche_start..=niche_end` inside `range`. @@ -537,6 +550,21 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { relative_discr, bx.cx().const_uint(tag_llty, relative_max as u64), ); + + // Thanks to parameter attributes and load metadata, LLVM already knows + // the general valid range of the tag. It's possible, though, for there + // to be an impossible value *in the middle*, which those ranges don't + // communicate, so it's worth an `assume` to let the optimizer know. + if niche_variants.contains(&untagged_variant) + && bx.cx().sess().opts.optimize != OptLevel::No + { + let impossible = + u64::from(untagged_variant.as_u32() - niche_variants.start().as_u32()); + let impossible = bx.cx().const_uint(tag_llty, impossible); + let ne = bx.icmp(IntPredicate::IntNE, relative_discr, impossible); + bx.assume(ne); + } + (is_niche, cast_tag, niche_variants.start().as_u32() as u128) }; @@ -553,7 +581,9 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { ); // In principle we could insert assumes on the possible range of `discr`, but - // currently in LLVM this seems to be a pessimization. + // currently in LLVM this isn't worth it because the original `tag` will + // have either a `range` parameter attribute or `!range` metadata, + // or come from a `transmute` that already `assume`d it. discr } diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs index 2b74c849f1ae..b600b8918dd0 100644 --- a/compiler/rustc_const_eval/src/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/check_consts/check.rs @@ -34,7 +34,7 @@ use crate::check_consts::is_fn_or_trait_safe_to_expose_on_stable; use crate::errors; type QualifResults<'mir, 'tcx, Q> = - rustc_mir_dataflow::ResultsCursor<'mir, 'tcx, FlowSensitiveAnalysis<'mir, 'mir, 'tcx, Q>>; + rustc_mir_dataflow::ResultsCursor<'mir, 'tcx, FlowSensitiveAnalysis<'mir, 'tcx, Q>>; #[derive(Copy, Clone, PartialEq, Eq, Debug)] enum ConstConditionsHold { diff --git a/compiler/rustc_const_eval/src/check_consts/resolver.rs b/compiler/rustc_const_eval/src/check_consts/resolver.rs index 8cee282311f0..9f7fcc509a58 100644 --- a/compiler/rustc_const_eval/src/check_consts/resolver.rs +++ b/compiler/rustc_const_eval/src/check_consts/resolver.rs @@ -22,17 +22,17 @@ use super::{ConstCx, Qualif, qualifs}; /// qualified immediately after it is borrowed or its address escapes. The borrow must allow for /// mutation, which includes shared borrows of places with interior mutability. The type of /// borrowed place must contain the qualif. -struct TransferFunction<'a, 'mir, 'tcx, Q> { - ccx: &'a ConstCx<'mir, 'tcx>, - state: &'a mut State, +struct TransferFunction<'mir, 'tcx, Q> { + ccx: &'mir ConstCx<'mir, 'tcx>, + state: &'mir mut State, _qualif: PhantomData, } -impl<'a, 'mir, 'tcx, Q> TransferFunction<'a, 'mir, 'tcx, Q> +impl<'mir, 'tcx, Q> TransferFunction<'mir, 'tcx, Q> where Q: Qualif, { - fn new(ccx: &'a ConstCx<'mir, 'tcx>, state: &'a mut State) -> Self { + fn new(ccx: &'mir ConstCx<'mir, 'tcx>, state: &'mir mut State) -> Self { TransferFunction { ccx, state, _qualif: PhantomData } } @@ -124,7 +124,7 @@ where } } -impl<'tcx, Q> Visitor<'tcx> for TransferFunction<'_, '_, 'tcx, Q> +impl<'tcx, Q> Visitor<'tcx> for TransferFunction<'_, 'tcx, Q> where Q: Qualif, { @@ -228,20 +228,20 @@ where } /// The dataflow analysis used to propagate qualifs on arbitrary CFGs. -pub(super) struct FlowSensitiveAnalysis<'a, 'mir, 'tcx, Q> { - ccx: &'a ConstCx<'mir, 'tcx>, +pub(super) struct FlowSensitiveAnalysis<'mir, 'tcx, Q> { + ccx: &'mir ConstCx<'mir, 'tcx>, _qualif: PhantomData, } -impl<'a, 'mir, 'tcx, Q> FlowSensitiveAnalysis<'a, 'mir, 'tcx, Q> +impl<'mir, 'tcx, Q> FlowSensitiveAnalysis<'mir, 'tcx, Q> where Q: Qualif, { - pub(super) fn new(_: Q, ccx: &'a ConstCx<'mir, 'tcx>) -> Self { + pub(super) fn new(_: Q, ccx: &'mir ConstCx<'mir, 'tcx>) -> Self { FlowSensitiveAnalysis { ccx, _qualif: PhantomData } } - fn transfer_function(&self, state: &'a mut State) -> TransferFunction<'a, 'mir, 'tcx, Q> { + fn transfer_function(&self, state: &'mir mut State) -> TransferFunction<'mir, 'tcx, Q> { TransferFunction::::new(self.ccx, state) } } @@ -313,7 +313,7 @@ impl JoinSemiLattice for State { } } -impl<'tcx, Q> Analysis<'tcx> for FlowSensitiveAnalysis<'_, '_, 'tcx, Q> +impl<'tcx, Q> Analysis<'tcx> for FlowSensitiveAnalysis<'_, 'tcx, Q> where Q: Qualif, { diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index e2675e2f4c90..6472aaa57581 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -6,7 +6,7 @@ use rustc_abi::WrappingRange; use rustc_errors::codes::*; use rustc_errors::{ Diag, DiagArgValue, DiagCtxtHandle, DiagMessage, Diagnostic, EmissionGuarantee, Level, - MultiSpan, SubdiagMessageOp, Subdiagnostic, + MultiSpan, Subdiagnostic, }; use rustc_hir::ConstContext; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; @@ -290,11 +290,7 @@ pub struct FrameNote { } impl Subdiagnostic for FrameNote { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { diag.arg("times", self.times); diag.arg("where_", self.where_); diag.arg("instance", self.instance); @@ -302,7 +298,7 @@ impl Subdiagnostic for FrameNote { if self.has_label && !self.span.is_dummy() { span.push_span_label(self.span, fluent::const_eval_frame_note_last); } - let msg = f(diag, fluent::const_eval_frame_note.into()); + let msg = diag.eagerly_translate(fluent::const_eval_frame_note); diag.span_note(span, msg); } } diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index c1948e9f31f1..b69bc0918be8 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -268,7 +268,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { /// Call this on things you got out of the MIR (so it is as generic as the current /// stack frame), to bring it into the proper environment for this interpreter. - pub(super) fn instantiate_from_current_frame_and_normalize_erasing_regions< + pub fn instantiate_from_current_frame_and_normalize_erasing_regions< T: TypeFoldable>, >( &self, @@ -279,9 +279,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { /// Call this on things you got out of the MIR (so it is as generic as the provided /// stack frame), to bring it into the proper environment for this interpreter. - pub(super) fn instantiate_from_frame_and_normalize_erasing_regions< - T: TypeFoldable>, - >( + pub fn instantiate_from_frame_and_normalize_erasing_regions>>( &self, frame: &Frame<'tcx, M::Provenance, M::FrameExtra>, value: T, diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs index e4b2fe5d153e..8f0cb197c445 100644 --- a/compiler/rustc_const_eval/src/interpret/intern.rs +++ b/compiler/rustc_const_eval/src/interpret/intern.rs @@ -30,6 +30,7 @@ use super::{ AllocId, Allocation, InterpCx, MPlaceTy, Machine, MemoryKind, PlaceTy, err_ub, interp_ok, }; use crate::const_eval; +use crate::const_eval::DummyMachine; use crate::errors::NestedStaticInThreadLocal; pub trait CompileTimeMachine<'tcx, T> = Machine< @@ -323,14 +324,17 @@ pub fn intern_const_alloc_for_constprop<'tcx, T, M: CompileTimeMachine<'tcx, T>> interp_ok(()) } -impl<'tcx, M: super::intern::CompileTimeMachine<'tcx, !>> InterpCx<'tcx, M> { +impl<'tcx> InterpCx<'tcx, DummyMachine> { /// A helper function that allocates memory for the layout given and gives you access to mutate /// it. Once your own mutation code is done, the backing `Allocation` is removed from the /// current `Memory` and interned as read-only into the global memory. pub fn intern_with_temp_alloc( &mut self, layout: TyAndLayout<'tcx>, - f: impl FnOnce(&mut InterpCx<'tcx, M>, &PlaceTy<'tcx, M::Provenance>) -> InterpResult<'tcx, ()>, + f: impl FnOnce( + &mut InterpCx<'tcx, DummyMachine>, + &PlaceTy<'tcx, CtfeProvenance>, + ) -> InterpResult<'tcx, ()>, ) -> InterpResult<'tcx, AllocId> { // `allocate` picks a fresh AllocId that we will associate with its data below. let dest = self.allocate(layout, MemoryKind::Stack)?; diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs index e03849c32f94..da52d60ae59f 100644 --- a/compiler/rustc_const_eval/src/lib.rs +++ b/compiler/rustc_const_eval/src/lib.rs @@ -1,7 +1,6 @@ // tidy-alphabetical-start #![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] -#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![doc(rust_logo)] #![feature(assert_matches)] #![feature(box_patterns)] diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml index fcaf2750507d..f48c73b13b96 100644 --- a/compiler/rustc_data_structures/Cargo.toml +++ b/compiler/rustc_data_structures/Cargo.toml @@ -14,7 +14,7 @@ indexmap = "2.4.0" jobserver_crate = { version = "0.1.28", package = "jobserver" } measureme = "12.0.1" rustc-hash = "2.0.0" -rustc-rayon = { version = "0.5.1", features = ["indexmap"] } +rustc-rayon-core = { version = "0.5.0" } rustc-stable-hash = { version = "0.1.0", features = ["nightly"] } rustc_arena = { path = "../rustc_arena" } rustc_graphviz = { path = "../rustc_graphviz" } diff --git a/compiler/rustc_data_structures/src/marker.rs b/compiler/rustc_data_structures/src/marker.rs index 64c64bfa3c29..5f07cfef1335 100644 --- a/compiler/rustc_data_structures/src/marker.rs +++ b/compiler/rustc_data_structures/src/marker.rs @@ -1,13 +1,13 @@ use std::alloc::Allocator; -#[rustc_on_unimplemented(message = "`{Self}` doesn't implement `DynSend`. \ +#[diagnostic::on_unimplemented(message = "`{Self}` doesn't implement `DynSend`. \ Add it to `rustc_data_structures::marker` or use `IntoDynSyncSend` if it's already `Send`")] // This is an auto trait for types which can be sent across threads if `sync::is_dyn_thread_safe()` // is true. These types can be wrapped in a `FromDyn` to get a `Send` type. Wrapping a // `Send` type in `IntoDynSyncSend` will create a `DynSend` type. pub unsafe auto trait DynSend {} -#[rustc_on_unimplemented(message = "`{Self}` doesn't implement `DynSync`. \ +#[diagnostic::on_unimplemented(message = "`{Self}` doesn't implement `DynSync`. \ Add it to `rustc_data_structures::marker` or use `IntoDynSyncSend` if it's already `Sync`")] // This is an auto trait for types which can be shared across threads if `sync::is_dyn_thread_safe()` // is true. These types can be wrapped in a `FromDyn` to get a `Sync` type. Wrapping a @@ -179,6 +179,12 @@ impl FromDyn { FromDyn(val) } + #[inline(always)] + pub fn derive(&self, val: O) -> FromDyn { + // We already did the check for `sync::is_dyn_thread_safe()` when creating `Self` + FromDyn(val) + } + #[inline(always)] pub fn into_inner(self) -> T { self.0 @@ -200,6 +206,13 @@ impl std::ops::Deref for FromDyn { } } +impl std::ops::DerefMut for FromDyn { + #[inline(always)] + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + // A wrapper to convert a struct that is already a `Send` or `Sync` into // an instance of `DynSend` and `DynSync`, since the compiler cannot infer // it automatically in some cases. (e.g. Box) diff --git a/compiler/rustc_data_structures/src/obligation_forest/mod.rs b/compiler/rustc_data_structures/src/obligation_forest/mod.rs index f63b201742d9..2c62034c6e87 100644 --- a/compiler/rustc_data_structures/src/obligation_forest/mod.rs +++ b/compiler/rustc_data_structures/src/obligation_forest/mod.rs @@ -315,7 +315,7 @@ mod helper { use super::*; pub(super) type ObligationTreeIdGenerator = impl Iterator; impl ObligationForest { - #[cfg_attr(not(bootstrap), define_opaque(ObligationTreeIdGenerator))] + #[define_opaque(ObligationTreeIdGenerator)] pub fn new() -> ObligationForest { ObligationForest { nodes: vec![], diff --git a/compiler/rustc_data_structures/src/sync/freeze.rs b/compiler/rustc_data_structures/src/sync/freeze.rs index 9720b22ea7d1..6338afb92c34 100644 --- a/compiler/rustc_data_structures/src/sync/freeze.rs +++ b/compiler/rustc_data_structures/src/sync/freeze.rs @@ -88,7 +88,7 @@ impl FreezeLock { #[inline] #[track_caller] pub fn write(&self) -> FreezeWriteGuard<'_, T> { - self.try_write().expect("still mutable") + self.try_write().expect("data should not be frozen if we're still attempting to mutate it") } #[inline] diff --git a/compiler/rustc_data_structures/src/sync/parallel.rs b/compiler/rustc_data_structures/src/sync/parallel.rs index 8ef8a3f35856..ba3c85ef5b15 100644 --- a/compiler/rustc_data_structures/src/sync/parallel.rs +++ b/compiler/rustc_data_structures/src/sync/parallel.rs @@ -7,7 +7,6 @@ use std::any::Any; use std::panic::{AssertUnwindSafe, catch_unwind, resume_unwind}; use parking_lot::Mutex; -use rayon::iter::{FromParallelIterator, IntoParallelIterator, ParallelIterator}; use crate::FatalErrorMarker; use crate::sync::{DynSend, DynSync, FromDyn, IntoDynSyncSend, mode}; @@ -97,11 +96,11 @@ macro_rules! parallel { // This function only works when `mode::is_dyn_thread_safe()`. pub fn scope<'scope, OP, R>(op: OP) -> R where - OP: FnOnce(&rayon::Scope<'scope>) -> R + DynSend, + OP: FnOnce(&rayon_core::Scope<'scope>) -> R + DynSend, R: DynSend, { let op = FromDyn::from(op); - rayon::scope(|s| FromDyn::from(op.into_inner()(s))).into_inner() + rayon_core::scope(|s| FromDyn::from(op.into_inner()(s))).into_inner() } #[inline] @@ -114,7 +113,7 @@ where let oper_a = FromDyn::from(oper_a); let oper_b = FromDyn::from(oper_b); let (a, b) = parallel_guard(|guard| { - rayon::join( + rayon_core::join( move || guard.run(move || FromDyn::from(oper_a.into_inner()())), move || guard.run(move || FromDyn::from(oper_b.into_inner()())), ) @@ -125,56 +124,103 @@ where } } -pub fn par_for_each_in + IntoParallelIterator>( +fn par_slice( + items: &mut [I], + guard: &ParallelGuard, + for_each: impl Fn(&mut I) + DynSync + DynSend, +) { + struct State<'a, F> { + for_each: FromDyn, + guard: &'a ParallelGuard, + group: usize, + } + + fn par_rec( + items: &mut [I], + state: &State<'_, F>, + ) { + if items.len() <= state.group { + for item in items { + state.guard.run(|| (state.for_each)(item)); + } + } else { + let (left, right) = items.split_at_mut(items.len() / 2); + let mut left = state.for_each.derive(left); + let mut right = state.for_each.derive(right); + rayon_core::join(move || par_rec(*left, state), move || par_rec(*right, state)); + } + } + + let state = State { + for_each: FromDyn::from(for_each), + guard, + group: std::cmp::max(items.len() / 128, 1), + }; + par_rec(items, &state) +} + +pub fn par_for_each_in>( t: T, - for_each: impl Fn(I) + DynSync + DynSend, + for_each: impl Fn(&I) + DynSync + DynSend, ) { parallel_guard(|guard| { if mode::is_dyn_thread_safe() { - let for_each = FromDyn::from(for_each); - t.into_par_iter().for_each(|i| { - guard.run(|| for_each(i)); - }); + let mut items: Vec<_> = t.into_iter().collect(); + par_slice(&mut items, guard, |i| for_each(&*i)) } else { t.into_iter().for_each(|i| { - guard.run(|| for_each(i)); + guard.run(|| for_each(&i)); }); } }); } -pub fn try_par_for_each_in< - T: IntoIterator + IntoParallelIterator::Item>, - E: Send, ->( +/// This runs `for_each` in parallel for each iterator item. If one or more of the +/// `for_each` calls returns `Err`, the function will also return `Err`. The error returned +/// will be non-deterministic, but this is expected to be used with `ErrorGuaranteed` which +/// are all equivalent. +pub fn try_par_for_each_in( t: T, - for_each: impl Fn(::Item) -> Result<(), E> + DynSync + DynSend, -) -> Result<(), E> { + for_each: impl Fn(&::Item) -> Result<(), E> + DynSync + DynSend, +) -> Result<(), E> +where + ::Item: DynSend, +{ parallel_guard(|guard| { if mode::is_dyn_thread_safe() { - let for_each = FromDyn::from(for_each); - t.into_par_iter() - .filter_map(|i| guard.run(|| for_each(i))) - .reduce(|| Ok(()), Result::and) + let mut items: Vec<_> = t.into_iter().collect(); + + let error = Mutex::new(None); + + par_slice(&mut items, guard, |i| { + if let Err(err) = for_each(&*i) { + *error.lock() = Some(err); + } + }); + + if let Some(err) = error.into_inner() { Err(err) } else { Ok(()) } } else { - t.into_iter().filter_map(|i| guard.run(|| for_each(i))).fold(Ok(()), Result::and) + t.into_iter().filter_map(|i| guard.run(|| for_each(&i))).fold(Ok(()), Result::and) } }) } -pub fn par_map< - I, - T: IntoIterator + IntoParallelIterator, - R: std::marker::Send, - C: FromIterator + FromParallelIterator, ->( +pub fn par_map, R: DynSend, C: FromIterator>( t: T, map: impl Fn(I) -> R + DynSync + DynSend, ) -> C { parallel_guard(|guard| { if mode::is_dyn_thread_safe() { let map = FromDyn::from(map); - t.into_par_iter().filter_map(|i| guard.run(|| map(i))).collect() + + let mut items: Vec<(Option, Option)> = + t.into_iter().map(|i| (Some(i), None)).collect(); + + par_slice(&mut items, guard, |i| { + i.1 = Some(map(i.0.take().unwrap())); + }); + + items.into_iter().filter_map(|i| i.1).collect() } else { t.into_iter().filter_map(|i| guard.run(|| map(i))).collect() } diff --git a/compiler/rustc_data_structures/src/unord.rs b/compiler/rustc_data_structures/src/unord.rs index baa66cd7c852..3d44fb1fd48d 100644 --- a/compiler/rustc_data_structures/src/unord.rs +++ b/compiler/rustc_data_structures/src/unord.rs @@ -109,6 +109,16 @@ impl> UnordItems { pub fn collect>>(self) -> C { self.into() } + + /// If the iterator has only one element, returns it, otherwise returns `None`. + #[track_caller] + pub fn get_only(mut self) -> Option { + let item = self.0.next(); + if self.0.next().is_some() { + return None; + } + item + } } impl UnordItems> { diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs index 381309f83b2c..a03834c519d5 100644 --- a/compiler/rustc_driver/src/lib.rs +++ b/compiler/rustc_driver/src/lib.rs @@ -3,7 +3,6 @@ // tidy-alphabetical-start #![allow(internal_features)] -#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![doc(rust_logo)] #![feature(rustdoc_internals)] // tidy-alphabetical-end diff --git a/compiler/rustc_driver_impl/Cargo.toml b/compiler/rustc_driver_impl/Cargo.toml index de643355f5f4..c823d11126e2 100644 --- a/compiler/rustc_driver_impl/Cargo.toml +++ b/compiler/rustc_driver_impl/Cargo.toml @@ -4,6 +4,7 @@ version = "0.0.0" edition = "2024" [dependencies] +jiff = { version = "0.2.5", default-features = false, features = ["std"] } # tidy-alphabetical-start rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } @@ -50,7 +51,6 @@ rustc_trait_selection = { path = "../rustc_trait_selection" } rustc_ty_utils = { path = "../rustc_ty_utils" } serde_json = "1.0.59" shlex = "1.0" -time = { version = "0.3.36", default-features = false, features = ["alloc", "formatting", "macros"] } tracing = { version = "0.1.35" } # tidy-alphabetical-end diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 595ac1edd289..40cc82727a55 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -7,7 +7,6 @@ // tidy-alphabetical-start #![allow(internal_features)] #![allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable -#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(decl_macro)] @@ -30,7 +29,7 @@ use std::path::{Path, PathBuf}; use std::process::{self, Command, Stdio}; use std::sync::OnceLock; use std::sync::atomic::{AtomicBool, Ordering}; -use std::time::{Instant, SystemTime}; +use std::time::Instant; use std::{env, str}; use rustc_ast as ast; @@ -66,8 +65,6 @@ use rustc_span::FileName; use rustc_span::def_id::LOCAL_CRATE; use rustc_target::json::ToJson; use rustc_target::spec::{Target, TargetTuple}; -use time::OffsetDateTime; -use time::macros::format_description; use tracing::trace; #[allow(unused_macros)] @@ -264,6 +261,7 @@ pub fn run_compiler(at_args: &[String], callbacks: &mut (dyn Callbacks + Send)) hash_untracked_state: None, register_lints: None, override_queries: None, + extra_symbols: Vec::new(), make_codegen_backend: None, registry: diagnostics_registry(), using_internal_features: &USING_INTERNAL_FEATURES, @@ -348,10 +346,6 @@ pub fn run_compiler(at_args: &[String], callbacks: &mut (dyn Callbacks + Send)) // Make sure name resolution and macro expansion is run. let _ = tcx.resolver_for_lowering(); - if let Some(metrics_dir) = &sess.opts.unstable_opts.metrics_dir { - dump_feature_usage_metrics(tcx, metrics_dir); - } - if callbacks.after_expansion(compiler, tcx) == Compilation::Stop { return early_exit(); } @@ -370,6 +364,10 @@ pub fn run_compiler(at_args: &[String], callbacks: &mut (dyn Callbacks + Send)) tcx.ensure_ok().analysis(()); + if let Some(metrics_dir) = &sess.opts.unstable_opts.metrics_dir { + dump_feature_usage_metrics(tcx, metrics_dir); + } + if callbacks.after_analysis(compiler, tcx) == Compilation::Stop { return early_exit(); } @@ -1300,13 +1298,8 @@ fn ice_path_with_config(config: Option<&UnstableOptions>) -> &'static Option isize; } # fn main() {} diff --git a/compiler/rustc_error_codes/src/error_codes/E0756.md b/compiler/rustc_error_codes/src/error_codes/E0756.md index ffdc421aab58..aadde038d12c 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0756.md +++ b/compiler/rustc_error_codes/src/error_codes/E0756.md @@ -6,7 +6,7 @@ Erroneous code example: ```compile_fail,E0756 #![feature(ffi_const)] -#[ffi_const] // error! +#[unsafe(ffi_const)] // error! pub fn foo() {} # fn main() {} ``` @@ -18,7 +18,7 @@ which have no side effects except for their return value: #![feature(ffi_const)] extern "C" { - #[ffi_const] // ok! + #[unsafe(ffi_const)] // ok! pub fn strlen(s: *const i8) -> i32; } # fn main() {} diff --git a/compiler/rustc_error_codes/src/error_codes/E0757.md b/compiler/rustc_error_codes/src/error_codes/E0757.md index 41b06b23c4f2..fb75b028f45c 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0757.md +++ b/compiler/rustc_error_codes/src/error_codes/E0757.md @@ -6,8 +6,9 @@ Erroneous code example: #![feature(ffi_const, ffi_pure)] extern "C" { - #[ffi_const] - #[ffi_pure] // error: `#[ffi_const]` function cannot be `#[ffi_pure]` + #[unsafe(ffi_const)] + #[unsafe(ffi_pure)] + //~^ ERROR `#[ffi_const]` function cannot be `#[ffi_pure]` pub fn square(num: i32) -> i32; } ``` @@ -19,7 +20,7 @@ As `ffi_const` provides stronger guarantees than `ffi_pure`, remove the #![feature(ffi_const)] extern "C" { - #[ffi_const] + #[unsafe(ffi_const)] pub fn square(num: i32) -> i32; } ``` diff --git a/compiler/rustc_error_codes/src/lib.rs b/compiler/rustc_error_codes/src/lib.rs index dfeef5a957d6..2488d870899c 100644 --- a/compiler/rustc_error_codes/src/lib.rs +++ b/compiler/rustc_error_codes/src/lib.rs @@ -397,7 +397,7 @@ E0618: 0618, E0619: 0619, E0620: 0620, E0621: 0621, -E0622: 0622, +E0622: 0622, // REMOVED: rustc-intrinsic ABI was removed E0623: 0623, E0624: 0624, E0625: 0625, diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs index 39e78ae88416..3c6df147b1ba 100644 --- a/compiler/rustc_error_messages/src/lib.rs +++ b/compiler/rustc_error_messages/src/lib.rs @@ -208,7 +208,7 @@ pub type LazyFallbackBundle = Arc Fluent /// Return the default `FluentBundle` with standard "en-US" diagnostic messages. #[instrument(level = "trace", skip(resources))] -#[cfg_attr(not(bootstrap), define_opaque(LazyFallbackBundle))] +#[define_opaque(LazyFallbackBundle)] pub fn fallback_fluent_bundle( resources: Vec<&'static str>, with_directionality_markers: bool, diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 794502d7aaee..539ecfbb42e2 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -181,22 +181,9 @@ where Self: Sized, { /// Add a subdiagnostic to an existing diagnostic. - fn add_to_diag(self, diag: &mut Diag<'_, G>) { - self.add_to_diag_with(diag, &|_, m| m); - } - - /// Add a subdiagnostic to an existing diagnostic where `f` is invoked on every message used - /// (to optionally perform eager translation). - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - f: &F, - ); + fn add_to_diag(self, diag: &mut Diag<'_, G>); } -pub trait SubdiagMessageOp = - Fn(&mut Diag<'_, G>, SubdiagMessage) -> SubdiagMessage; - /// Trait implemented by lint types. This should not be implemented manually. Instead, use /// `#[derive(LintDiagnostic)]` -- see [rustc_macros::LintDiagnostic]. #[rustc_diagnostic_item = "LintDiagnostic"] @@ -647,9 +634,9 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> { #[rustc_lint_diagnostics] pub fn note_expected_found( &mut self, - expected_label: &dyn fmt::Display, + expected_label: &str, expected: DiagStyledString, - found_label: &dyn fmt::Display, + found_label: &str, found: DiagStyledString, ) -> &mut Self { self.note_expected_found_extra( @@ -665,9 +652,9 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> { #[rustc_lint_diagnostics] pub fn note_expected_found_extra( &mut self, - expected_label: &dyn fmt::Display, + expected_label: &str, expected: DiagStyledString, - found_label: &dyn fmt::Display, + found_label: &str, found: DiagStyledString, expected_extra: DiagStyledString, found_extra: DiagStyledString, @@ -1227,15 +1214,21 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> { /// interpolated variables). #[rustc_lint_diagnostics] pub fn subdiagnostic(&mut self, subdiagnostic: impl Subdiagnostic) -> &mut Self { - let dcx = self.dcx; - subdiagnostic.add_to_diag_with(self, &|diag, msg| { - let args = diag.args.iter(); - let msg = diag.subdiagnostic_message_to_diagnostic_message(msg); - dcx.eagerly_translate(msg, args) - }); + subdiagnostic.add_to_diag(self); self } + /// Fluent variables are not namespaced from each other, so when + /// `Diagnostic`s and `Subdiagnostic`s use the same variable name, + /// one value will clobber the other. Eagerly translating the + /// diagnostic uses the variables defined right then, before the + /// clobbering occurs. + pub fn eagerly_translate(&self, msg: impl Into) -> SubdiagMessage { + let args = self.args.iter(); + let msg = self.subdiagnostic_message_to_diagnostic_message(msg.into()); + self.dcx.eagerly_translate(msg, args) + } + with_fn! { with_span, /// Add a span. #[rustc_lint_diagnostics] diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs index cb2e1769fa1c..8b59ba9984c1 100644 --- a/compiler/rustc_errors/src/diagnostic_impls.rs +++ b/compiler/rustc_errors/src/diagnostic_impls.rs @@ -19,7 +19,7 @@ use {rustc_ast as ast, rustc_hir as hir}; use crate::diagnostic::DiagLocation; use crate::{ Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, ErrCode, IntoDiagArg, Level, - SubdiagMessageOp, Subdiagnostic, fluent_generated as fluent, + Subdiagnostic, fluent_generated as fluent, }; pub struct DiagArgFromDisplay<'a>(pub &'a dyn fmt::Display); @@ -384,11 +384,7 @@ pub struct SingleLabelManySpans { pub label: &'static str, } impl Subdiagnostic for SingleLabelManySpans { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { diag.span_labels(self.spans, self.label); } } diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index f5f7618285e1..c0c5dba46772 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -47,7 +47,7 @@ pub use codes::*; pub use diagnostic::{ BugAbort, Diag, DiagArg, DiagArgMap, DiagArgName, DiagArgValue, DiagInner, DiagStyledString, Diagnostic, EmissionGuarantee, FatalAbort, IntoDiagArg, LintDiagnostic, StringPart, Subdiag, - SubdiagMessageOp, Subdiagnostic, + Subdiagnostic, }; pub use diagnostic_impls::{ DiagArgFromDisplay, DiagSymbolList, ElidedLifetimeInPathSubdiag, ExpectedLifetimeParameter, @@ -589,7 +589,8 @@ struct DiagCtxtInner { /// add more information). All stashed diagnostics must be emitted with /// `emit_stashed_diagnostics` by the time the `DiagCtxtInner` is dropped, /// otherwise an assertion failure will occur. - stashed_diagnostics: FxIndexMap<(Span, StashKey), (DiagInner, Option)>, + stashed_diagnostics: + FxIndexMap)>>, future_breakage_diagnostics: Vec, @@ -912,8 +913,12 @@ impl<'a> DiagCtxtHandle<'a> { // FIXME(Centril, #69537): Consider reintroducing panic on overwriting a stashed diagnostic // if/when we have a more robust macro-friendly replacement for `(span, key)` as a key. // See the PR for a discussion. - let key = (span.with_parent(None), key); - self.inner.borrow_mut().stashed_diagnostics.insert(key, (diag, guar)); + self.inner + .borrow_mut() + .stashed_diagnostics + .entry(key) + .or_default() + .insert(span.with_parent(None), (diag, guar)); guar } @@ -922,9 +927,10 @@ impl<'a> DiagCtxtHandle<'a> { /// and [`StashKey`] as the key. Panics if the found diagnostic is an /// error. pub fn steal_non_err(self, span: Span, key: StashKey) -> Option> { - let key = (span.with_parent(None), key); // FIXME(#120456) - is `swap_remove` correct? - let (diag, guar) = self.inner.borrow_mut().stashed_diagnostics.swap_remove(&key)?; + let (diag, guar) = self.inner.borrow_mut().stashed_diagnostics.get_mut(&key).and_then( + |stashed_diagnostics| stashed_diagnostics.swap_remove(&span.with_parent(None)), + )?; assert!(!diag.is_error()); assert!(guar.is_none()); Some(Diag::new_diagnostic(self, diag)) @@ -943,9 +949,10 @@ impl<'a> DiagCtxtHandle<'a> { where F: FnMut(&mut Diag<'_>), { - let key = (span.with_parent(None), key); // FIXME(#120456) - is `swap_remove` correct? - let err = self.inner.borrow_mut().stashed_diagnostics.swap_remove(&key); + let err = self.inner.borrow_mut().stashed_diagnostics.get_mut(&key).and_then( + |stashed_diagnostics| stashed_diagnostics.swap_remove(&span.with_parent(None)), + ); err.map(|(err, guar)| { // The use of `::` is safe because level is `Level::Error`. assert_eq!(err.level, Error); @@ -966,9 +973,10 @@ impl<'a> DiagCtxtHandle<'a> { key: StashKey, new_err: Diag<'_>, ) -> ErrorGuaranteed { - let key = (span.with_parent(None), key); // FIXME(#120456) - is `swap_remove` correct? - let old_err = self.inner.borrow_mut().stashed_diagnostics.swap_remove(&key); + let old_err = self.inner.borrow_mut().stashed_diagnostics.get_mut(&key).and_then( + |stashed_diagnostics| stashed_diagnostics.swap_remove(&span.with_parent(None)), + ); match old_err { Some((old_err, guar)) => { assert_eq!(old_err.level, Error); @@ -983,7 +991,14 @@ impl<'a> DiagCtxtHandle<'a> { } pub fn has_stashed_diagnostic(&self, span: Span, key: StashKey) -> bool { - self.inner.borrow().stashed_diagnostics.get(&(span.with_parent(None), key)).is_some() + let inner = self.inner.borrow(); + if let Some(stashed_diagnostics) = inner.stashed_diagnostics.get(&key) + && !stashed_diagnostics.is_empty() + { + stashed_diagnostics.contains_key(&span.with_parent(None)) + } else { + false + } } /// Emit all stashed diagnostics. @@ -997,7 +1012,11 @@ impl<'a> DiagCtxtHandle<'a> { let inner = self.inner.borrow(); inner.err_guars.len() + inner.lint_err_guars.len() - + inner.stashed_diagnostics.values().filter(|(_diag, guar)| guar.is_some()).count() + + inner + .stashed_diagnostics + .values() + .map(|a| a.values().filter(|(_, guar)| guar.is_some()).count()) + .sum::() } /// This excludes lint errors and delayed bugs. Unless absolutely @@ -1486,16 +1505,18 @@ impl DiagCtxtInner { fn emit_stashed_diagnostics(&mut self) -> Option { let mut guar = None; let has_errors = !self.err_guars.is_empty(); - for (_, (diag, _guar)) in std::mem::take(&mut self.stashed_diagnostics).into_iter() { - if !diag.is_error() { - // Unless they're forced, don't flush stashed warnings when - // there are errors, to avoid causing warning overload. The - // stash would've been stolen already if it were important. - if !diag.is_force_warn() && has_errors { - continue; + for (_, stashed_diagnostics) in std::mem::take(&mut self.stashed_diagnostics).into_iter() { + for (_, (diag, _guar)) in stashed_diagnostics { + if !diag.is_error() { + // Unless they're forced, don't flush stashed warnings when + // there are errors, to avoid causing warning overload. The + // stash would've been stolen already if it were important. + if !diag.is_force_warn() && has_errors { + continue; + } } + guar = guar.or(self.emit_diagnostic(diag, None)); } - guar = guar.or(self.emit_diagnostic(diag, None)); } guar } @@ -1688,6 +1709,7 @@ impl DiagCtxtInner { if let Some((_diag, guar)) = self .stashed_diagnostics .values() + .flat_map(|stashed_diagnostics| stashed_diagnostics.values()) .find(|(diag, guar)| guar.is_some() && diag.is_lint.is_none()) { *guar @@ -1700,13 +1722,9 @@ impl DiagCtxtInner { fn has_errors(&self) -> Option { self.err_guars.get(0).copied().or_else(|| self.lint_err_guars.get(0).copied()).or_else( || { - if let Some((_diag, guar)) = - self.stashed_diagnostics.values().find(|(_diag, guar)| guar.is_some()) - { - *guar - } else { - None - } + self.stashed_diagnostics.values().find_map(|stashed_diagnostics| { + stashed_diagnostics.values().find_map(|(_, guar)| *guar) + }) }, ) } diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index d14e476ba322..f5eaf7d616b2 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -824,10 +824,10 @@ impl SyntaxExtension { return Err(item.span); } - match item.name_or_empty() { - sym::no => Ok(CollapseMacroDebuginfo::No), - sym::external => Ok(CollapseMacroDebuginfo::External), - sym::yes => Ok(CollapseMacroDebuginfo::Yes), + match item.name() { + Some(sym::no) => Ok(CollapseMacroDebuginfo::No), + Some(sym::external) => Ok(CollapseMacroDebuginfo::External), + Some(sym::yes) => Ok(CollapseMacroDebuginfo::Yes), _ => Err(item.path.span), } } @@ -1102,7 +1102,7 @@ pub trait ResolverExpand { /// HIR proc macros items back to their harness items. fn declare_proc_macro(&mut self, id: NodeId); - fn append_stripped_cfg_item(&mut self, parent_node: NodeId, name: Ident, cfg: ast::MetaItem); + fn append_stripped_cfg_item(&mut self, parent_node: NodeId, ident: Ident, cfg: ast::MetaItem); /// Tools registered with `#![register_tool]` and used by tool attributes and lints. fn registered_tools(&self) -> &RegisteredTools; diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs index f68172c1f67c..6d616cf84bbd 100644 --- a/compiler/rustc_expand/src/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -230,6 +230,7 @@ impl<'a> ExtCtxt<'a> { self.pat_ident(sp, ident) }; let local = P(ast::Local { + super_: None, pat, ty, id: ast::DUMMY_NODE_ID, @@ -245,6 +246,7 @@ impl<'a> ExtCtxt<'a> { /// Generates `let _: Type;`, which is usually used for type assertions. pub fn stmt_let_type_only(&self, span: Span, ty: P) -> ast::Stmt { let local = P(ast::Local { + super_: None, pat: self.pat_wild(span), ty: Some(ty), id: ast::DUMMY_NODE_ID, diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index bcc2703c39b3..c70e259b2cd8 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -237,18 +237,6 @@ impl<'a> StripUnconfigured<'a> { inner = self.configure_tokens(&inner); Some(AttrTokenTree::Delimited(sp, spacing, delim, inner)) } - AttrTokenTree::Token( - Token { - kind: - TokenKind::NtIdent(..) - | TokenKind::NtLifetime(..) - | TokenKind::Interpolated(..), - .. - }, - _, - ) => { - panic!("Nonterminal should have been flattened: {:?}", tree); - } AttrTokenTree::Token( Token { kind: TokenKind::OpenDelim(_) | TokenKind::CloseDelim(_), .. }, _, diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index bca846d2ec42..1e26d6681943 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -1169,9 +1169,9 @@ trait InvocationCollectorNode: HasAttrs + HasNodeId + Sized { collector.cx.dcx().emit_err(RemoveNodeNotSupported { span, descr: Self::descr() }); } - /// All of the names (items) declared by this node. + /// All of the identifiers (items) declared by this node. /// This is an approximation and should only be used for diagnostics. - fn declared_names(&self) -> Vec { + fn declared_idents(&self) -> Vec { vec![] } } @@ -1306,7 +1306,7 @@ impl InvocationCollectorNode for P { res } - fn declared_names(&self) -> Vec { + fn declared_idents(&self) -> Vec { if let ItemKind::Use(ut) = &self.kind { fn collect_use_tree_leaves(ut: &ast::UseTree, idents: &mut Vec) { match &ut.kind { @@ -2053,25 +2053,25 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { ) -> Node::OutputTy { loop { return match self.take_first_attr(&mut node) { - Some((attr, pos, derives)) => match attr.name_or_empty() { - sym::cfg => { + Some((attr, pos, derives)) => match attr.name() { + Some(sym::cfg) => { let (res, meta_item) = self.expand_cfg_true(&mut node, attr, pos); if res { continue; } if let Some(meta_item) = meta_item { - for name in node.declared_names() { + for ident in node.declared_idents() { self.cx.resolver.append_stripped_cfg_item( self.cx.current_expansion.lint_node_id, - name, + ident, meta_item.clone(), ) } } Default::default() } - sym::cfg_attr => { + Some(sym::cfg_attr) => { self.expand_cfg_attr(&mut node, &attr, pos); continue; } @@ -2144,8 +2144,8 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { ) { loop { return match self.take_first_attr(node) { - Some((attr, pos, derives)) => match attr.name_or_empty() { - sym::cfg => { + Some((attr, pos, derives)) => match attr.name() { + Some(sym::cfg) => { let span = attr.span; if self.expand_cfg_true(node, attr, pos).0 { continue; @@ -2154,7 +2154,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { node.expand_cfg_false(self, pos, span); continue; } - sym::cfg_attr => { + Some(sym::cfg_attr) => { self.expand_cfg_attr(node, &attr, pos); continue; } diff --git a/compiler/rustc_expand/src/mbe/diagnostics.rs b/compiler/rustc_expand/src/mbe/diagnostics.rs index e60a9e83184f..b663e959744f 100644 --- a/compiler/rustc_expand/src/mbe/diagnostics.rs +++ b/compiler/rustc_expand/src/mbe/diagnostics.rs @@ -66,9 +66,7 @@ pub(super) fn failed_to_match_macro( } if let MatcherLoc::Token { token: expected_token } = &remaining_matcher - && (matches!(expected_token.kind, TokenKind::Interpolated(_)) - || matches!(token.kind, TokenKind::Interpolated(_)) - || matches!(expected_token.kind, TokenKind::OpenDelim(Delimiter::Invisible(_))) + && (matches!(expected_token.kind, TokenKind::OpenDelim(Delimiter::Invisible(_))) || matches!(token.kind, TokenKind::OpenDelim(Delimiter::Invisible(_)))) { err.note("captured metavariables except for `:tt`, `:ident` and `:lifetime` cannot be compared to other tokens"); @@ -162,7 +160,7 @@ impl<'dcx, 'matcher> Tracker<'matcher> for CollectTrackerAndEmitter<'dcx, 'match .is_none_or(|failure| failure.is_better_position(*approx_position)) { self.best_failure = Some(BestFailure { - token: token.clone(), + token: *token, position_in_tokenstream: *approx_position, msg, remaining_matcher: self diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs index d709fd792817..0065f83eb4ee 100644 --- a/compiler/rustc_expand/src/mbe/macro_parser.rs +++ b/compiler/rustc_expand/src/mbe/macro_parser.rs @@ -179,7 +179,7 @@ pub(super) fn compute_locs(matcher: &[TokenTree]) -> Vec { for tt in tts { match tt { TokenTree::Token(token) => { - locs.push(MatcherLoc::Token { token: token.clone() }); + locs.push(MatcherLoc::Token { token: *token }); } TokenTree::Delimited(span, _, delimited) => { let open_token = Token::new(token::OpenDelim(delimited.delim), span.open); @@ -648,7 +648,7 @@ impl TtParser { // There are no possible next positions AND we aren't waiting for the black-box // parser: syntax error. return Failure(T::build_failure( - parser.token.clone(), + parser.token, parser.approx_token_stream_pos(), "no rules expected this token in macro call", )); diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index 77ec598e62a1..c138b0908772 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -12,7 +12,7 @@ use rustc_ast::{self as ast, DUMMY_NODE_ID, NodeId}; use rustc_ast_pretty::pprust; use rustc_attr_parsing::{AttributeKind, find_attr}; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; -use rustc_errors::{Applicability, ErrorGuaranteed}; +use rustc_errors::{Applicability, Diag, ErrorGuaranteed}; use rustc_feature::Features; use rustc_hir as hir; use rustc_lint_defs::BuiltinLintDiag; @@ -27,19 +27,18 @@ use rustc_span::hygiene::Transparency; use rustc_span::{Ident, MacroRulesNormalizedIdent, Span, kw, sym}; use tracing::{debug, instrument, trace, trace_span}; -use super::diagnostics; use super::macro_parser::{NamedMatches, NamedParseResult}; +use super::{SequenceRepetition, diagnostics}; use crate::base::{ DummyResult, ExpandResult, ExtCtxt, MacResult, MacroExpanderResult, SyntaxExtension, SyntaxExtensionKind, TTMacroExpander, }; use crate::expand::{AstFragment, AstFragmentKind, ensure_complete_parse, parse_ast_fragment}; -use crate::mbe; use crate::mbe::diagnostics::{annotate_doc_comment, parse_failure_msg}; -use crate::mbe::macro_check; use crate::mbe::macro_parser::NamedMatch::*; use crate::mbe::macro_parser::{Error, ErrorReported, Failure, MatcherLoc, Success, TtParser}; use crate::mbe::transcribe::transcribe; +use crate::mbe::{self, KleeneOp, macro_check}; pub(crate) struct ParserAnyMacro<'a> { parser: Parser<'a>, @@ -640,6 +639,37 @@ fn is_empty_token_tree(sess: &Session, seq: &mbe::SequenceRepetition) -> bool { } } +/// Checks if a `vis` nonterminal fragment is unnecessarily wrapped in an optional repetition. +/// +/// When a `vis` fragment (which can already be empty) is wrapped in `$(...)?`, +/// this suggests removing the redundant repetition syntax since it provides no additional benefit. +fn check_redundant_vis_repetition( + err: &mut Diag<'_>, + sess: &Session, + seq: &SequenceRepetition, + span: &DelimSpan, +) { + let is_zero_or_one: bool = seq.kleene.op == KleeneOp::ZeroOrOne; + let is_vis = seq.tts.first().map_or(false, |tt| { + matches!(tt, mbe::TokenTree::MetaVarDecl(_, _, Some(NonterminalKind::Vis))) + }); + + if is_vis && is_zero_or_one { + err.note("a `vis` fragment can already be empty"); + err.multipart_suggestion( + "remove the `$(` and `)?`", + vec![ + ( + sess.source_map().span_extend_to_prev_char_before(span.open, '$', true), + "".to_string(), + ), + (span.close.with_hi(seq.kleene.span.hi()), "".to_string()), + ], + Applicability::MaybeIncorrect, + ); + } +} + /// Checks that the lhs contains no repetition which could match an empty token /// tree, because then the matcher would hang indefinitely. fn check_lhs_no_empty_seq(sess: &Session, tts: &[mbe::TokenTree]) -> Result<(), ErrorGuaranteed> { @@ -654,8 +684,10 @@ fn check_lhs_no_empty_seq(sess: &Session, tts: &[mbe::TokenTree]) -> Result<(), TokenTree::Sequence(span, seq) => { if is_empty_token_tree(sess, seq) { let sp = span.entire(); - let guar = sess.dcx().span_err(sp, "repetition matches empty token tree"); - return Err(guar); + let mut err = + sess.dcx().struct_span_err(sp, "repetition matches empty token tree"); + check_redundant_vis_repetition(&mut err, sess, seq, span); + return Err(err.emit()); } check_lhs_no_empty_seq(sess, &seq.tts)? } @@ -778,7 +810,7 @@ impl<'tt> FirstSets<'tt> { // token could be the separator token itself. if let (Some(sep), true) = (&seq_rep.separator, subfirst.maybe_empty) { - first.add_one_maybe(TtHandle::from_token(sep.clone())); + first.add_one_maybe(TtHandle::from_token(*sep)); } // Reverse scan: Sequence comes before `first`. @@ -841,7 +873,7 @@ impl<'tt> FirstSets<'tt> { // If the sequence contents can be empty, then the first // token could be the separator token itself. if let (Some(sep), true) = (&seq_rep.separator, subfirst.maybe_empty) { - first.add_one_maybe(TtHandle::from_token(sep.clone())); + first.add_one_maybe(TtHandle::from_token(*sep)); } assert!(first.maybe_empty); @@ -917,7 +949,7 @@ impl<'tt> Clone for TtHandle<'tt> { // This variant *must* contain a `mbe::TokenTree::Token`, and not // any other variant of `mbe::TokenTree`. TtHandle::Token(mbe::TokenTree::Token(tok)) => { - TtHandle::Token(mbe::TokenTree::Token(tok.clone())) + TtHandle::Token(mbe::TokenTree::Token(*tok)) } _ => unreachable!(), @@ -1093,7 +1125,7 @@ fn check_matcher_core<'tt>( let mut new; let my_suffix = if let Some(sep) = &seq_rep.separator { new = suffix_first.clone(); - new.add_one_maybe(TtHandle::from_token(sep.clone())); + new.add_one_maybe(TtHandle::from_token(*sep)); &new } else { &suffix_first diff --git a/compiler/rustc_expand/src/mbe/quoted.rs b/compiler/rustc_expand/src/mbe/quoted.rs index 0ea53627fe78..3f0372599565 100644 --- a/compiler/rustc_expand/src/mbe/quoted.rs +++ b/compiler/rustc_expand/src/mbe/quoted.rs @@ -283,7 +283,7 @@ fn parse_tree<'a>( } // `tree` is an arbitrary token. Keep it. - tokenstream::TokenTree::Token(token, _) => TokenTree::Token(token.clone()), + tokenstream::TokenTree::Token(token, _) => TokenTree::Token(*token), // `tree` is the beginning of a delimited set of tokens (e.g., `(` or `{`). We need to // descend into the delimited set and further parse it. @@ -321,7 +321,7 @@ fn parse_kleene_op( match iter.next() { Some(tokenstream::TokenTree::Token(token, _)) => match kleene_op(token) { Some(op) => Ok(Ok((op, token.span))), - None => Ok(Err(token.clone())), + None => Ok(Err(*token)), }, tree => Err(tree.map_or(span, tokenstream::TokenTree::span)), } diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs index 6e47ed6eb67c..39186319b1cc 100644 --- a/compiler/rustc_expand/src/mbe/transcribe.rs +++ b/compiler/rustc_expand/src/mbe/transcribe.rs @@ -1,5 +1,4 @@ use std::mem; -use std::sync::Arc; use rustc_ast::mut_visit::{self, MutVisitor}; use rustc_ast::token::{ @@ -165,7 +164,7 @@ pub(super) fn transcribe<'a>( if repeat_idx < repeat_len { frame.idx = 0; if let Some(sep) = sep { - result.push(TokenTree::Token(sep.clone(), Spacing::Alone)); + result.push(TokenTree::Token(*sep, Spacing::Alone)); } continue; } @@ -307,7 +306,9 @@ pub(super) fn transcribe<'a>( let tt = match cur_matched { MatchedSingle(ParseNtResult::Tt(tt)) => { // `tt`s are emitted into the output stream directly as "raw tokens", - // without wrapping them into groups. + // without wrapping them into groups. Other variables are emitted into + // the output stream as groups with `Delimiter::Invisible` to maintain + // parsing priorities. maybe_use_metavar_location(psess, &stack, sp, tt, &mut marker) } MatchedSingle(ParseNtResult::Ident(ident, is_raw)) => { @@ -325,6 +326,11 @@ pub(super) fn transcribe<'a>( MatchedSingle(ParseNtResult::Item(item)) => { mk_delimited(item.span, MetaVarKind::Item, TokenStream::from_ast(item)) } + MatchedSingle(ParseNtResult::Block(block)) => mk_delimited( + block.span, + MetaVarKind::Block, + TokenStream::from_ast(block), + ), MatchedSingle(ParseNtResult::Stmt(stmt)) => { let stream = if let StmtKind::Empty = stmt.kind { // FIXME: Properly collect tokens for empty statements. @@ -385,15 +391,6 @@ pub(super) fn transcribe<'a>( MatchedSingle(ParseNtResult::Vis(vis)) => { mk_delimited(vis.span, MetaVarKind::Vis, TokenStream::from_ast(vis)) } - MatchedSingle(ParseNtResult::Nt(nt)) => { - // Other variables are emitted into the output stream as groups with - // `Delimiter::Invisible` to maintain parsing priorities. - // `Interpolated` is currently used for such groups in rustc parser. - marker.visit_span(&mut sp); - let use_span = nt.use_span(); - with_metavar_spans(|mspans| mspans.insert(use_span, sp)); - TokenTree::token_alone(token::Interpolated(Arc::clone(nt)), sp) - } MatchedSeq(..) => { // We were unable to descend far enough. This is an error. return Err(dcx.create_err(VarStillRepeating { span: sp, ident })); @@ -441,7 +438,7 @@ pub(super) fn transcribe<'a>( // Nothing much to do here. Just push the token to the result, being careful to // preserve syntax context. mbe::TokenTree::Token(token) => { - let mut token = token.clone(); + let mut token = *token; mut_visit::visit_token(&mut marker, &mut token); let tt = TokenTree::Token(token, Spacing::Alone); result.push(tt); diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs index ee6306e39610..4edaf68c89ae 100644 --- a/compiler/rustc_expand/src/proc_macro_server.rs +++ b/compiler/rustc_expand/src/proc_macro_server.rs @@ -1,5 +1,4 @@ use std::ops::{Bound, Range}; -use std::sync::Arc; use ast::token::IdentIsRaw; use pm::bridge::{ @@ -18,7 +17,7 @@ use rustc_parse::parser::Parser; use rustc_parse::{exp, new_parser_from_source_str, source_str_to_stream, unwrap_or_emit_fatal}; use rustc_session::parse::ParseSess; use rustc_span::def_id::CrateNum; -use rustc_span::{BytePos, FileName, Pos, SourceFile, Span, Symbol, sym}; +use rustc_span::{BytePos, FileName, Pos, Span, Symbol, sym}; use smallvec::{SmallVec, smallvec}; use crate::base::ExtCtxt; @@ -309,15 +308,6 @@ impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)> for Vec { - let stream = TokenStream::from_nonterminal_ast(&nt); - trees.push(TokenTree::Group(Group { - delimiter: pm::Delimiter::None, - stream: Some(stream), - span: DelimSpan::from_single(span), - })) - } - OpenDelim(..) | CloseDelim(..) => unreachable!(), Eof => unreachable!(), } @@ -467,7 +457,6 @@ impl<'a, 'b> Rustc<'a, 'b> { impl server::Types for Rustc<'_, '_> { type FreeFunctions = FreeFunctions; type TokenStream = TokenStream; - type SourceFile = Arc; type Span = Span; type Symbol = Symbol; } @@ -673,28 +662,6 @@ impl server::TokenStream for Rustc<'_, '_> { } } -impl server::SourceFile for Rustc<'_, '_> { - fn eq(&mut self, file1: &Self::SourceFile, file2: &Self::SourceFile) -> bool { - Arc::ptr_eq(file1, file2) - } - - fn path(&mut self, file: &Self::SourceFile) -> String { - match &file.name { - FileName::Real(name) => name - .local_path() - .expect("attempting to get a file path in an imported file in `proc_macro::SourceFile::path`") - .to_str() - .expect("non-UTF8 file path in `proc_macro::SourceFile::path`") - .to_string(), - _ => file.name.prefer_local().to_string(), - } - } - - fn is_real(&mut self, file: &Self::SourceFile) -> bool { - file.is_real_file() - } -} - impl server::Span for Rustc<'_, '_> { fn debug(&mut self, span: Self::Span) -> String { if self.ecx.ecfg.span_debug { @@ -704,8 +671,29 @@ impl server::Span for Rustc<'_, '_> { } } - fn source_file(&mut self, span: Self::Span) -> Self::SourceFile { - self.psess().source_map().lookup_char_pos(span.lo()).file + fn file(&mut self, span: Self::Span) -> String { + self.psess() + .source_map() + .lookup_char_pos(span.lo()) + .file + .name + .prefer_remapped_unconditionaly() + .to_string() + } + + fn local_file(&mut self, span: Self::Span) -> Option { + self.psess() + .source_map() + .lookup_char_pos(span.lo()) + .file + .name + .clone() + .into_local_path() + .map(|p| { + p.to_str() + .expect("non-UTF8 file path in `proc_macro::SourceFile::path`") + .to_string() + }) } fn parent(&mut self, span: Self::Span) -> Option { diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index 88e6593572bc..fcc11dd3c1fd 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -63,7 +63,7 @@ declare_features! ( /// Allows using `const` operands in inline assembly. (accepted, asm_const, "1.82.0", Some(93332)), /// Allows using `label` operands in inline assembly. - (accepted, asm_goto, "CURRENT_RUSTC_VERSION", Some(119364)), + (accepted, asm_goto, "1.87.0", Some(119364)), /// Allows using `sym` operands in inline assembly. (accepted, asm_sym, "1.66.0", Some(93333)), /// Allows the definition of associated constants in `trait` or `impl` blocks. @@ -95,6 +95,8 @@ declare_features! ( (accepted, c_unwind, "1.81.0", Some(74990)), /// Allows `#[cfg_attr(predicate, multiple, attributes, here)]`. (accepted, cfg_attr_multi, "1.33.0", Some(54881)), + /// Allows the use of `#[cfg()]`. + (accepted, cfg_boolean_literals, "CURRENT_RUSTC_VERSION", Some(131204)), /// Allows the use of `#[cfg(doctest)]`, set when rustdoc is collecting doctests. (accepted, cfg_doctest, "1.40.0", Some(62210)), /// Enables `#[cfg(panic = "...")]` config key. @@ -332,7 +334,7 @@ declare_features! ( /// Allows `use<'a, 'b, A, B>` in `impl Trait + use<...>` for precise capture of generic args. (accepted, precise_capturing, "1.82.0", Some(123432)), /// Allows `use<..>` precise capturign on impl Trait in traits. - (accepted, precise_capturing_in_traits, "CURRENT_RUSTC_VERSION", Some(130044)), + (accepted, precise_capturing_in_traits, "1.87.0", Some(130044)), /// Allows procedural macros in `proc-macro` crates. (accepted, proc_macro, "1.29.0", Some(38356)), /// Allows multi-segment paths in attributes and derives. diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 1e33e2e9393f..3b441729d755 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -6,6 +6,7 @@ use AttributeDuplicates::*; use AttributeGate::*; use AttributeType::*; use rustc_data_structures::fx::FxHashMap; +use rustc_span::edition::Edition; use rustc_span::{Symbol, sym}; use crate::{Features, Stability}; @@ -65,9 +66,12 @@ pub enum AttributeSafety { /// Normal attribute that does not need `#[unsafe(...)]` Normal, - /// Unsafe attribute that requires safety obligations - /// to be discharged - Unsafe, + /// Unsafe attribute that requires safety obligations to be discharged. + /// + /// An error is emitted when `#[unsafe(...)]` is omitted, except when the attribute's edition + /// is less than the one stored in `unsafe_since`. This handles attributes that were safe in + /// earlier editions, but become unsafe in later ones. + Unsafe { unsafe_since: Option }, } #[derive(Clone, Copy)] @@ -187,12 +191,23 @@ macro_rules! template { } macro_rules! ungated { + (unsafe($edition:ident) $attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr $(,)?) => { + BuiltinAttribute { + name: sym::$attr, + encode_cross_crate: $encode_cross_crate, + type_: $typ, + safety: AttributeSafety::Unsafe { unsafe_since: Some(Edition::$edition) }, + template: $tpl, + gate: Ungated, + duplicates: $duplicates, + } + }; (unsafe $attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr $(,)?) => { BuiltinAttribute { name: sym::$attr, encode_cross_crate: $encode_cross_crate, type_: $typ, - safety: AttributeSafety::Unsafe, + safety: AttributeSafety::Unsafe { unsafe_since: None }, template: $tpl, gate: Ungated, duplicates: $duplicates, @@ -217,7 +232,7 @@ macro_rules! gated { name: sym::$attr, encode_cross_crate: $encode_cross_crate, type_: $typ, - safety: AttributeSafety::Unsafe, + safety: AttributeSafety::Unsafe { unsafe_since: None }, template: $tpl, duplicates: $duplicates, gate: Gated(Stability::Unstable, sym::$gate, $msg, Features::$gate), @@ -228,7 +243,7 @@ macro_rules! gated { name: sym::$attr, encode_cross_crate: $encode_cross_crate, type_: $typ, - safety: AttributeSafety::Unsafe, + safety: AttributeSafety::Unsafe { unsafe_since: None }, template: $tpl, duplicates: $duplicates, gate: Gated(Stability::Unstable, sym::$attr, $msg, Features::$attr), @@ -423,9 +438,9 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ ), ungated!(no_link, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No), ungated!(repr, Normal, template!(List: "C"), DuplicatesOk, EncodeCrossCrate::No), - ungated!(unsafe export_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding, EncodeCrossCrate::No), - ungated!(unsafe link_section, Normal, template!(NameValueStr: "name"), FutureWarnPreceding, EncodeCrossCrate::No), - ungated!(unsafe no_mangle, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No), + ungated!(unsafe(Edition2024) export_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding, EncodeCrossCrate::No), + ungated!(unsafe(Edition2024) link_section, Normal, template!(NameValueStr: "name"), FutureWarnPreceding, EncodeCrossCrate::No), + ungated!(unsafe(Edition2024) no_mangle, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No), ungated!(used, Normal, template!(Word, List: "compiler|linker"), WarnFollowing, EncodeCrossCrate::No), ungated!(link_ordinal, Normal, template!(List: "ordinal"), ErrorPreceding, EncodeCrossCrate::Yes), @@ -752,7 +767,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ ), rustc_attr!( rustc_macro_transparency, Normal, - template!(NameValueStr: "transparent|semitransparent|opaque"), ErrorFollowing, + template!(NameValueStr: "transparent|semiopaque|opaque"), ErrorFollowing, EncodeCrossCrate::Yes, "used internally for testing macro hygiene", ), rustc_attr!( diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs index 6ba7b22a0dff..402e18c5d148 100644 --- a/compiler/rustc_feature/src/removed.rs +++ b/compiler/rustc_feature/src/removed.rs @@ -247,7 +247,7 @@ declare_features! ( /// Allows unnamed fields of struct and union type (removed, unnamed_fields, "1.83.0", Some(49804), Some("feature needs redesign")), (removed, unsafe_no_drop_flag, "1.0.0", None, None), - (removed, unsized_tuple_coercion, "CURRENT_RUSTC_VERSION", Some(42877), + (removed, unsized_tuple_coercion, "1.87.0", Some(42877), Some("The feature restricts possible layouts for tuples, and this restriction is not worth it.")), /// 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), diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 710e129b609f..e09ae3c12394 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -211,7 +211,7 @@ declare_features! ( (internal, custom_mir, "1.65.0", None), /// Outputs useful `assert!` messages (unstable, generic_assert, "1.63.0", None), - /// Allows using the `rust-intrinsic`'s "ABI". + /// Allows using the #[rustc_intrinsic] attribute. (internal, intrinsics, "1.0.0", None), /// Allows using `#[lang = ".."]` attribute for linking items to special compiler logic. (internal, lang_items, "1.0.0", None), @@ -391,8 +391,6 @@ declare_features! ( (unstable, async_trait_bounds, "1.85.0", Some(62290)), /// Allows using C-variadics. (unstable, c_variadic, "1.34.0", Some(44930)), - /// Allows the use of `#[cfg()]`. - (unstable, cfg_boolean_literals, "1.83.0", Some(131204)), /// Allows the use of `#[cfg(contract_checks)` to check if contract checks are enabled. (unstable, cfg_contract_checks, "1.86.0", Some(128044)), /// Allows the use of `#[cfg(overflow_checks)` to check if integer overflow behaviour. @@ -474,9 +472,11 @@ declare_features! ( /// Allows `dyn* Trait` objects. (incomplete, dyn_star, "1.65.0", Some(102425)), /// Allows the .use postfix syntax `x.use` and use closures `use |x| { ... }` - (incomplete, ergonomic_clones, "CURRENT_RUSTC_VERSION", Some(132290)), + (incomplete, ergonomic_clones, "1.87.0", Some(132290)), /// Allows exhaustive pattern matching on types that contain uninhabited types. (unstable, exhaustive_patterns, "1.13.0", Some(51085)), + /// Disallows `extern` without an explicit ABI. + (unstable, explicit_extern_abis, "CURRENT_RUSTC_VERSION", Some(134986)), /// Allows explicit tail calls via `become` expression. (incomplete, explicit_tail_calls, "1.72.0", Some(112788)), /// Allows using `aapcs`, `efiapi`, `sysv64` and `win64` as calling conventions @@ -511,7 +511,7 @@ declare_features! ( /// Allows generic parameters and where-clauses on free & associated const items. (incomplete, generic_const_items, "1.73.0", Some(113521)), /// Allows the type of const generics to depend on generic parameters - (incomplete, generic_const_parameter_types, "CURRENT_RUSTC_VERSION", Some(137626)), + (incomplete, generic_const_parameter_types, "1.87.0", Some(137626)), /// Allows any generic constants being used as pattern type range ends (incomplete, generic_pattern_types, "1.86.0", Some(136574)), /// Allows registering static items globally, possibly across crates, to iterate over at runtime. @@ -565,6 +565,8 @@ declare_features! ( (incomplete, mut_ref, "1.79.0", Some(123076)), /// Allows using `#[naked]` on functions. (unstable, naked_functions, "1.9.0", Some(90957)), + /// Allows using `#[naked]` on `extern "Rust"` functions. + (unstable, naked_functions_rustic_abi, "CURRENT_RUSTC_VERSION", Some(138997)), /// Allows using `#[target_feature(enable = "...")]` on `#[naked]` on functions. (unstable, naked_functions_target_feature, "1.86.0", Some(138568)), /// Allows specifying the as-needed link modifier @@ -602,7 +604,7 @@ declare_features! ( /// Allows macro attributes on expressions, statements and non-inline modules. (unstable, proc_macro_hygiene, "1.30.0", Some(54727)), /// Allows the use of raw-dylibs on ELF platforms - (incomplete, raw_dylib_elf, "CURRENT_RUSTC_VERSION", Some(135694)), + (incomplete, raw_dylib_elf, "1.87.0", Some(135694)), /// Makes `&` and `&mut` patterns eat only one layer of references in Rust 2024. (incomplete, ref_pat_eat_one_layer_2024, "1.79.0", Some(123076)), /// Makes `&` and `&mut` patterns eat only one layer of references in Rust 2024—structural variant @@ -630,7 +632,7 @@ declare_features! ( /// Allows string patterns to dereference values to match them. (unstable, string_deref_patterns, "1.67.0", Some(87121)), /// Allows `super let` statements. - (incomplete, super_let, "CURRENT_RUSTC_VERSION", Some(139076)), + (unstable, super_let, "CURRENT_RUSTC_VERSION", Some(139076)), /// Allows subtrait items to shadow supertrait items. (unstable, supertrait_item_shadowing, "1.86.0", Some(89151)), /// Allows using `#[thread_local]` on `static` items. @@ -664,14 +666,14 @@ declare_features! ( /// Allows using the `#[used(linker)]` (or `#[used(compiler)]`) attribute. (unstable, used_with_arg, "1.60.0", Some(93798)), /// Allows use of attributes in `where` clauses. - (unstable, where_clause_attrs, "CURRENT_RUSTC_VERSION", Some(115590)), + (unstable, where_clause_attrs, "1.87.0", Some(115590)), /// Allows use of x86 `AMX` target-feature attributes and intrinsics (unstable, x86_amx_intrinsics, "1.81.0", Some(126622)), /// Allows use of the `xop` target-feature (unstable, xop_target_feature, "1.81.0", Some(127208)), /// Allows `do yeet` expressions (unstable, yeet_expr, "1.62.0", Some(96373)), - (unstable, yield_expr, "CURRENT_RUSTC_VERSION", Some(43122)), + (unstable, yield_expr, "1.87.0", Some(43122)), // !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! // Features are listed in alphabetical order. Tidy will fail if you don't keep it this way. // !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! diff --git a/compiler/rustc_fluent_macro/src/fluent.rs b/compiler/rustc_fluent_macro/src/fluent.rs index b04fd1b48f7a..c96bb48a0368 100644 --- a/compiler/rustc_fluent_macro/src/fluent.rs +++ b/compiler/rustc_fluent_macro/src/fluent.rs @@ -25,7 +25,10 @@ fn invocation_relative_path_to_absolute(span: Span, path: &str) -> PathBuf { path.to_path_buf() } else { // `/a/b/c/foo/bar.rs` contains the current macro invocation + #[cfg(bootstrap)] let mut source_file_path = span.source_file().path(); + #[cfg(not(bootstrap))] + let mut source_file_path = span.local_file().unwrap(); // `/a/b/c/foo/` source_file_path.pop(); // `/a/b/c/foo/../locales/en-US/example.ftl` diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs index dc00b52a5936..9372ab532bf3 100644 --- a/compiler/rustc_hir/src/def.rs +++ b/compiler/rustc_hir/src/def.rs @@ -267,11 +267,16 @@ impl DefKind { | DefKind::ForeignTy | DefKind::TraitAlias | DefKind::TyParam - | DefKind::ExternCrate => DefPathData::TypeNs(Some(name.unwrap())), + | DefKind::ExternCrate => DefPathData::TypeNs(name.unwrap()), - // An associated type names will be missing for an RPITIT. It will - // later be given a name with `synthetic` in it, if necessary. - DefKind::AssocTy => DefPathData::TypeNs(name), + // An associated type name will be missing for an RPITIT. + DefKind::AssocTy => { + if let Some(name) = name { + DefPathData::TypeNs(name) + } else { + DefPathData::AnonAssocTy + } + } // It's not exactly an anon const, but wrt DefPathData, there // is no difference. diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs index c52954aa96fc..bf7b1eefcf68 100644 --- a/compiler/rustc_hir/src/definitions.rs +++ b/compiler/rustc_hir/src/definitions.rs @@ -47,12 +47,9 @@ impl DefPathTable { debug_assert_eq!(self.stable_crate_id, def_path_hash.stable_crate_id()); let local_hash = def_path_hash.local_hash(); - let index = { - let index = DefIndex::from(self.index_to_key.len()); - debug!("DefPathTable::insert() - {:?} <-> {:?}", key, index); - self.index_to_key.push(key); - index - }; + let index = self.index_to_key.push(key); + debug!("DefPathTable::insert() - {key:?} <-> {index:?}"); + self.def_path_hashes.push(local_hash); debug_assert!(self.def_path_hashes.len() == self.index_to_key.len()); @@ -271,9 +268,8 @@ pub enum DefPathData { Use, /// A global asm item. GlobalAsm, - /// Something in the type namespace. Will be empty for RPITIT associated - /// types, which are given a synthetic name later, if necessary. - TypeNs(Option), + /// Something in the type namespace. + TypeNs(Symbol), /// Something in the value namespace. ValueNs(Symbol), /// Something in the macro namespace. @@ -291,6 +287,8 @@ pub enum DefPathData { /// An existential `impl Trait` type node. /// Argument position `impl Trait` have a `TypeNs` with their pretty-printed name. OpaqueTy, + /// An anonymous associated type from an RPITIT. + AnonAssocTy, /// A synthetic body for a coroutine's by-move body. SyntheticCoroutineBody, } @@ -413,9 +411,7 @@ impl DefPathData { pub fn get_opt_name(&self) -> Option { use self::DefPathData::*; match *self { - TypeNs(name) => name, - - ValueNs(name) | MacroNs(name) | LifetimeNs(name) => Some(name), + TypeNs(name) | ValueNs(name) | MacroNs(name) | LifetimeNs(name) => Some(name), Impl | ForeignMod @@ -426,6 +422,7 @@ impl DefPathData { | Ctor | AnonConst | OpaqueTy + | AnonAssocTy | SyntheticCoroutineBody => None, } } @@ -433,14 +430,9 @@ impl DefPathData { pub fn name(&self) -> DefPathDataName { use self::DefPathData::*; match *self { - TypeNs(name) => { - if let Some(name) = name { - DefPathDataName::Named(name) - } else { - DefPathDataName::Anon { namespace: sym::synthetic } - } + TypeNs(name) | ValueNs(name) | MacroNs(name) | LifetimeNs(name) => { + DefPathDataName::Named(name) } - ValueNs(name) | MacroNs(name) | LifetimeNs(name) => DefPathDataName::Named(name), // Note that this does not show up in user print-outs. CrateRoot => DefPathDataName::Anon { namespace: kw::Crate }, Impl => DefPathDataName::Anon { namespace: kw::Impl }, @@ -451,6 +443,7 @@ impl DefPathData { Ctor => DefPathDataName::Anon { namespace: sym::constructor }, AnonConst => DefPathDataName::Anon { namespace: sym::constant }, OpaqueTy => DefPathDataName::Anon { namespace: sym::opaque }, + AnonAssocTy => DefPathDataName::Anon { namespace: sym::anon_assoc }, SyntheticCoroutineBody => DefPathDataName::Anon { namespace: sym::synthetic }, } } diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 1a6c15b66a45..d02c767ea677 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -42,7 +42,7 @@ pub enum IsAnonInPath { } /// A lifetime. The valid field combinations are non-obvious. The following -/// example shows some of them. See also the comments on `LifetimeName`. +/// example shows some of them. See also the comments on `LifetimeKind`. /// ``` /// #[repr(C)] /// struct S<'a>(&'a u32); // res=Param, name='a, IsAnonInPath::No @@ -84,7 +84,7 @@ pub struct Lifetime { pub ident: Ident, /// Semantics of this lifetime. - pub res: LifetimeName, + pub kind: LifetimeKind, /// Is the lifetime anonymous and in a path? Used only for error /// suggestions. See `Lifetime::suggestion` for example use. @@ -130,7 +130,7 @@ impl ParamName { } #[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable_Generic)] -pub enum LifetimeName { +pub enum LifetimeKind { /// User-given names or fresh (synthetic) names. Param(LocalDefId), @@ -160,16 +160,16 @@ pub enum LifetimeName { Static, } -impl LifetimeName { +impl LifetimeKind { fn is_elided(&self) -> bool { match self { - LifetimeName::ImplicitObjectLifetimeDefault | LifetimeName::Infer => true, + LifetimeKind::ImplicitObjectLifetimeDefault | LifetimeKind::Infer => true, // It might seem surprising that `Fresh` counts as not *elided* // -- but this is because, as far as the code in the compiler is // concerned -- `Fresh` variants act equivalently to "some fresh name". // They correspond to early-bound regions on an impl, in other words. - LifetimeName::Error | LifetimeName::Param(..) | LifetimeName::Static => false, + LifetimeKind::Error | LifetimeKind::Param(..) | LifetimeKind::Static => false, } } } @@ -184,10 +184,10 @@ impl Lifetime { pub fn new( hir_id: HirId, ident: Ident, - res: LifetimeName, + kind: LifetimeKind, is_anon_in_path: IsAnonInPath, ) -> Lifetime { - let lifetime = Lifetime { hir_id, ident, res, is_anon_in_path }; + let lifetime = Lifetime { hir_id, ident, kind, is_anon_in_path }; // Sanity check: elided lifetimes form a strict subset of anonymous lifetimes. #[cfg(debug_assertions)] @@ -202,7 +202,7 @@ impl Lifetime { } pub fn is_elided(&self) -> bool { - self.res.is_elided() + self.kind.is_elided() } pub fn is_anonymous(&self) -> bool { @@ -1014,7 +1014,7 @@ pub struct WhereRegionPredicate<'hir> { impl<'hir> WhereRegionPredicate<'hir> { /// Returns `true` if `param_def_id` matches the `lifetime` of this predicate. fn is_param_bound(&self, param_def_id: LocalDefId) -> bool { - self.lifetime.res == LifetimeName::Param(param_def_id) + self.lifetime.kind == LifetimeKind::Param(param_def_id) } } @@ -1237,7 +1237,7 @@ impl AttributeExt for Attribute { Attribute::Parsed(AttributeKind::DocComment { kind, comment, .. }) => { Some((*comment, *kind)) } - Attribute::Unparsed(_) if self.name_or_empty() == sym::doc => { + Attribute::Unparsed(_) if self.has_name(sym::doc) => { self.value_str().map(|s| (s, CommentKind::Line)) } _ => None, @@ -1262,8 +1262,8 @@ impl Attribute { } #[inline] - pub fn name_or_empty(&self) -> Symbol { - AttributeExt::name_or_empty(self) + pub fn name(&self) -> Option { + AttributeExt::name(self) } #[inline] @@ -1301,6 +1301,11 @@ impl Attribute { AttributeExt::has_name(self, name) } + #[inline] + pub fn has_any_name(&self, names: &[Symbol]) -> bool { + AttributeExt::has_any_name(self, names) + } + #[inline] pub fn span(&self) -> Span { AttributeExt::span(self) @@ -1555,6 +1560,7 @@ impl<'hir> Pat<'hir> { use PatKind::*; match self.kind { + Missing => unreachable!(), Wild | Never | Expr(_) | Range(..) | Binding(.., None) | Err(_) => true, Box(s) | Deref(s) | Ref(s, _) | Binding(.., Some(s)) | Guard(s, _) => s.walk_short_(it), Struct(_, fields, _) => fields.iter().all(|field| field.pat.walk_short_(it)), @@ -1582,7 +1588,7 @@ impl<'hir> Pat<'hir> { use PatKind::*; match self.kind { - Wild | Never | Expr(_) | Range(..) | Binding(.., None) | Err(_) => {} + Missing | Wild | Never | Expr(_) | Range(..) | Binding(.., None) | Err(_) => {} Box(s) | Deref(s) | Ref(s, _) | Binding(.., Some(s)) | Guard(s, _) => s.walk_(it), Struct(_, fields, _) => fields.iter().for_each(|field| field.pat.walk_(it)), TupleStruct(_, s, _) | Tuple(s, _) | Or(s) => s.iter().for_each(|p| p.walk_(it)), @@ -1720,6 +1726,9 @@ pub enum TyPatKind<'hir> { #[derive(Debug, Clone, Copy, HashStable_Generic)] pub enum PatKind<'hir> { + /// A missing pattern, e.g. for an anonymous param in a bare fn like `fn f(u32)`. + Missing, + /// Represents a wildcard pattern (i.e., `_`). Wild, @@ -1752,7 +1761,7 @@ pub enum PatKind<'hir> { Never, /// A tuple pattern (e.g., `(a, b)`). - /// If the `..` pattern fragment is present, then `Option` denotes its position. + /// If the `..` pattern fragment is present, then `DotDotPos` denotes its position. /// `0 <= position <= subpats.len()` Tuple(&'hir [Pat<'hir>], DotDotPos), @@ -1817,6 +1826,8 @@ pub enum StmtKind<'hir> { /// Represents a `let` statement (i.e., `let : = ;`). #[derive(Debug, Clone, Copy, HashStable_Generic)] pub struct LetStmt<'hir> { + /// Span of `super` in `super let`. + pub super_: Option, pub pat: &'hir Pat<'hir>, /// Type annotation, if any (otherwise the type will be inferred). pub ty: Option<&'hir Ty<'hir>>, @@ -3393,9 +3404,9 @@ pub struct BareFnTy<'hir> { pub abi: ExternAbi, pub generic_params: &'hir [GenericParam<'hir>], pub decl: &'hir FnDecl<'hir>, - // `Option` because bare fn parameter names are optional. We also end up + // `Option` because bare fn parameter identifiers are optional. We also end up // with `None` in some error cases, e.g. invalid parameter patterns. - pub param_names: &'hir [Option], + pub param_idents: &'hir [Option], } #[derive(Debug, Clone, Copy, HashStable_Generic)] @@ -4850,7 +4861,7 @@ mod size_asserts { static_assert_size!(ImplItemKind<'_>, 40); static_assert_size!(Item<'_>, 88); static_assert_size!(ItemKind<'_>, 64); - static_assert_size!(LetStmt<'_>, 64); + static_assert_size!(LetStmt<'_>, 72); static_assert_size!(Param<'_>, 32); static_assert_size!(Pat<'_>, 72); static_assert_size!(Path<'_>, 40); diff --git a/compiler/rustc_hir/src/hir/tests.rs b/compiler/rustc_hir/src/hir/tests.rs index 62ef02d2f500..fcd0eafa4613 100644 --- a/compiler/rustc_hir/src/hir/tests.rs +++ b/compiler/rustc_hir/src/hir/tests.rs @@ -57,7 +57,7 @@ fn trait_object_roundtrips_impl(syntax: TraitObjectSyntax) { Lifetime { hir_id: HirId::INVALID, ident: Ident::new(sym::name, DUMMY_SP), - res: LifetimeName::Static, + kind: LifetimeKind::Static, is_anon_in_path: IsAnonInPath::No, } }, diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 506358341b50..3c2897ef1d95 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -6,7 +6,7 @@ //! 1. **Shallow visit**: Get a simple callback for every item (or item-like thing) in the HIR. //! - Example: find all items with a `#[foo]` attribute on them. //! - How: Use the `hir_crate_items` or `hir_module_items` query to traverse over item-like ids -//! (ItemId, TraitItemId, etc.) and use tcx.def_kind and `tcx.hir().item*(id)` to filter and +//! (ItemId, TraitItemId, etc.) and use tcx.def_kind and `tcx.hir_item*(id)` to filter and //! access actual item-like thing, respectively. //! - Pro: Efficient; just walks the lists of item ids and gives users control whether to access //! the hir_owners themselves or not. @@ -652,10 +652,10 @@ pub fn walk_foreign_item<'v, V: Visitor<'v>>( try_visit!(visitor.visit_ident(foreign_item.ident)); match foreign_item.kind { - ForeignItemKind::Fn(ref sig, param_names, ref generics) => { + ForeignItemKind::Fn(ref sig, param_idents, ref generics) => { try_visit!(visitor.visit_generics(generics)); try_visit!(visitor.visit_fn_decl(sig.decl)); - for ident in param_names.iter().copied() { + for ident in param_idents.iter().copied() { visit_opt!(visitor, visit_ident, ident); } } @@ -744,7 +744,7 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat<'v>) -> V: visit_opt!(visitor, visit_pat_expr, lower_bound); visit_opt!(visitor, visit_pat_expr, upper_bound); } - PatKind::Never | PatKind::Wild | PatKind::Err(_) => (), + PatKind::Missing | PatKind::Never | PatKind::Wild | PatKind::Err(_) => (), PatKind::Slice(prepatterns, ref slice_pattern, postpatterns) => { walk_list!(visitor, visit_pat, prepatterns); visit_opt!(visitor, visit_pat, slice_pattern); @@ -1169,9 +1169,9 @@ pub fn walk_trait_item<'v, V: Visitor<'v>>( try_visit!(visitor.visit_ty_unambig(ty)); visit_opt!(visitor, visit_nested_body, default); } - TraitItemKind::Fn(ref sig, TraitFn::Required(param_names)) => { + TraitItemKind::Fn(ref sig, TraitFn::Required(param_idents)) => { try_visit!(visitor.visit_fn_decl(sig.decl)); - for ident in param_names.iter().copied() { + for ident in param_idents.iter().copied() { visit_opt!(visitor, visit_ident, ident); } } diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 90fab01ba2d4..b9f4a8cd165d 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -182,6 +182,7 @@ language_item_table! { DynMetadata, sym::dyn_metadata, dyn_metadata, Target::Struct, GenericRequirement::None; Freeze, sym::freeze, freeze_trait, Target::Trait, GenericRequirement::Exact(0); + UnsafeUnpin, sym::unsafe_unpin, unsafe_unpin_trait, Target::Trait, GenericRequirement::Exact(0); FnPtrTrait, sym::fn_ptr_trait, fn_ptr_trait, Target::Trait, GenericRequirement::Exact(0); FnPtrAddr, sym::fn_ptr_addr, fn_ptr_addr, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None; @@ -235,6 +236,8 @@ language_item_table! { IndexMut, sym::index_mut, index_mut_trait, Target::Trait, GenericRequirement::Exact(1); UnsafeCell, sym::unsafe_cell, unsafe_cell_type, Target::Struct, GenericRequirement::None; + UnsafePinned, sym::unsafe_pinned, unsafe_pinned_type, Target::Struct, GenericRequirement::None; + VaList, sym::va_list, va_list, Target::Struct, GenericRequirement::None; Deref, sym::deref, deref_trait, Target::Trait, GenericRequirement::Exact(0); @@ -439,6 +442,8 @@ language_item_table! { DefaultTrait3, sym::default_trait3, default_trait3_trait, Target::Trait, GenericRequirement::None; DefaultTrait2, sym::default_trait2, default_trait2_trait, Target::Trait, GenericRequirement::None; DefaultTrait1, sym::default_trait1, default_trait1_trait, Target::Trait, GenericRequirement::None; + + ContractCheckEnsures, sym::contract_check_ensures, contract_check_ensures_fn, Target::Fn, GenericRequirement::None; } /// The requirement imposed on the generics of a lang item diff --git a/compiler/rustc_hir/src/lib.rs b/compiler/rustc_hir/src/lib.rs index 6bc0f797cca5..a84857e3597b 100644 --- a/compiler/rustc_hir/src/lib.rs +++ b/compiler/rustc_hir/src/lib.rs @@ -4,7 +4,6 @@ // tidy-alphabetical-start #![allow(internal_features)] -#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![feature(associated_type_defaults)] #![feature(box_patterns)] #![feature(closure_track_caller)] diff --git a/compiler/rustc_hir/src/tests.rs b/compiler/rustc_hir/src/tests.rs index 0837444ffdbe..18c2bfdac8ce 100644 --- a/compiler/rustc_hir/src/tests.rs +++ b/compiler/rustc_hir/src/tests.rs @@ -17,7 +17,7 @@ fn def_path_hash_depends_on_crate_id() { // the crate by changing the crate disambiguator (e.g. via bumping the // crate's version number). - create_session_globals_then(Edition::Edition2024, None, || { + create_session_globals_then(Edition::Edition2024, &[], None, || { let id0 = StableCrateId::new(Symbol::intern("foo"), false, vec!["1".to_string()], ""); let id1 = StableCrateId::new(Symbol::intern("foo"), false, vec!["2".to_string()], ""); diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index 194f2cd04e46..92701e3328e9 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -1,5 +1,5 @@ -hir_analysis_ambiguous_assoc_item = ambiguous associated {$assoc_kind} `{$assoc_name}` in bounds of `{$qself}` - .label = ambiguous associated {$assoc_kind} `{$assoc_name}` +hir_analysis_ambiguous_assoc_item = ambiguous associated {$assoc_kind} `{$assoc_ident}` in bounds of `{$qself}` + .label = ambiguous associated {$assoc_kind} `{$assoc_ident}` hir_analysis_ambiguous_lifetime_bound = ambiguous lifetime bound, explicit lifetime bound required @@ -12,13 +12,13 @@ hir_analysis_assoc_item_is_private = {$kind} `{$name}` is private .label = private {$kind} .defined_here_label = the {$kind} is defined here -hir_analysis_assoc_item_not_found = associated {$assoc_kind} `{$assoc_name}` not found for `{$qself}` +hir_analysis_assoc_item_not_found = associated {$assoc_kind} `{$assoc_ident}` not found for `{$qself}` hir_analysis_assoc_item_not_found_found_in_other_trait_label = there is {$identically_named -> [true] an *[false] a similarly named } associated {$assoc_kind} `{$suggested_name}` in the trait `{$trait_name}` -hir_analysis_assoc_item_not_found_label = associated {$assoc_kind} `{$assoc_name}` not found +hir_analysis_assoc_item_not_found_label = associated {$assoc_kind} `{$assoc_ident}` not found hir_analysis_assoc_item_not_found_other_sugg = `{$qself}` has the following associated {$assoc_kind} hir_analysis_assoc_item_not_found_similar_in_other_trait_qpath_sugg = consider fully qualifying{$identically_named -> @@ -486,6 +486,9 @@ hir_analysis_self_in_impl_self = `Self` is not valid in the self type of an impl block .note = replace `Self` with a different type +hir_analysis_self_in_type_alias = `Self` is not allowed in type aliases + .label = `Self` is only available in impls, traits, and concrete type definitions + hir_analysis_self_ty_not_captured = `impl Trait` must mention the `Self` type of the trait in `use<...>` .label = `Self` type parameter is implicitly captured by this `impl Trait` .note = currently, all type parameters are required to be mentioned in the precise captures list diff --git a/compiler/rustc_hir_analysis/src/autoderef.rs b/compiler/rustc_hir_analysis/src/autoderef.rs index b3eade8c8ae4..99e495d92669 100644 --- a/compiler/rustc_hir_analysis/src/autoderef.rs +++ b/compiler/rustc_hir_analysis/src/autoderef.rs @@ -2,8 +2,8 @@ use rustc_infer::infer::InferCtxt; use rustc_infer::traits::PredicateObligations; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; use rustc_session::Limit; -use rustc_span::Span; use rustc_span::def_id::{LOCAL_CRATE, LocalDefId}; +use rustc_span::{ErrorGuaranteed, Span}; use rustc_trait_selection::traits::ObligationCtxt; use tracing::{debug, instrument}; @@ -259,7 +259,11 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> { } } -pub fn report_autoderef_recursion_limit_error<'tcx>(tcx: TyCtxt<'tcx>, span: Span, ty: Ty<'tcx>) { +pub fn report_autoderef_recursion_limit_error<'tcx>( + tcx: TyCtxt<'tcx>, + span: Span, + ty: Ty<'tcx>, +) -> ErrorGuaranteed { // We've reached the recursion limit, error gracefully. let suggested_limit = match tcx.recursion_limit() { Limit(0) => Limit(2), @@ -270,5 +274,5 @@ pub fn report_autoderef_recursion_limit_error<'tcx>(tcx: TyCtxt<'tcx>, span: Spa ty, suggested_limit, crate_name: tcx.crate_name(LOCAL_CRATE), - }); + }) } diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index a07986567630..4f338c6a19e6 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -397,8 +397,11 @@ fn best_definition_site_of_opaque<'tcx>( return ControlFlow::Continue(()); } - if let Some(hidden_ty) = - self.tcx.mir_borrowck(item_def_id).concrete_opaque_types.get(&self.opaque_def_id) + if let Some(hidden_ty) = self + .tcx + .mir_borrowck(item_def_id) + .ok() + .and_then(|opaque_types| opaque_types.0.get(&self.opaque_def_id)) { ControlFlow::Break((hidden_ty.span, item_def_id)) } else { @@ -413,9 +416,6 @@ fn best_definition_site_of_opaque<'tcx>( self.tcx } fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) -> Self::Result { - if let hir::ExprKind::Closure(closure) = ex.kind { - self.check(closure.def_id)?; - } intravisit::walk_expr(self, ex) } fn visit_item(&mut self, it: &'tcx hir::Item<'tcx>) -> Self::Result { @@ -443,13 +443,13 @@ fn best_definition_site_of_opaque<'tcx>( let impl_def_id = tcx.local_parent(parent); for assoc in tcx.associated_items(impl_def_id).in_definition_order() { match assoc.kind { - ty::AssocKind::Const | ty::AssocKind::Fn => { + ty::AssocKind::Const { .. } | ty::AssocKind::Fn { .. } => { if let ControlFlow::Break(span) = locator.check(assoc.def_id.expect_local()) { return Some(span); } } - ty::AssocKind::Type => {} + ty::AssocKind::Type { .. } => {} } } @@ -719,7 +719,6 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) { def_id, tcx.def_ident_span(def_id).unwrap(), i.name, - ExternAbi::Rust, ) } } @@ -741,11 +740,7 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) { for &assoc_item in assoc_items.in_definition_order() { match assoc_item.kind { - ty::AssocKind::Fn => { - let abi = tcx.fn_sig(assoc_item.def_id).skip_binder().abi(); - forbid_intrinsic_abi(tcx, assoc_item.ident(tcx).span, abi); - } - ty::AssocKind::Type if assoc_item.defaultness(tcx).has_value() => { + ty::AssocKind::Type { .. } if assoc_item.defaultness(tcx).has_value() => { let trait_args = GenericArgs::identity_for_item(tcx, def_id); let _: Result<_, rustc_errors::ErrorGuaranteed> = check_type_bounds( tcx, @@ -788,65 +783,49 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) { }; check_abi(tcx, it.span, abi); - match abi { - ExternAbi::RustIntrinsic => { - for item in items { - intrinsic::check_intrinsic_type( - tcx, - item.id.owner_id.def_id, - item.span, - item.ident.name, - abi, - ); - } + for item in items { + let def_id = item.id.owner_id.def_id; + + let generics = tcx.generics_of(def_id); + let own_counts = generics.own_counts(); + if generics.own_params.len() - own_counts.lifetimes != 0 { + let (kinds, kinds_pl, egs) = match (own_counts.types, own_counts.consts) { + (_, 0) => ("type", "types", Some("u32")), + // We don't specify an example value, because we can't generate + // a valid value for any type. + (0, _) => ("const", "consts", None), + _ => ("type or const", "types or consts", None), + }; + struct_span_code_err!( + tcx.dcx(), + item.span, + E0044, + "foreign items may not have {kinds} parameters", + ) + .with_span_label(item.span, format!("can't have {kinds} parameters")) + .with_help( + // FIXME: once we start storing spans for type arguments, turn this + // into a suggestion. + format!( + "replace the {} parameters with concrete {}{}", + kinds, + kinds_pl, + egs.map(|egs| format!(" like `{egs}`")).unwrap_or_default(), + ), + ) + .emit(); } - _ => { - for item in items { - let def_id = item.id.owner_id.def_id; - let generics = tcx.generics_of(def_id); - let own_counts = generics.own_counts(); - if generics.own_params.len() - own_counts.lifetimes != 0 { - let (kinds, kinds_pl, egs) = match (own_counts.types, own_counts.consts) - { - (_, 0) => ("type", "types", Some("u32")), - // We don't specify an example value, because we can't generate - // a valid value for any type. - (0, _) => ("const", "consts", None), - _ => ("type or const", "types or consts", None), - }; - struct_span_code_err!( - tcx.dcx(), - item.span, - E0044, - "foreign items may not have {kinds} parameters", - ) - .with_span_label(item.span, format!("can't have {kinds} parameters")) - .with_help( - // FIXME: once we start storing spans for type arguments, turn this - // into a suggestion. - format!( - "replace the {} parameters with concrete {}{}", - kinds, - kinds_pl, - egs.map(|egs| format!(" like `{egs}`")).unwrap_or_default(), - ), - ) - .emit(); - } - - let item = tcx.hir_foreign_item(item.id); - match &item.kind { - hir::ForeignItemKind::Fn(sig, _, _) => { - require_c_abi_if_c_variadic(tcx, sig.decl, abi, item.span); - } - hir::ForeignItemKind::Static(..) => { - check_static_inhabited(tcx, def_id); - check_static_linkage(tcx, def_id); - } - _ => {} - } + let item = tcx.hir_foreign_item(item.id); + match &item.kind { + hir::ForeignItemKind::Fn(sig, _, _) => { + require_c_abi_if_c_variadic(tcx, sig.decl, abi, item.span); } + hir::ForeignItemKind::Static(..) => { + check_static_inhabited(tcx, def_id); + check_static_linkage(tcx, def_id); + } + _ => {} } } } @@ -947,31 +926,7 @@ fn check_impl_items_against_trait<'tcx>( let trait_def = tcx.trait_def(trait_ref.def_id); - let infcx = tcx.infer_ctxt().ignoring_regions().build(TypingMode::non_body_analysis()); - - let ocx = ObligationCtxt::new_with_diagnostics(&infcx); - let cause = ObligationCause::misc(tcx.def_span(impl_id), impl_id); - let param_env = tcx.param_env(impl_id); - - let self_is_guaranteed_unsized = match tcx - .struct_tail_raw( - trait_ref.self_ty(), - |ty| { - ocx.structurally_normalize_ty(&cause, param_env, ty).unwrap_or_else(|_| { - Ty::new_error_with_message( - tcx, - tcx.def_span(impl_id), - "struct tail should be computable", - ) - }) - }, - || (), - ) - .kind() - { - ty::Dynamic(_, _, ty::DynKind::Dyn) | ty::Slice(_) | ty::Str => true, - _ => false, - }; + let self_is_guaranteed_unsize_self = tcx.impl_self_is_guaranteed_unsized(impl_id); for &impl_item in impl_item_refs { let ty_impl_item = tcx.associated_item(impl_item); @@ -987,7 +942,7 @@ fn check_impl_items_against_trait<'tcx>( if res.is_ok() { match ty_impl_item.kind { - ty::AssocKind::Fn => { + ty::AssocKind::Fn { .. } => { compare_impl_item::refine::check_refining_return_position_impl_trait_in_trait( tcx, ty_impl_item, @@ -997,12 +952,12 @@ fn check_impl_items_against_trait<'tcx>( .instantiate_identity(), ); } - ty::AssocKind::Const => {} - ty::AssocKind::Type => {} + ty::AssocKind::Const { .. } => {} + ty::AssocKind::Type { .. } => {} } } - if self_is_guaranteed_unsized && tcx.generics_require_sized_self(ty_trait_item.def_id) { + if self_is_guaranteed_unsize_self && tcx.generics_require_sized_self(ty_trait_item.def_id) { tcx.emit_node_span_lint( rustc_lint_defs::builtin::DEAD_CODE, tcx.local_def_id_to_hir_id(ty_impl_item.def_id.expect_local()), @@ -1037,7 +992,7 @@ fn check_impl_items_against_trait<'tcx>( if !is_implemented && tcx.defaultness(impl_id).is_final() // unsized types don't need to implement methods that have `Self: Sized` bounds. - && !(self_is_guaranteed_unsized && tcx.generics_require_sized_self(trait_item_id)) + && !(self_is_guaranteed_unsize_self && tcx.generics_require_sized_self(trait_item_id)) { missing_items.push(tcx.associated_item(trait_item_id)); } diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 5e68bb310015..06a7b1f6c298 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -43,9 +43,11 @@ pub(super) fn compare_impl_item( debug!(?impl_trait_ref); match impl_item.kind { - ty::AssocKind::Fn => compare_impl_method(tcx, impl_item, trait_item, impl_trait_ref), - ty::AssocKind::Type => compare_impl_ty(tcx, impl_item, trait_item, impl_trait_ref), - ty::AssocKind::Const => compare_impl_const(tcx, impl_item, trait_item, impl_trait_ref), + ty::AssocKind::Fn { .. } => compare_impl_method(tcx, impl_item, trait_item, impl_trait_ref), + ty::AssocKind::Type { .. } => compare_impl_ty(tcx, impl_item, trait_item, impl_trait_ref), + ty::AssocKind::Const { .. } => { + compare_impl_const(tcx, impl_item, trait_item, impl_trait_ref) + } } } @@ -442,7 +444,7 @@ impl<'tcx> TypeFolder> for RemapLateParam<'tcx> { } fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { - if let ty::ReLateParam(fr) = *r { + if let ty::ReLateParam(fr) = r.kind() { ty::Region::new_late_param( self.tcx, fr.scope, @@ -606,7 +608,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( // with placeholders, which imply nothing about outlives bounds, and then // prove below that the hidden types are well formed. let universe = infcx.create_next_universe(); - let mut idx = 0; + let mut idx = ty::BoundVar::ZERO; let mapping: FxIndexMap<_, _> = collector .types .iter() @@ -623,10 +625,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( tcx, ty::Placeholder { universe, - bound: ty::BoundTy { - var: ty::BoundVar::from_usize(idx), - kind: ty::BoundTyKind::Anon, - }, + bound: ty::BoundTy { var: idx, kind: ty::BoundTyKind::Anon }, }, ), ) @@ -654,7 +653,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( cause.span, E0053, "method `{}` has an incompatible return type for trait", - trait_m.name + trait_m.name() ); infcx.err_ctxt().note_type_err( &mut diag, @@ -1032,11 +1031,11 @@ fn report_trait_method_mismatch<'tcx>( impl_err_span, E0053, "method `{}` has an incompatible type for trait", - trait_m.name + trait_m.name() ); match &terr { TypeError::ArgumentMutability(0) | TypeError::ArgumentSorts(_, 0) - if trait_m.fn_has_self_parameter => + if trait_m.is_method() => { let ty = trait_sig.inputs()[0]; let sugg = get_self_string(ty, |ty| ty == impl_trait_ref.self_ty()); @@ -1046,11 +1045,11 @@ fn report_trait_method_mismatch<'tcx>( // argument pattern and type. let (sig, body) = tcx.hir_expect_impl_item(impl_m.def_id.expect_local()).expect_fn(); let span = tcx - .hir_body_param_names(body) + .hir_body_param_idents(body) .zip(sig.decl.inputs.iter()) - .map(|(param_name, ty)| { - if let Some(param_name) = param_name { - param_name.span.to(ty.span) + .map(|(param_ident, ty)| { + if let Some(param_ident) = param_ident { + param_ident.span.to(ty.span) } else { ty.span } @@ -1255,7 +1254,7 @@ fn compare_self_type<'tcx>( get_self_string(self_arg_ty, can_eq_self) }; - match (trait_m.fn_has_self_parameter, impl_m.fn_has_self_parameter) { + match (trait_m.is_method(), impl_m.is_method()) { (false, false) | (true, true) => {} (false, true) => { @@ -1266,14 +1265,14 @@ fn compare_self_type<'tcx>( impl_m_span, E0185, "method `{}` has a `{}` declaration in the impl, but not in the trait", - trait_m.name, + trait_m.name(), self_descr ); err.span_label(impl_m_span, format!("`{self_descr}` used in impl")); 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, trait_m.signature(tcx)); + err.note_trait_signature(trait_m.name(), trait_m.signature(tcx)); } return Err(err.emit_unless(delay)); } @@ -1286,14 +1285,14 @@ fn compare_self_type<'tcx>( impl_m_span, E0186, "method `{}` has a `{}` declaration in the trait, but not in the impl", - trait_m.name, + trait_m.name(), self_descr ); err.span_label(impl_m_span, format!("expected `{self_descr}` in impl")); 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, trait_m.signature(tcx)); + err.note_trait_signature(trait_m.name(), trait_m.signature(tcx)); } return Err(err.emit_unless(delay)); @@ -1363,7 +1362,7 @@ fn compare_number_of_generics<'tcx>( let mut err_occurred = None; for (kind, trait_count, impl_count) in matchings { if impl_count != trait_count { - let arg_spans = |kind: ty::AssocKind, generics: &hir::Generics<'_>| { + let arg_spans = |item: &ty::AssocItem, generics: &hir::Generics<'_>| { let mut spans = generics .params .iter() @@ -1373,7 +1372,7 @@ fn compare_number_of_generics<'tcx>( } => { // A fn can have an arbitrary number of extra elided lifetimes for the // same signature. - !matches!(kind, ty::AssocKind::Fn) + !item.is_fn() } _ => true, }) @@ -1386,7 +1385,7 @@ fn compare_number_of_generics<'tcx>( }; let (trait_spans, impl_trait_spans) = if let Some(def_id) = trait_.def_id.as_local() { let trait_item = tcx.hir_expect_trait_item(def_id); - let arg_spans: Vec = arg_spans(trait_.kind, trait_item.generics); + let arg_spans: Vec = arg_spans(&trait_, trait_item.generics); let impl_trait_spans: Vec = trait_item .generics .params @@ -1412,7 +1411,7 @@ fn compare_number_of_generics<'tcx>( _ => None, }) .collect(); - let spans = arg_spans(impl_.kind, impl_item.generics); + let spans = arg_spans(&impl_, impl_item.generics); let span = spans.first().copied(); let mut err = tcx.dcx().struct_span_err( @@ -1421,7 +1420,7 @@ fn compare_number_of_generics<'tcx>( "{} `{}` has {} {kind} parameter{} but its trait \ declaration has {} {kind} parameter{}", item_kind, - trait_.name, + trait_.name(), impl_count, pluralize!(impl_count), trait_count, @@ -1512,7 +1511,7 @@ fn compare_number_of_method_arguments<'tcx>( impl_span, E0050, "method `{}` has {} but the declaration in trait `{}` has {}", - trait_m.name, + trait_m.name(), potentially_plural_count(impl_number_args, "parameter"), tcx.def_path_str(trait_m.def_id), trait_number_args @@ -1527,7 +1526,7 @@ fn compare_number_of_method_arguments<'tcx>( ), ); } else { - err.note_trait_signature(trait_m.name, trait_m.signature(tcx)); + err.note_trait_signature(trait_m.name(), trait_m.signature(tcx)); } err.span_label( @@ -1581,7 +1580,7 @@ fn compare_synthetic_generics<'tcx>( impl_span, E0643, "method `{}` has incompatible signature for trait", - trait_m.name + trait_m.name() ); err.span_label(trait_span, "declaration in trait here"); if impl_synthetic { @@ -1703,7 +1702,7 @@ fn compare_generic_param_kinds<'tcx>( trait_item: ty::AssocItem, delay: bool, ) -> Result<(), ErrorGuaranteed> { - assert_eq!(impl_item.kind, trait_item.kind); + assert_eq!(impl_item.as_tag(), trait_item.as_tag()); let ty_const_params_of = |def_id| { tcx.generics_of(def_id).own_params.iter().filter(|param| { @@ -1741,7 +1740,7 @@ fn compare_generic_param_kinds<'tcx>( E0053, "{} `{}` has an incompatible generic parameter for trait `{}`", impl_item.descr(), - trait_item.name, + trait_item.name(), &tcx.def_path_str(tcx.parent(trait_item.def_id)) ); @@ -1877,7 +1876,7 @@ fn compare_const_predicate_entailment<'tcx>( cause.span, E0326, "implemented const `{}` has an incompatible type for trait", - trait_ct.name + trait_ct.name() ); let trait_c_span = trait_ct.def_id.as_local().map(|trait_ct_def_id| { @@ -2235,16 +2234,19 @@ fn param_env_with_gat_bounds<'tcx>( // of the RPITITs associated with the same body. This is because checking // the item bounds of RPITITs often involves nested RPITITs having to prove // bounds about themselves. - let impl_tys_to_install = match impl_ty.opt_rpitit_info { - None => vec![impl_ty], - Some( - ty::ImplTraitInTraitData::Impl { fn_def_id } - | ty::ImplTraitInTraitData::Trait { fn_def_id, .. }, - ) => tcx + let impl_tys_to_install = match impl_ty.kind { + ty::AssocKind::Type { + data: + ty::AssocTypeData::Rpitit( + ty::ImplTraitInTraitData::Impl { fn_def_id } + | ty::ImplTraitInTraitData::Trait { fn_def_id, .. }, + ), + } => tcx .associated_types_for_impl_traits_in_associated_fn(fn_def_id) .iter() .map(|def_id| tcx.associated_item(*def_id)) .collect(), + _ => vec![impl_ty], }; for impl_ty in impl_tys_to_install { diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 42d785c8dd0f..89fb35154b75 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -1,9 +1,8 @@ -//! Type-checking for the rust-intrinsic intrinsics that the compiler exposes. +//! Type-checking for the `#[rustc_intrinsic]` intrinsics that the compiler exposes. use rustc_abi::ExternAbi; -use rustc_errors::codes::*; -use rustc_errors::{DiagMessage, struct_span_code_err}; -use rustc_hir::{self as hir, Safety}; +use rustc_errors::DiagMessage; +use rustc_hir::{self as hir}; use rustc_middle::bug; use rustc_middle::traits::{ObligationCause, ObligationCauseCode}; use rustc_middle::ty::{self, Ty, TyCtxt}; @@ -26,17 +25,10 @@ fn equate_intrinsic_type<'tcx>( sig: ty::PolyFnSig<'tcx>, ) { let (generics, span) = match tcx.hir_node_by_def_id(def_id) { - hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn { generics, .. }, .. }) - | hir::Node::ForeignItem(hir::ForeignItem { - kind: hir::ForeignItemKind::Fn(_, _, generics), - .. - }) => (tcx.generics_of(def_id), generics.span), - _ => { - struct_span_code_err!(tcx.dcx(), span, E0622, "intrinsic must be a function") - .with_span_label(span, "expected a function") - .emit(); - return; + hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn { generics, .. }, .. }) => { + (tcx.generics_of(def_id), generics.span) } + _ => tcx.dcx().span_bug(span, "intrinsic must be a function"), }; let own_counts = generics.own_counts(); @@ -70,13 +62,7 @@ fn equate_intrinsic_type<'tcx>( } /// Returns the unsafety of the given intrinsic. -pub fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hir::Safety { - let has_safe_attr = if tcx.has_attr(intrinsic_id, sym::rustc_intrinsic) { - tcx.fn_sig(intrinsic_id).skip_binder().safety() - } else { - // Old-style intrinsics are never safe - Safety::Unsafe - }; +fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hir::Safety { let is_in_list = match tcx.item_name(intrinsic_id.into()) { // When adding a new intrinsic to this list, // it's usually worth updating that intrinsic's documentation @@ -148,7 +134,7 @@ pub fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) - _ => hir::Safety::Unsafe, }; - if has_safe_attr != is_in_list { + if tcx.fn_sig(intrinsic_id).skip_binder().safety() != is_in_list { tcx.dcx().struct_span_err( tcx.def_span(intrinsic_id), DiagMessage::from(format!( @@ -163,12 +149,11 @@ pub fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) - /// Remember to add all intrinsics here, in `compiler/rustc_codegen_llvm/src/intrinsic.rs`, /// and in `library/core/src/intrinsics.rs`. -pub fn check_intrinsic_type( +pub(crate) fn check_intrinsic_type( tcx: TyCtxt<'_>, intrinsic_id: LocalDefId, span: Span, intrinsic_name: Symbol, - abi: ExternAbi, ) { let generics = tcx.generics_of(intrinsic_id); let param = |n| { @@ -232,15 +217,11 @@ pub fn check_intrinsic_type( }; (n_tps, 0, 0, inputs, output, hir::Safety::Unsafe) } else if intrinsic_name == sym::contract_check_ensures { - // contract_check_ensures::<'a, Ret, C>(&'a Ret, C) - // where C: impl Fn(&'a Ret) -> bool, + // contract_check_ensures::(Ret, C) -> Ret + // where C: for<'a> Fn(&'a Ret) -> bool, // - // so: two type params, one lifetime param, 0 const params, two inputs, no return - - let p = generics.param_at(0, tcx); - let r = ty::Region::new_early_param(tcx, p.to_early_bound_region_data()); - let ref_ret = Ty::new_imm_ref(tcx, r, param(1)); - (2, 1, 0, vec![ref_ret, param(2)], tcx.types.unit, hir::Safety::Safe) + // so: two type params, 0 lifetime param, 0 const params, two inputs, no return + (2, 0, 0, vec![param(0), param(1)], param(1), hir::Safety::Safe) } else { let safety = intrinsic_operation_unsafety(tcx, intrinsic_id); let (n_tps, n_cts, inputs, output) = match intrinsic_name { @@ -674,8 +655,12 @@ pub fn check_intrinsic_type( sym::simd_masked_load => (3, 0, vec![param(0), param(1), param(2)], param(2)), sym::simd_masked_store => (3, 0, vec![param(0), param(1), param(2)], tcx.types.unit), sym::simd_scatter => (3, 0, vec![param(0), param(1), param(2)], tcx.types.unit), - sym::simd_insert => (2, 0, vec![param(0), tcx.types.u32, param(1)], param(0)), - sym::simd_extract => (2, 0, vec![param(0), tcx.types.u32], param(1)), + sym::simd_insert | sym::simd_insert_dyn => { + (2, 0, vec![param(0), tcx.types.u32, param(1)], param(0)) + } + sym::simd_extract | sym::simd_extract_dyn => { + (2, 0, vec![param(0), tcx.types.u32], param(1)) + } sym::simd_cast | sym::simd_as | sym::simd_cast_ptr @@ -706,7 +691,7 @@ pub fn check_intrinsic_type( }; (n_tps, 0, n_cts, inputs, output, safety) }; - let sig = tcx.mk_fn_sig(inputs, output, false, safety, abi); + let sig = tcx.mk_fn_sig(inputs, output, false, safety, ExternAbi::Rust); let sig = ty::Binder::bind_with_vars(sig, bound_vars); equate_intrinsic_type(tcx, span, intrinsic_id, n_tps, n_lts, n_cts, sig) } diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index 7c5d7b33a34d..5fbd771976bb 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -137,15 +137,6 @@ fn get_owner_return_paths( }) } -/// Forbid defining intrinsics in Rust code, -/// as they must always be defined by the compiler. -// FIXME: Move this to a more appropriate place. -pub fn forbid_intrinsic_abi(tcx: TyCtxt<'_>, sp: Span, abi: ExternAbi) { - if let ExternAbi::RustIntrinsic = abi { - tcx.dcx().span_err(sp, "intrinsic must be in `extern \"rust-intrinsic\" { ... }` block"); - } -} - pub(super) 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 { @@ -214,7 +205,7 @@ fn missing_items_err( let missing_items_msg = missing_items .clone() - .map(|trait_item| trait_item.name.to_string()) + .map(|trait_item| trait_item.name().to_string()) .collect::>() .join("`, `"); @@ -245,7 +236,7 @@ fn missing_items_err( let code = format!("{padding}{snippet}\n{padding}"); if let Some(span) = tcx.hir_span_if_local(trait_item.def_id) { missing_trait_item_label - .push(errors::MissingTraitItemLabel { span, item: trait_item.name }); + .push(errors::MissingTraitItemLabel { span, item: trait_item.name() }); missing_trait_item.push(errors::MissingTraitItemSuggestion { span: sugg_sp, code, @@ -416,14 +407,14 @@ fn fn_sig_suggestion<'tcx>( .enumerate() .map(|(i, ty)| { Some(match ty.kind() { - ty::Param(_) if assoc.fn_has_self_parameter && i == 0 => "self".to_string(), + ty::Param(_) if assoc.is_method() && i == 0 => "self".to_string(), ty::Ref(reg, ref_ty, mutability) if i == 0 => { let reg = format!("{reg} "); let reg = match ®[..] { "'_ " | " " => "", reg => reg, }; - if assoc.fn_has_self_parameter { + if assoc.is_method() { match ref_ty.kind() { ty::Param(param) if param.name == kw::SelfUpper => { format!("&{}{}self", reg, mutability.prefix_str()) @@ -436,7 +427,7 @@ fn fn_sig_suggestion<'tcx>( } } _ => { - if assoc.fn_has_self_parameter && i == 0 { + if assoc.is_method() && i == 0 { format!("self: {ty}") } else { format!("_: {ty}") @@ -498,7 +489,7 @@ fn suggestion_signature<'tcx>( ); match assoc.kind { - ty::AssocKind::Fn => fn_sig_suggestion( + ty::AssocKind::Fn { .. } => fn_sig_suggestion( tcx, tcx.liberate_late_bound_regions( assoc.def_id, @@ -508,14 +499,14 @@ fn suggestion_signature<'tcx>( tcx.predicates_of(assoc.def_id).instantiate_own(tcx, args), assoc, ), - ty::AssocKind::Type => { + ty::AssocKind::Type { .. } => { let (generics, where_clauses) = bounds_from_generic_predicates( tcx, tcx.predicates_of(assoc.def_id).instantiate_own(tcx, args), ); - format!("type {}{generics} = /* Type */{where_clauses};", assoc.name) + format!("type {}{generics} = /* Type */{where_clauses};", assoc.name()) } - ty::AssocKind::Const => { + ty::AssocKind::Const { name } => { let ty = tcx.type_of(assoc.def_id).instantiate_identity(); let val = tcx .infer_ctxt() @@ -523,7 +514,7 @@ fn suggestion_signature<'tcx>( .err_ctxt() .ty_kind_suggestion(tcx.param_env(assoc.def_id), ty) .unwrap_or_else(|| "value".to_string()); - format!("const {}: {} = {};", assoc.name, ty, val) + format!("const {}: {} = {};", name, ty, val) } } } diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs index cf66ab708bb9..7cb31a64e13e 100644 --- a/compiler/rustc_hir_analysis/src/check/region.rs +++ b/compiler/rustc_hir_analysis/src/check/region.rs @@ -8,6 +8,7 @@ use std::mem; +use rustc_data_structures::fx::FxHashMap; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{self, Visitor}; @@ -44,6 +45,8 @@ struct ScopeResolutionVisitor<'tcx> { scope_tree: ScopeTree, cx: Context, + + extended_super_lets: FxHashMap>, } /// Records the lifetime of a local variable as `cx.var_parent` @@ -214,18 +217,29 @@ fn resolve_stmt<'tcx>(visitor: &mut ScopeResolutionVisitor<'tcx>, stmt: &'tcx hi let stmt_id = stmt.hir_id.local_id; debug!("resolve_stmt(stmt.id={:?})", stmt_id); - // Every statement will clean up the temporaries created during - // execution of that statement. Therefore each statement has an - // associated destruction scope that represents the scope of the - // statement plus its destructors, and thus the scope for which - // regions referenced by the destructors need to survive. + if let hir::StmtKind::Let(LetStmt { super_: Some(_), .. }) = stmt.kind { + // `super let` statement does not start a new scope, such that + // + // { super let x = identity(&temp()); &x }.method(); + // + // behaves exactly as + // + // (&identity(&temp()).method(); + intravisit::walk_stmt(visitor, stmt); + } else { + // Every statement will clean up the temporaries created during + // execution of that statement. Therefore each statement has an + // associated destruction scope that represents the scope of the + // statement plus its destructors, and thus the scope for which + // regions referenced by the destructors need to survive. - let prev_parent = visitor.cx.parent; - visitor.enter_node_scope_with_dtor(stmt_id, true); + let prev_parent = visitor.cx.parent; + visitor.enter_node_scope_with_dtor(stmt_id, true); - intravisit::walk_stmt(visitor, stmt); + intravisit::walk_stmt(visitor, stmt); - visitor.cx.parent = prev_parent; + visitor.cx.parent = prev_parent; + } } fn resolve_expr<'tcx>( @@ -446,14 +460,11 @@ fn resolve_expr<'tcx>( // Mark this expr's scope and all parent scopes as containing `yield`. let mut scope = Scope { local_id: expr.hir_id.local_id, data: ScopeData::Node }; loop { - let span = match expr.kind { - hir::ExprKind::Yield(expr, hir::YieldSource::Await { .. }) => { - expr.span.shrink_to_hi().to(expr.span) - } - _ => expr.span, + let data = YieldData { + span: expr.span, + expr_and_pat_count: visitor.expr_and_pat_count, + source: *source, }; - let data = - YieldData { span, expr_and_pat_count: visitor.expr_and_pat_count, source: *source }; match visitor.scope_tree.yield_in_scope.get_mut(&scope) { Some(yields) => yields.push(data), None => { @@ -481,14 +492,19 @@ fn resolve_expr<'tcx>( visitor.cx = prev_cx; } +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +enum LetKind { + Regular, + Super, +} + fn resolve_local<'tcx>( visitor: &mut ScopeResolutionVisitor<'tcx>, pat: Option<&'tcx hir::Pat<'tcx>>, init: Option<&'tcx hir::Expr<'tcx>>, + let_kind: LetKind, ) { - debug!("resolve_local(pat={:?}, init={:?})", pat, init); - - let blk_scope = visitor.cx.var_parent; + debug!("resolve_local(pat={:?}, init={:?}, let_kind={:?})", pat, init, let_kind); // As an exception to the normal rules governing temporary // lifetimes, initializers in a let have a temporary lifetime @@ -546,14 +562,50 @@ fn resolve_local<'tcx>( // A, but the inner rvalues `a()` and `b()` have an extended lifetime // due to rule C. + if let_kind == LetKind::Super { + if let Some(scope) = visitor.extended_super_lets.remove(&pat.unwrap().hir_id.local_id) { + // This expression was lifetime-extended by a parent let binding. E.g. + // + // let a = { + // super let b = temp(); + // &b + // }; + // + // (Which needs to behave exactly as: let a = &temp();) + // + // Processing of `let a` will have already decided to extend the lifetime of this + // `super let` to its own var_scope. We use that scope. + visitor.cx.var_parent = scope; + } else { + // This `super let` is not subject to lifetime extension from a parent let binding. E.g. + // + // identity({ super let x = temp(); &x }).method(); + // + // (Which needs to behave exactly as: identity(&temp()).method();) + // + // Iterate up to the enclosing destruction scope to find the same scope that will also + // be used for the result of the block itself. + while let Some(s) = visitor.cx.var_parent { + let parent = visitor.scope_tree.parent_map.get(&s).cloned(); + if let Some(Scope { data: ScopeData::Destruction, .. }) = parent { + break; + } + visitor.cx.var_parent = parent; + } + } + } + if let Some(expr) = init { - record_rvalue_scope_if_borrow_expr(visitor, expr, blk_scope); + record_rvalue_scope_if_borrow_expr(visitor, expr, visitor.cx.var_parent); if let Some(pat) = pat { if is_binding_pat(pat) { visitor.scope_tree.record_rvalue_candidate( expr.hir_id, - RvalueCandidate { target: expr.hir_id.local_id, lifetime: blk_scope }, + RvalueCandidate { + target: expr.hir_id.local_id, + lifetime: visitor.cx.var_parent, + }, ); } } @@ -565,6 +617,7 @@ fn resolve_local<'tcx>( if let Some(expr) = init { visitor.visit_expr(expr); } + if let Some(pat) = pat { visitor.visit_pat(pat); } @@ -626,6 +679,7 @@ fn resolve_local<'tcx>( PatKind::Ref(_, _) | PatKind::Binding(hir::BindingMode(hir::ByRef::No, _), ..) + | PatKind::Missing | PatKind::Wild | PatKind::Never | PatKind::Expr(_) @@ -642,6 +696,7 @@ fn resolve_local<'tcx>( /// | [ ..., E&, ... ] /// | ( ..., E&, ... ) /// | {...; E&} + /// | { super let ... = E&; ... } /// | if _ { ...; E& } else { ...; E& } /// | match _ { ..., _ => E&, ... } /// | box E& @@ -678,6 +733,13 @@ fn resolve_local<'tcx>( if let Some(subexpr) = block.expr { record_rvalue_scope_if_borrow_expr(visitor, subexpr, blk_id); } + for stmt in block.stmts { + if let hir::StmtKind::Let(local) = stmt.kind + && let Some(_) = local.super_ + { + visitor.extended_super_lets.insert(local.pat.hir_id.local_id, blk_id); + } + } } hir::ExprKind::If(_, then_block, else_block) => { record_rvalue_scope_if_borrow_expr(visitor, then_block, blk_id); @@ -803,7 +865,7 @@ impl<'tcx> Visitor<'tcx> for ScopeResolutionVisitor<'tcx> { local_id: body.value.hir_id.local_id, data: ScopeData::Destruction, }); - resolve_local(this, None, Some(body.value)); + resolve_local(this, None, Some(body.value), LetKind::Regular); } }) } @@ -821,7 +883,11 @@ impl<'tcx> Visitor<'tcx> for ScopeResolutionVisitor<'tcx> { resolve_expr(self, ex, false); } fn visit_local(&mut self, l: &'tcx LetStmt<'tcx>) { - resolve_local(self, Some(l.pat), l.init) + let let_kind = match l.super_ { + Some(_) => LetKind::Super, + None => LetKind::Regular, + }; + resolve_local(self, Some(l.pat), l.init, let_kind); } fn visit_inline_const(&mut self, c: &'tcx hir::ConstBlock) { let body = self.tcx.hir_body(c.body); @@ -850,6 +916,7 @@ pub(crate) fn region_scope_tree(tcx: TyCtxt<'_>, def_id: DefId) -> &ScopeTree { cx: Context { parent: None, var_parent: None }, pessimistic_yield: false, fixup_scopes: vec![], + extended_super_lets: Default::default(), }; visitor.scope_tree.root_body = Some(body.value.hir_id); diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 83d095ab72e8..33d5a86beb3b 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -408,7 +408,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, trait_def_id: LocalDefId) { let gat_def_id = gat_item.def_id.expect_local(); let gat_item = tcx.associated_item(gat_def_id); // If this item is not an assoc ty, or has no args, then it's not a GAT - if gat_item.kind != ty::AssocKind::Type { + if !gat_item.is_type() { continue; } let gat_generics = tcx.generics_of(gat_def_id); @@ -432,7 +432,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, trait_def_id: LocalDefId) { let item_required_bounds = match tcx.associated_item(item_def_id).kind { // In our example, this corresponds to `into_iter` method - ty::AssocKind::Fn => { + ty::AssocKind::Fn { .. } => { // For methods, we check the function signature's return type for any GATs // to constrain. In the `into_iter` case, we see that the return type // `Self::Iter<'a>` is a GAT we want to gather any potential missing bounds from. @@ -453,7 +453,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, trait_def_id: LocalDefId) { ) } // In our example, this corresponds to the `Iter` and `Item` associated types - ty::AssocKind::Type => { + ty::AssocKind::Type { .. } => { // If our associated item is a GAT with missing bounds, add them to // the param-env here. This allows this GAT to propagate missing bounds // to other GATs. @@ -474,7 +474,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, trait_def_id: LocalDefId) { gat_generics, ) } - ty::AssocKind::Const => None, + ty::AssocKind::Const { .. } => None, }; if let Some(item_required_bounds) = item_required_bounds { @@ -631,7 +631,7 @@ fn gather_gat_bounds<'tcx, T: TypeFoldable>>( // Ignore `'static` lifetimes for the purpose of this lint: it's // because we know it outlives everything and so doesn't give meaningful // clues. Also ignore `ReError`, to avoid knock-down errors. - if let ty::ReStatic | ty::ReError(_) = **region_a { + if let ty::ReStatic | ty::ReError(_) = region_a.kind() { continue; } // For each region argument (e.g., `'a` in our example), check for a @@ -672,7 +672,7 @@ fn gather_gat_bounds<'tcx, T: TypeFoldable>>( // Again, skip `'static` because it outlives everything. Also, we trivially // know that a region outlives itself. Also ignore `ReError`, to avoid // knock-down errors. - if matches!(**region_b, ty::ReStatic | ty::ReError(_)) || region_a == region_b { + if matches!(region_b.kind(), ty::ReStatic | ty::ReError(_)) || region_a == region_b { continue; } if region_known_to_outlive(tcx, item_def_id, param_env, wf_tys, *region_a, *region_b) { @@ -1076,7 +1076,7 @@ fn check_associated_item( }; match item.kind { - ty::AssocKind::Const => { + ty::AssocKind::Const { .. } => { let ty = tcx.type_of(item.def_id).instantiate_identity(); let ty = wfcx.normalize(span, Some(WellFormedLoc::Ty(item_id)), ty); wfcx.register_wf_obligation(span, loc, ty.into()); @@ -1089,7 +1089,7 @@ fn check_associated_item( ); Ok(()) } - ty::AssocKind::Fn => { + ty::AssocKind::Fn { .. } => { let sig = tcx.fn_sig(item.def_id).instantiate_identity(); let hir_sig = sig_if_method.expect("bad signature for method"); check_fn_or_method( @@ -1101,7 +1101,7 @@ fn check_associated_item( ); check_method_receiver(wfcx, hir_sig, item, self_ty) } - ty::AssocKind::Type => { + ty::AssocKind::Type { .. } => { if let ty::AssocItemContainer::Trait = item.container { check_associated_type_bounds(wfcx, item, span) } @@ -1716,7 +1716,7 @@ fn check_method_receiver<'tcx>( ) -> Result<(), ErrorGuaranteed> { let tcx = wfcx.tcx(); - if !method.fn_has_self_parameter { + if !method.is_method() { return Ok(()); } diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index 1f3f0b754bb1..8ad9d80c6b5a 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -656,7 +656,7 @@ fn infringing_fields_error<'tcx>( .entry((ty.clone(), predicate.clone())) .or_default() .push(origin.span()); - if let ty::RegionKind::ReEarlyParam(ebr) = *b + if let ty::RegionKind::ReEarlyParam(ebr) = b.kind() && ebr.has_name() { bounds.push((b.to_string(), a.to_string(), None)); diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs index dc616576c9c1..242639125b19 100644 --- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs +++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs @@ -51,7 +51,7 @@ impl<'tcx> InherentOverlapChecker<'tcx> { for &item1 in impl_items1.in_definition_order() { let collision = impl_items2 - .filter_by_name_unhygienic(item1.name) + .filter_by_name_unhygienic(item1.name()) .any(|&item2| self.compare_hygienically(item1, item2)); if collision { @@ -64,7 +64,7 @@ impl<'tcx> InherentOverlapChecker<'tcx> { fn compare_hygienically(&self, item1: ty::AssocItem, item2: ty::AssocItem) -> bool { // Symbols and namespace match, compare hygienically. - item1.kind.namespace() == item2.kind.namespace() + item1.namespace() == item2.namespace() && item1.ident(self.tcx).normalize_to_macros_2_0() == item2.ident(self.tcx).normalize_to_macros_2_0() } @@ -113,7 +113,7 @@ impl<'tcx> InherentOverlapChecker<'tcx> { let mut res = Ok(()); for &item1 in impl_items1.in_definition_order() { let collision = impl_items2 - .filter_by_name_unhygienic(item1.name) + .filter_by_name_unhygienic(item1.name()) .find(|&&item2| self.compare_hygienically(item1, item2)); if let Some(item2) = collision { @@ -230,11 +230,11 @@ impl<'tcx> InherentOverlapChecker<'tcx> { let mut ids = impl_items .in_definition_order() .filter_map(|item| { - let entry = connected_region_ids.entry(item.name); + let entry = connected_region_ids.entry(item.name()); if let IndexEntry::Occupied(e) = &entry { Some(*e.get()) } else { - idents_to_add.push(item.name); + idents_to_add.push(item.name()); None } }) diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 625f51dd29ea..4520fbe352ce 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -14,6 +14,7 @@ //! At present, however, we do run collection across all items in the //! crate as a kind of pass. This should eventually be factored away. +use std::assert_matches::assert_matches; use std::cell::Cell; use std::iter; use std::ops::Bound; @@ -42,9 +43,8 @@ use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::ObligationCtxt; use tracing::{debug, instrument}; -use crate::check::intrinsic::intrinsic_operation_unsafety; use crate::errors; -use crate::hir_ty_lowering::errors::assoc_kind_str; +use crate::hir_ty_lowering::errors::assoc_tag_str; use crate::hir_ty_lowering::{FeedConstTy, HirTyLowerer, RegionInferReason}; pub(crate) mod dump; @@ -439,9 +439,9 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> { &self, span: Span, def_id: LocalDefId, - assoc_name: Ident, + assoc_ident: Ident, ) -> ty::EarlyBinder<'tcx, &'tcx [(ty::Clause<'tcx>, Span)]> { - self.tcx.at(span).type_param_predicates((self.item_def_id, def_id, assoc_name)) + self.tcx.at(span).type_param_predicates((self.item_def_id, def_id, assoc_ident)) } fn lower_assoc_shared( @@ -450,7 +450,7 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> { item_def_id: DefId, item_segment: &rustc_hir::PathSegment<'tcx>, poly_trait_ref: ty::PolyTraitRef<'tcx>, - kind: ty::AssocKind, + assoc_tag: ty::AssocTag, ) -> Result<(DefId, ty::GenericArgsRef<'tcx>), ErrorGuaranteed> { if let Some(trait_ref) = poly_trait_ref.no_bound_vars() { let item_args = self.lowerer().lower_generic_args_of_assoc_item( @@ -525,7 +525,7 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> { inferred_sugg, bound, mpart_sugg, - what: assoc_kind_str(kind), + what: assoc_tag_str(assoc_tag), })) } } @@ -1345,7 +1345,8 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_, ty::PolyFn compute_sig_of_foreign_fn_decl(tcx, def_id, sig.decl, abi, sig.header.safety()) } - Ctor(data) | Variant(hir::Variant { data, .. }) if data.ctor().is_some() => { + Ctor(data) => { + assert_matches!(data.ctor(), Some(_)); let adt_def_id = tcx.hir_get_parent_item(hir_id).def_id.to_def_id(); let ty = tcx.type_of(adt_def_id).instantiate_identity(); let inputs = data.fields().iter().map(|f| tcx.type_of(f.def_id).instantiate_identity()); @@ -1417,7 +1418,7 @@ fn recover_infer_ret_ty<'tcx>( GenericParamKind::Lifetime { .. } => true, _ => false, }); - let fn_sig = fold_regions(tcx, fn_sig, |r, _| match *r { + let fn_sig = fold_regions(tcx, fn_sig, |r, _| match r.kind() { ty::ReErased => { if has_region_params { ty::Region::new_error_with_message( @@ -1704,18 +1705,13 @@ fn compute_sig_of_foreign_fn_decl<'tcx>( abi: ExternAbi, safety: hir::Safety, ) -> ty::PolyFnSig<'tcx> { - let safety = if abi == ExternAbi::RustIntrinsic { - intrinsic_operation_unsafety(tcx, def_id) - } else { - safety - }; let hir_id = tcx.local_def_id_to_hir_id(def_id); let fty = ItemCtxt::new(tcx, def_id).lowerer().lower_fn_ty(hir_id, safety, abi, decl, None, None); // Feature gate SIMD types in FFI, since I am not sure that the // ABIs are handled at all correctly. -huonw - if abi != ExternAbi::RustIntrinsic && !tcx.features().simd_ffi() { + if !tcx.features().simd_ffi() { let check = |hir_ty: &hir::Ty<'_>, ty: Ty<'_>| { if ty.is_simd() { let snip = tcx diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index 776b23bea8e1..ce0f83d0ec28 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -172,33 +172,9 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen }; if let Node::TraitItem(item) = node { - let parent = tcx.local_parent(item.hir_id().owner.def_id); - let Node::Item(parent_trait) = tcx.hir_node_by_def_id(parent) else { - unreachable!(); - }; - - let (trait_generics, trait_bounds) = match parent_trait.kind { - hir::ItemKind::Trait(_, _, _, generics, supertraits, _) => (generics, supertraits), - hir::ItemKind::TraitAlias(_, generics, supertraits) => (generics, supertraits), - _ => unreachable!(), - }; - - // Implicitly add `Self: DefaultAutoTrait` clauses on trait associated items if - // they are not added as super trait bounds to the trait itself. See comment on - // `requires_default_supertraits` for more details. - if !icx.lowerer().requires_default_supertraits(trait_bounds, trait_generics) { - let mut bounds = Vec::new(); - let self_ty_where_predicates = (parent, item.generics.predicates); - icx.lowerer().add_default_traits_with_filter( - &mut bounds, - tcx.types.self_param, - &[], - Some(self_ty_where_predicates), - item.span, - |tr| tr != hir::LangItem::Sized, - ); - predicates.extend(bounds); - } + let mut bounds = Vec::new(); + icx.lowerer().add_default_trait_item_bounds(item, &mut bounds); + predicates.extend(bounds); } let generics = tcx.generics_of(def_id); @@ -383,7 +359,7 @@ fn compute_bidirectional_outlives_predicates<'tcx>( ) { for param in opaque_own_params { let orig_lifetime = tcx.map_opaque_lifetime_to_parent_lifetime(param.def_id.expect_local()); - if let ty::ReEarlyParam(..) = *orig_lifetime { + if let ty::ReEarlyParam(..) = orig_lifetime.kind() { let dup_lifetime = ty::Region::new_early_param( tcx, ty::EarlyParamRegion { index: param.index, name: param.name }, @@ -608,12 +584,12 @@ pub(super) fn explicit_super_predicates_of<'tcx>( pub(super) fn explicit_supertraits_containing_assoc_item<'tcx>( tcx: TyCtxt<'tcx>, - (trait_def_id, assoc_name): (DefId, Ident), + (trait_def_id, assoc_ident): (DefId, Ident), ) -> ty::EarlyBinder<'tcx, &'tcx [(ty::Clause<'tcx>, Span)]> { implied_predicates_with_filter( tcx, trait_def_id, - PredicateFilter::SelfTraitThatDefines(assoc_name), + PredicateFilter::SelfTraitThatDefines(assoc_ident), ) } @@ -641,7 +617,7 @@ pub(super) fn implied_predicates_with_filter<'tcx>( filter: PredicateFilter, ) -> ty::EarlyBinder<'tcx, &'tcx [(ty::Clause<'tcx>, Span)]> { let Some(trait_def_id) = trait_def_id.as_local() else { - // if `assoc_name` is None, then the query should've been redirected to an + // if `assoc_ident` is None, then the query should've been redirected to an // external provider assert_matches!(filter, PredicateFilter::SelfTraitThatDefines(_)); return tcx.explicit_super_predicates_of(trait_def_id); @@ -858,11 +834,11 @@ pub(super) fn assert_only_contains_predicates_from<'tcx>( #[instrument(level = "trace", skip(tcx))] pub(super) fn type_param_predicates<'tcx>( tcx: TyCtxt<'tcx>, - (item_def_id, def_id, assoc_name): (LocalDefId, LocalDefId, Ident), + (item_def_id, def_id, assoc_ident): (LocalDefId, LocalDefId, Ident), ) -> ty::EarlyBinder<'tcx, &'tcx [(ty::Clause<'tcx>, Span)]> { match tcx.opt_rpitit_info(item_def_id.to_def_id()) { Some(ty::ImplTraitInTraitData::Trait { opaque_def_id, .. }) => { - return tcx.type_param_predicates((opaque_def_id.expect_local(), def_id, assoc_name)); + return tcx.type_param_predicates((opaque_def_id.expect_local(), def_id, assoc_ident)); } Some(ty::ImplTraitInTraitData::Impl { .. }) => { unreachable!("should not be lowering bounds on RPITIT in impl") @@ -887,7 +863,7 @@ pub(super) fn type_param_predicates<'tcx>( let result = if let Some(parent) = parent { let icx = ItemCtxt::new(tcx, parent); - icx.probe_ty_param_bounds(DUMMY_SP, def_id, assoc_name) + icx.probe_ty_param_bounds(DUMMY_SP, def_id, assoc_ident) } else { ty::EarlyBinder::bind(&[] as &[_]) }; @@ -913,7 +889,7 @@ pub(super) fn type_param_predicates<'tcx>( let extra_predicates = extend.into_iter().chain(icx.probe_ty_param_bounds_in_generics( hir_generics, def_id, - PredicateFilter::SelfTraitThatDefines(assoc_name), + PredicateFilter::SelfTraitThatDefines(assoc_ident), )); let bounds = @@ -932,7 +908,7 @@ pub(super) fn type_param_predicates<'tcx>( _ => unreachable!(), }; assert_only_contains_predicates_from( - PredicateFilter::SelfTraitThatDefines(assoc_name), + PredicateFilter::SelfTraitThatDefines(assoc_ident), bounds, self_ty, ); diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index 404753875ee5..59ab36d98fda 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -16,7 +16,7 @@ use rustc_errors::ErrorGuaranteed; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::{self, InferKind, Visitor, VisitorExt}; use rustc_hir::{ - self as hir, AmbigArg, GenericArg, GenericParam, GenericParamKind, HirId, LifetimeName, Node, + self as hir, AmbigArg, GenericArg, GenericParam, GenericParamKind, HirId, LifetimeKind, Node, }; use rustc_macros::extension; use rustc_middle::hir::nested_filter; @@ -646,14 +646,14 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { arg: &'tcx hir::PreciseCapturingArg<'tcx>, ) -> Self::Result { match *arg { - hir::PreciseCapturingArg::Lifetime(lt) => match lt.res { - LifetimeName::Param(def_id) => { + hir::PreciseCapturingArg::Lifetime(lt) => match lt.kind { + LifetimeKind::Param(def_id) => { self.resolve_lifetime_ref(def_id, lt); } - LifetimeName::Error => {} - LifetimeName::ImplicitObjectLifetimeDefault - | LifetimeName::Infer - | LifetimeName::Static => { + LifetimeKind::Error => {} + LifetimeKind::ImplicitObjectLifetimeDefault + | LifetimeKind::Infer + | LifetimeKind::Static => { self.tcx.dcx().emit_err(errors::BadPreciseCapture { span: lt.ident.span, kind: "lifetime", @@ -774,26 +774,26 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { ); } }); - match lifetime.res { - LifetimeName::ImplicitObjectLifetimeDefault => { + match lifetime.kind { + LifetimeKind::ImplicitObjectLifetimeDefault => { // If the user does not write *anything*, we // use the object lifetime defaulting // rules. So e.g., `Box` becomes // `Box`. self.resolve_object_lifetime_default(&*lifetime) } - LifetimeName::Infer => { + LifetimeKind::Infer => { // If the user writes `'_`, we use the *ordinary* elision // rules. So the `'_` in e.g., `Box` will be // resolved the same as the `'_` in `&'_ Foo`. // // cc #48468 } - LifetimeName::Param(..) | LifetimeName::Static => { + LifetimeKind::Param(..) | LifetimeKind::Static => { // If the user wrote an explicit name, use that. self.visit_lifetime(&*lifetime); } - LifetimeName::Error => {} + LifetimeKind::Error => {} } } hir::TyKind::Ref(lifetime_ref, ref mt) => { @@ -873,17 +873,17 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { #[instrument(level = "debug", skip(self))] fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) { - match lifetime_ref.res { - hir::LifetimeName::Static => { + match lifetime_ref.kind { + hir::LifetimeKind::Static => { self.insert_lifetime(lifetime_ref, ResolvedArg::StaticLifetime) } - hir::LifetimeName::Param(param_def_id) => { + hir::LifetimeKind::Param(param_def_id) => { self.resolve_lifetime_ref(param_def_id, lifetime_ref) } // If we've already reported an error, just ignore `lifetime_ref`. - hir::LifetimeName::Error => {} + hir::LifetimeKind::Error => {} // Those will be resolved by typechecking. - hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Infer => {} + hir::LifetimeKind::ImplicitObjectLifetimeDefault | hir::LifetimeKind::Infer => {} } } @@ -1063,15 +1063,15 @@ fn object_lifetime_default(tcx: TyCtxt<'_>, param_def_id: LocalDefId) -> ObjectL for bound in bound.bounds { if let hir::GenericBound::Outlives(lifetime) = bound { - set.insert(lifetime.res); + set.insert(lifetime.kind); } } } match set { Set1::Empty => ObjectLifetimeDefault::Empty, - Set1::One(hir::LifetimeName::Static) => ObjectLifetimeDefault::Static, - Set1::One(hir::LifetimeName::Param(param_def_id)) => { + Set1::One(hir::LifetimeKind::Static) => ObjectLifetimeDefault::Static, + Set1::One(hir::LifetimeKind::Param(param_def_id)) => { ObjectLifetimeDefault::Param(param_def_id.to_def_id()) } _ => ObjectLifetimeDefault::Ambiguous, @@ -1241,7 +1241,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { // 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(param_id) = lifetime_ref.res + && let hir::LifetimeKind::Param(param_id) = lifetime_ref.kind && let Some(generics) = self.tcx.hir_get_generics(self.tcx.local_parent(param_id)) && let Some(param) = generics.params.iter().find(|p| p.def_id == param_id) @@ -1811,7 +1811,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { self.tcx, type_def_id, constraint.ident, - ty::AssocKind::Fn, + ty::AssocTag::Fn, ) { bound_vars.extend( self.tcx @@ -1843,7 +1843,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { self.tcx, type_def_id, constraint.ident, - ty::AssocKind::Type, + ty::AssocTag::Type, ) .map(|(bound_vars, _)| bound_vars); self.with(scope, |this| { @@ -1874,14 +1874,14 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { fn supertrait_hrtb_vars( tcx: TyCtxt<'tcx>, def_id: DefId, - assoc_name: Ident, - assoc_kind: ty::AssocKind, + assoc_ident: Ident, + assoc_tag: ty::AssocTag, ) -> Option<(Vec, &'tcx ty::AssocItem)> { let trait_defines_associated_item_named = |trait_def_id: DefId| { - tcx.associated_items(trait_def_id).find_by_name_and_kind( + tcx.associated_items(trait_def_id).find_by_ident_and_kind( tcx, - assoc_name, - assoc_kind, + assoc_ident, + assoc_tag, trait_def_id, ) }; @@ -1894,8 +1894,8 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { let Some((def_id, bound_vars)) = stack.pop() else { break None; }; - // See issue #83753. If someone writes an associated type on a non-trait, just treat it as - // there being no supertrait HRTBs. + // See issue #83753. If someone writes an associated type on a non-trait, just treat it + // as there being no supertrait HRTBs. match tcx.def_kind(def_id) { DefKind::Trait | DefKind::TraitAlias | DefKind::Impl { .. } => {} _ => break None, @@ -1904,7 +1904,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { if let Some(assoc_item) = trait_defines_associated_item_named(def_id) { break Some((bound_vars.into_iter().collect(), assoc_item)); } - let predicates = tcx.explicit_supertraits_containing_assoc_item((def_id, assoc_name)); + let predicates = tcx.explicit_supertraits_containing_assoc_item((def_id, assoc_ident)); let obligations = predicates.iter_identity_copied().filter_map(|(pred, _)| { let bound_predicate = pred.kind(); match bound_predicate.skip_binder() { @@ -2067,7 +2067,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { self.tcx, trait_def_id, item_segment.ident, - ty::AssocKind::Fn, + ty::AssocTag::Fn, ) }); @@ -2112,7 +2112,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { self.tcx, trait_def_id, item_segment.ident, - ty::AssocKind::Fn, + ty::AssocTag::Fn, ) else { return; }; @@ -2440,7 +2440,7 @@ fn is_late_bound_map( } fn visit_lifetime(&mut self, lifetime_ref: &'v hir::Lifetime) { - if let hir::LifetimeName::Param(def_id) = lifetime_ref.res { + if let hir::LifetimeKind::Param(def_id) = lifetime_ref.kind { self.regions.insert(def_id); } } @@ -2453,7 +2453,7 @@ fn is_late_bound_map( impl<'tcx> Visitor<'tcx> for AllCollector { fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) { - if let hir::LifetimeName::Param(def_id) = lifetime_ref.res { + if let hir::LifetimeKind::Param(def_id) = lifetime_ref.kind { self.regions.insert(def_id); } } diff --git a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs index 3fe3d71b32da..50e20a19edae 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs @@ -32,9 +32,11 @@ pub(super) fn find_opaque_ty_constraints_for_impl_trait_in_assoc_type( for &assoc_id in tcx.associated_item_def_ids(impl_def_id) { let assoc = tcx.associated_item(assoc_id); match assoc.kind { - ty::AssocKind::Const | ty::AssocKind::Fn => locator.check(assoc_id.expect_local()), + ty::AssocKind::Const { .. } | ty::AssocKind::Fn { .. } => { + locator.check(assoc_id.expect_local()) + } // Associated types don't have bodies, so they can't constrain hidden types - ty::AssocKind::Type => {} + ty::AssocKind::Type { .. } => {} } } @@ -183,25 +185,23 @@ impl<'tcx> TaitConstraintLocator<'tcx> { self.non_defining_use_in_defining_scope(item_def_id); } } - DefiningScopeKind::MirBorrowck => { - let borrowck_result = tcx.mir_borrowck(item_def_id); - if let Some(guar) = borrowck_result.tainted_by_errors { - self.insert_found(ty::OpaqueHiddenType::new_error(tcx, guar)); - } else if let Some(&hidden_type) = - borrowck_result.concrete_opaque_types.get(&self.def_id) - { - debug!(?hidden_type, "found constraint"); - self.insert_found(hidden_type); - } else if let Err(guar) = tcx - .type_of_opaque_hir_typeck(self.def_id) - .instantiate_identity() - .error_reported() - { - self.insert_found(ty::OpaqueHiddenType::new_error(tcx, guar)); - } else { - self.non_defining_use_in_defining_scope(item_def_id); + DefiningScopeKind::MirBorrowck => match tcx.mir_borrowck(item_def_id) { + Err(guar) => self.insert_found(ty::OpaqueHiddenType::new_error(tcx, guar)), + Ok(concrete_opaque_types) => { + if let Some(&hidden_type) = concrete_opaque_types.0.get(&self.def_id) { + debug!(?hidden_type, "found constraint"); + self.insert_found(hidden_type); + } else if let Err(guar) = tcx + .type_of_opaque_hir_typeck(self.def_id) + .instantiate_identity() + .error_reported() + { + self.insert_found(ty::OpaqueHiddenType::new_error(tcx, guar)); + } else { + self.non_defining_use_in_defining_scope(item_def_id); + } } - } + }, } } } @@ -264,20 +264,20 @@ pub(super) fn find_opaque_ty_constraints_for_rpit<'tcx>( Ty::new_diverging_default(tcx) } } - DefiningScopeKind::MirBorrowck => { - let borrowck_result = tcx.mir_borrowck(owner_def_id); - if let Some(guar) = borrowck_result.tainted_by_errors { - Ty::new_error(tcx, guar) - } else if let Some(hidden_ty) = borrowck_result.concrete_opaque_types.get(&def_id) { - hidden_ty.ty - } else { - let hir_ty = tcx.type_of_opaque_hir_typeck(def_id).instantiate_identity(); - if let Err(guar) = hir_ty.error_reported() { - Ty::new_error(tcx, guar) + DefiningScopeKind::MirBorrowck => match tcx.mir_borrowck(owner_def_id) { + Ok(concrete_opaque_types) => { + if let Some(hidden_ty) = concrete_opaque_types.0.get(&def_id) { + hidden_ty.ty } else { - hir_ty + let hir_ty = tcx.type_of_opaque_hir_typeck(def_id).instantiate_identity(); + if let Err(guar) = hir_ty.error_reported() { + Ty::new_error(tcx, guar) + } else { + hir_ty + } } } - } + Err(guar) => Ty::new_error(tcx, guar), + }, } } diff --git a/compiler/rustc_hir_analysis/src/constrained_generic_params.rs b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs index 53866aa27b16..951eda72ffed 100644 --- a/compiler/rustc_hir_analysis/src/constrained_generic_params.rs +++ b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs @@ -80,7 +80,7 @@ impl<'tcx> TypeVisitor> for ParameterCollector { } fn visit_region(&mut self, r: ty::Region<'tcx>) { - if let ty::ReEarlyParam(data) = *r { + if let ty::ReEarlyParam(data) = r.kind() { self.parameters.push(Parameter::from(data)); } } diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index f2560f22874b..508970cf2554 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -23,7 +23,7 @@ pub(crate) struct AmbiguousAssocItem<'a> { #[label] pub span: Span, pub assoc_kind: &'static str, - pub assoc_name: Ident, + pub assoc_ident: Ident, pub qself: &'a str, } @@ -75,7 +75,7 @@ pub(crate) struct AssocItemIsPrivate { pub(crate) struct AssocItemNotFound<'a> { #[primary_span] pub span: Span, - pub assoc_name: Ident, + pub assoc_ident: Ident, pub assoc_kind: &'static str, pub qself: &'a str, #[subdiagnostic] @@ -1707,3 +1707,11 @@ pub(crate) enum SupertraitItemShadowee { traits: DiagSymbolList, }, } + +#[derive(Diagnostic)] +#[diag(hir_analysis_self_in_type_alias, code = E0411)] +pub(crate) struct SelfInTypeAlias { + #[primary_span] + #[label] + pub span: Span, +} diff --git a/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs b/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs index 610b293a114e..526ee30209c7 100644 --- a/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs +++ b/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs @@ -4,7 +4,7 @@ use GenericArgsInfo::*; use rustc_errors::codes::*; use rustc_errors::{Applicability, Diag, Diagnostic, EmissionGuarantee, MultiSpan, pluralize}; use rustc_hir as hir; -use rustc_middle::ty::{self as ty, AssocItems, AssocKind, TyCtxt}; +use rustc_middle::ty::{self as ty, AssocItems, TyCtxt}; use rustc_span::def_id::DefId; use tracing::debug; @@ -486,13 +486,13 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { let items: &AssocItems = self.tcx.associated_items(self.def_id); items .in_definition_order() - .filter(|item| item.kind == AssocKind::Type) + .filter(|item| item.is_type()) .filter(|item| { !self .gen_args .constraints .iter() - .any(|constraint| constraint.ident.name == item.name) + .any(|constraint| constraint.ident.name == item.name()) }) .filter(|item| !item.is_impl_trait_in_trait()) .map(|item| self.tcx.item_ident(item.def_id).to_string()) diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs index c3bb860538ee..bf91eb1b8fda 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -43,12 +43,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } /// Checks whether `Self: DefaultAutoTrait` bounds should be added on trait super bounds - /// or associative items. + /// or associated items. /// /// To keep backward compatibility with existing code, `experimental_default_bounds` bounds /// should be added everywhere, including super bounds. However this causes a huge performance /// costs. For optimization purposes instead of adding default supertraits, bounds - /// are added to the associative items: + /// are added to the associated items: /// /// ```ignore(illustrative) /// // Default bounds are generated in the following way: @@ -81,7 +81,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { /// /// Therefore, `experimental_default_bounds` are still being added to supertraits if /// the `SelfTyParam` or `AssocItemConstraint` were found in a trait header. - pub(crate) fn requires_default_supertraits( + fn requires_default_supertraits( &self, hir_bounds: &'tcx [hir::GenericBound<'tcx>], hir_generics: &'tcx hir::Generics<'tcx>, @@ -120,6 +120,43 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { found } + /// Implicitly add `Self: DefaultAutoTrait` clauses on trait associated items if + /// they are not added as super trait bounds to the trait itself. See + /// `requires_default_supertraits` for more information. + pub(crate) fn add_default_trait_item_bounds( + &self, + trait_item: &hir::TraitItem<'tcx>, + bounds: &mut Vec<(ty::Clause<'tcx>, Span)>, + ) { + let tcx = self.tcx(); + if !tcx.sess.opts.unstable_opts.experimental_default_bounds { + return; + } + + let parent = tcx.local_parent(trait_item.hir_id().owner.def_id); + let hir::Node::Item(parent_trait) = tcx.hir_node_by_def_id(parent) else { + unreachable!(); + }; + + let (trait_generics, trait_bounds) = match parent_trait.kind { + hir::ItemKind::Trait(_, _, _, generics, supertraits, _) => (generics, supertraits), + hir::ItemKind::TraitAlias(_, generics, supertraits) => (generics, supertraits), + _ => unreachable!(), + }; + + if !self.requires_default_supertraits(trait_bounds, trait_generics) { + let self_ty_where_predicates = (parent, trait_item.generics.predicates); + self.add_default_traits_with_filter( + bounds, + tcx.types.self_param, + &[], + Some(self_ty_where_predicates), + trait_item.span, + |tr| tr != hir::LangItem::Sized, + ); + } + } + /// Lazily sets `experimental_default_bounds` to true on trait super bounds. /// See `requires_default_supertraits` for more information. pub(crate) fn add_default_super_traits( @@ -130,6 +167,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { hir_generics: &'tcx hir::Generics<'tcx>, span: Span, ) { + if !self.tcx().sess.opts.unstable_opts.experimental_default_bounds { + return; + } + assert!(matches!(self.tcx().def_kind(trait_def_id), DefKind::Trait | DefKind::TraitAlias)); if self.requires_default_supertraits(hir_bounds, hir_generics) { let self_ty_where_predicates = (trait_def_id, hir_generics.predicates); @@ -263,11 +304,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { seen_unbound = true; } let emit_relax_err = || { - let unbound_traits = - match self.tcx().sess.opts.unstable_opts.experimental_default_bounds { - true => "`?Sized` and `experimental_default_bounds`", - false => "`?Sized`", - }; + let unbound_traits = match tcx.sess.opts.unstable_opts.experimental_default_bounds { + true => "`?Sized` and `experimental_default_bounds`", + false => "`?Sized`", + }; // There was a `?Trait` bound, but it was neither `?Sized` nor `experimental_default_bounds`. tcx.dcx().span_err( unbound.span, @@ -323,10 +363,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { for hir_bound in hir_bounds { // In order to avoid cycles, when we're lowering `SelfTraitThatDefines`, // we skip over any traits that don't define the given associated type. - if let PredicateFilter::SelfTraitThatDefines(assoc_name) = predicate_filter { + if let PredicateFilter::SelfTraitThatDefines(assoc_ident) = predicate_filter { if let Some(trait_ref) = hir_bound.trait_ref() && let Some(trait_did) = trait_ref.trait_def_id() - && self.tcx().trait_may_define_assoc_item(trait_did, assoc_name) + && self.tcx().trait_may_define_assoc_item(trait_did, assoc_ident) { // Okay } else { @@ -391,16 +431,16 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ) -> Result<(), ErrorGuaranteed> { let tcx = self.tcx(); - let assoc_kind = if constraint.gen_args.parenthesized + let assoc_tag = if constraint.gen_args.parenthesized == hir::GenericArgsParentheses::ReturnTypeNotation { - ty::AssocKind::Fn + ty::AssocTag::Fn } else if let hir::AssocItemConstraintKind::Equality { term: hir::Term::Const(_) } = constraint.kind { - ty::AssocKind::Const + ty::AssocTag::Const } else { - ty::AssocKind::Type + ty::AssocTag::Type }; // Given something like `U: Trait`, we want to produce a predicate like @@ -413,7 +453,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // trait SuperTrait { type T; } let candidate = if self.probe_trait_that_defines_assoc_item( trait_ref.def_id(), - assoc_kind, + assoc_tag, constraint.ident, ) { // Simple case: The assoc item is defined in the current trait. @@ -424,7 +464,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { self.probe_single_bound_for_assoc_item( || traits::supertraits(tcx, trait_ref), AssocItemQSelf::Trait(trait_ref.def_id()), - assoc_kind, + assoc_tag, constraint.ident, path_span, Some(constraint), @@ -434,7 +474,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let assoc_item = self .probe_assoc_item( constraint.ident, - assoc_kind, + assoc_tag, hir_ref_id, constraint.span, candidate.def_id(), @@ -453,7 +493,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { }) .or_insert(constraint.span); - let projection_term = if let ty::AssocKind::Fn = assoc_kind { + let projection_term = if let ty::AssocTag::Fn = assoc_tag { let bound_vars = tcx.late_bound_vars(constraint.hir_id); ty::Binder::bind_with_vars( self.lower_return_type_notation_ty(candidate, assoc_item.def_id, path_span)?.into(), @@ -502,7 +542,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { }; match constraint.kind { - hir::AssocItemConstraintKind::Equality { .. } if let ty::AssocKind::Fn = assoc_kind => { + hir::AssocItemConstraintKind::Equality { .. } if let ty::AssocTag::Fn = assoc_tag => { return Err(self.dcx().emit_err(crate::errors::ReturnTypeNotationEqualityBound { span: constraint.span, })); @@ -639,7 +679,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { trait_def_id, hir_ty.span, item_segment, - ty::AssocKind::Type, + ty::AssocTag::Type, ); return Ty::new_error(tcx, guar); }; @@ -731,7 +771,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ) }, AssocItemQSelf::SelfTyAlias, - ty::AssocKind::Fn, + ty::AssocTag::Fn, assoc_ident, span, None, @@ -743,7 +783,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ) => self.probe_single_ty_param_bound_for_assoc_item( param_did.expect_local(), qself.span, - ty::AssocKind::Fn, + ty::AssocTag::Fn, assoc_ident, span, )?, @@ -783,7 +823,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let trait_def_id = bound.def_id(); let assoc_ty = self - .probe_assoc_item(assoc_ident, ty::AssocKind::Fn, qpath_hir_id, span, trait_def_id) + .probe_assoc_item(assoc_ident, ty::AssocTag::Fn, qpath_hir_id, span, trait_def_id) .expect("failed to find associated type"); Ok((bound, assoc_ty.def_id)) diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs index ecb453bced0a..d1ee5a5494c0 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs @@ -49,13 +49,13 @@ pub(crate) fn validate_cmse_abi<'tcx>( Ok(Err(index)) => { // fn(x: u32, u32, u32, u16, y: u16) -> u32, // ^^^^^^ - let span = if let Some(ident) = bare_fn_ty.param_names[index] { + let span = if let Some(ident) = bare_fn_ty.param_idents[index] { ident.span.to(bare_fn_ty.decl.inputs[index].span) } else { bare_fn_ty.decl.inputs[index].span } .to(bare_fn_ty.decl.inputs.last().unwrap().span); - let plural = bare_fn_ty.param_names.len() - index != 1; + let plural = bare_fn_ty.param_idents.len() - index != 1; dcx.emit_err(errors::CmseInputsStackSpill { span, plural, abi }); } Err(layout_err) => { diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs index aeebe45f881f..88f745892048 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs @@ -16,6 +16,7 @@ use smallvec::{SmallVec, smallvec}; use tracing::{debug, instrument}; use super::HirTyLowerer; +use crate::errors::SelfInTypeAlias; use crate::hir_ty_lowering::{ GenericArgCountMismatch, GenericArgCountResult, PredicateFilter, RegionInferReason, }; @@ -125,6 +126,19 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // ``` let mut projection_bounds = FxIndexMap::default(); for (proj, proj_span) in elaborated_projection_bounds { + let proj = proj.map_bound(|mut b| { + if let Some(term_ty) = &b.term.as_type() { + let references_self = term_ty.walk().any(|arg| arg == dummy_self.into()); + if references_self { + // With trait alias and type alias combined, type resolver + // may not be able to catch all illegal `Self` usages (issue 139082) + let guar = tcx.dcx().emit_err(SelfInTypeAlias { span }); + b.term = replace_dummy_self_with_error(tcx, b.term, guar); + } + } + b + }); + let key = ( proj.skip_binder().projection_term.def_id, tcx.anonymize_bound_vars( @@ -187,7 +201,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { tcx.associated_items(pred.trait_ref.def_id) .in_definition_order() // We only care about associated types. - .filter(|item| item.kind == ty::AssocKind::Type) + .filter(|item| item.is_type()) // No RPITITs -- they're not dyn-compatible for now. .filter(|item| !item.is_impl_trait_in_trait()) // If the associated type has a `where Self: Sized` bound, @@ -401,7 +415,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { self.lower_lifetime(lifetime, RegionInferReason::ExplicitObjectLifetime) } else { let reason = - if let hir::LifetimeName::ImplicitObjectLifetimeDefault = lifetime.res { + if let hir::LifetimeKind::ImplicitObjectLifetimeDefault = lifetime.kind { if let hir::Node::Ty(hir::Ty { kind: hir::TyKind::Ref(parent_lifetime, _), .. diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs index 6e9c178d33a6..3759a224ff75 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs @@ -116,8 +116,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { &self, all_candidates: impl Fn() -> I, qself: AssocItemQSelf, - assoc_kind: ty::AssocKind, - assoc_name: Ident, + assoc_tag: ty::AssocTag, + assoc_ident: Ident, span: Span, constraint: Option<&hir::AssocItemConstraint<'tcx>>, ) -> ErrorGuaranteed @@ -129,31 +129,35 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // First and foremost, provide a more user-friendly & “intuitive” error on kind mismatches. if let Some(assoc_item) = all_candidates().find_map(|r| { tcx.associated_items(r.def_id()) - .filter_by_name_unhygienic(assoc_name.name) - .find(|item| tcx.hygienic_eq(assoc_name, item.ident(tcx), r.def_id())) + .filter_by_name_unhygienic(assoc_ident.name) + .find(|item| tcx.hygienic_eq(assoc_ident, item.ident(tcx), r.def_id())) }) { return self.complain_about_assoc_kind_mismatch( - assoc_item, assoc_kind, assoc_name, span, constraint, + assoc_item, + assoc_tag, + assoc_ident, + span, + constraint, ); } - let assoc_kind_str = assoc_kind_str(assoc_kind); + let assoc_kind_str = assoc_tag_str(assoc_tag); let qself_str = qself.to_string(tcx); // The fallback span is needed because `assoc_name` might be an `Fn()`'s `Output` without a // valid span, so we point at the whole path segment instead. - let is_dummy = assoc_name.span == DUMMY_SP; + let is_dummy = assoc_ident.span == DUMMY_SP; let mut err = errors::AssocItemNotFound { - span: if is_dummy { span } else { assoc_name.span }, - assoc_name, + span: if is_dummy { span } else { assoc_ident.span }, + assoc_ident, assoc_kind: assoc_kind_str, qself: &qself_str, label: None, sugg: None, // Try to get the span of the identifier within the path's syntax context // (if that's different). - within_macro_span: assoc_name.span.within_macro(span, tcx.sess.source_map()), + within_macro_span: assoc_ident.span.within_macro(span, tcx.sess.source_map()), }; if is_dummy { @@ -164,15 +168,19 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let all_candidate_names: Vec<_> = all_candidates() .flat_map(|r| tcx.associated_items(r.def_id()).in_definition_order()) .filter_map(|item| { - (!item.is_impl_trait_in_trait() && item.kind == assoc_kind).then_some(item.name) + if !item.is_impl_trait_in_trait() && item.as_tag() == assoc_tag { + item.opt_name() + } else { + None + } }) .collect(); if let Some(suggested_name) = - find_best_match_for_name(&all_candidate_names, assoc_name.name, None) + find_best_match_for_name(&all_candidate_names, assoc_ident.name, None) { err.sugg = Some(errors::AssocItemNotFoundSugg::Similar { - span: assoc_name.span, + span: assoc_ident.span, assoc_kind: assoc_kind_str, suggested_name, }); @@ -196,12 +204,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .iter() .flat_map(|trait_def_id| tcx.associated_items(*trait_def_id).in_definition_order()) .filter_map(|item| { - (!item.is_impl_trait_in_trait() && item.kind == assoc_kind).then_some(item.name) + (!item.is_impl_trait_in_trait() && item.as_tag() == assoc_tag).then(|| item.name()) }) .collect(); if let Some(suggested_name) = - find_best_match_for_name(&wider_candidate_names, assoc_name.name, None) + find_best_match_for_name(&wider_candidate_names, assoc_ident.name, None) { if let [best_trait] = visible_traits .iter() @@ -209,17 +217,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .filter(|trait_def_id| { tcx.associated_items(trait_def_id) .filter_by_name_unhygienic(suggested_name) - .any(|item| item.kind == assoc_kind) + .any(|item| item.as_tag() == assoc_tag) }) .collect::>()[..] { let trait_name = tcx.def_path_str(best_trait); err.label = Some(errors::AssocItemNotFoundLabel::FoundInOtherTrait { - span: assoc_name.span, + span: assoc_ident.span, assoc_kind: assoc_kind_str, trait_name: &trait_name, suggested_name, - identically_named: suggested_name == assoc_name.name, + identically_named: suggested_name == assoc_ident.name, }); if let AssocItemQSelf::TyParam(ty_param_def_id, ty_param_span) = qself // Not using `self.item_def_id()` here as that would yield the opaque type itself if we're @@ -246,7 +254,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // The type param already has a bound for `trait_name`, we just need to // change the associated item. err.sugg = Some(errors::AssocItemNotFoundSugg::SimilarInOtherTrait { - span: assoc_name.span, + span: assoc_ident.span, assoc_kind: assoc_kind_str, suggested_name, }); @@ -265,7 +273,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { Applicability::MaybeIncorrect }; - let identically_named = suggested_name == assoc_name.name; + let identically_named = suggested_name == assoc_ident.name; if let DefKind::TyAlias = tcx.def_kind(item_def_id) && !tcx.type_alias_is_lazy(item_def_id) @@ -273,7 +281,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { err.sugg = Some(errors::AssocItemNotFoundSugg::SimilarInOtherTraitQPath { lo: ty_param_span.shrink_to_lo(), mi: ty_param_span.shrink_to_hi(), - hi: (!identically_named).then_some(assoc_name.span), + hi: (!identically_named).then_some(assoc_ident.span), trait_ref, identically_named, suggested_name, @@ -294,7 +302,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // We suggested constraining a type parameter, but the associated item on it // was also not an exact match, so we also suggest changing it. err.span_suggestion_verbose( - assoc_name.span, + assoc_ident.span, fluent::hir_analysis_assoc_item_not_found_similar_in_other_trait_with_bound_sugg, suggested_name, Applicability::MaybeIncorrect, @@ -311,13 +319,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // suggest using it. if let [candidate_name] = all_candidate_names.as_slice() { err.sugg = Some(errors::AssocItemNotFoundSugg::Other { - span: assoc_name.span, + span: assoc_ident.span, qself: &qself_str, assoc_kind: assoc_kind_str, suggested_name: *candidate_name, }); } else { - err.label = Some(errors::AssocItemNotFoundLabel::NotFound { span: assoc_name.span }); + err.label = Some(errors::AssocItemNotFoundLabel::NotFound { span: assoc_ident.span }); } self.dcx().emit_err(err) @@ -326,14 +334,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { fn complain_about_assoc_kind_mismatch( &self, assoc_item: &ty::AssocItem, - assoc_kind: ty::AssocKind, + assoc_tag: ty::AssocTag, ident: Ident, span: Span, constraint: Option<&hir::AssocItemConstraint<'tcx>>, ) -> ErrorGuaranteed { let tcx = self.tcx(); - let bound_on_assoc_const_label = if let ty::AssocKind::Const = assoc_item.kind + let bound_on_assoc_const_label = if let ty::AssocKind::Const { .. } = assoc_item.kind && let Some(constraint) = constraint && let hir::AssocItemConstraintKind::Bound { .. } = constraint.kind { @@ -371,17 +379,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { hir::Term::Ty(ty) => ty.span, hir::Term::Const(ct) => ct.span(), }; - (span, Some(ident.span), assoc_item.kind, assoc_kind) + (span, Some(ident.span), assoc_item.as_tag(), assoc_tag) } else { - (ident.span, None, assoc_kind, assoc_item.kind) + (ident.span, None, assoc_tag, assoc_item.as_tag()) }; self.dcx().emit_err(errors::AssocKindMismatch { span, - expected: assoc_kind_str(expected), - got: assoc_kind_str(got), + expected: assoc_tag_str(expected), + got: assoc_tag_str(got), expected_because_label, - assoc_kind: assoc_kind_str(assoc_item.kind), + assoc_kind: assoc_tag_str(assoc_item.as_tag()), def_span: tcx.def_span(assoc_item.def_id), bound_on_assoc_const_label, wrap_in_braces_sugg, @@ -394,9 +402,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { types: &[String], traits: &[String], name: Symbol, - kind: ty::AssocKind, + assoc_tag: ty::AssocTag, ) -> ErrorGuaranteed { - let kind_str = assoc_kind_str(kind); + let kind_str = assoc_tag_str(assoc_tag); let mut err = struct_span_code_err!(self.dcx(), span, E0223, "ambiguous associated {kind_str}"); if self @@ -565,7 +573,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { candidates: Vec<(DefId, (DefId, DefId))>, fulfillment_errors: Vec>, span: Span, - kind: ty::AssocKind, + assoc_tag: ty::AssocTag, ) -> ErrorGuaranteed { // FIXME(fmease): This was copied in parts from an old version of `rustc_hir_typeck::method::suggest`. // Either @@ -575,14 +583,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let tcx = self.tcx(); - let kind_str = assoc_kind_str(kind); + let assoc_tag_str = assoc_tag_str(assoc_tag); let adt_did = self_ty.ty_adt_def().map(|def| def.did()); let add_def_label = |err: &mut Diag<'_>| { if let Some(did) = adt_did { err.span_label( tcx.def_span(did), format!( - "associated {kind_str} `{name}` not found for this {}", + "associated {assoc_tag_str} `{name}` not found for this {}", tcx.def_descr(did) ), ); @@ -611,11 +619,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { self.dcx(), name.span, E0220, - "associated {kind_str} `{name}` not found for `{self_ty}` in the current scope" + "associated {assoc_tag_str} `{name}` not found for `{self_ty}` in the current scope" ); err.span_label(name.span, format!("associated item not found in `{self_ty}`")); err.note(format!( - "the associated {kind_str} was found for\n{type_candidates}{additional_types}", + "the associated {assoc_tag_str} was found for\n{type_candidates}{additional_types}", )); add_def_label(&mut err); return err.emit(); @@ -696,7 +704,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let mut err = self.dcx().struct_span_err( name.span, - format!("the associated {kind_str} `{name}` exists for `{self_ty}`, but its trait bounds were not satisfied") + format!("the associated {assoc_tag_str} `{name}` exists for `{self_ty}`, but its trait bounds were not satisfied") ); if !bounds.is_empty() { err.note(format!( @@ -706,7 +714,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } err.span_label( name.span, - format!("associated {kind_str} cannot be referenced on `{self_ty}` due to unsatisfied trait bounds") + format!("associated {assoc_tag_str} cannot be referenced on `{self_ty}` due to unsatisfied trait bounds") ); for (span, mut bounds) in bound_spans { @@ -757,7 +765,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // `issue-22560.rs`. let mut dyn_compatibility_violations = Ok(()); for (assoc_item, trait_ref) in &missing_assoc_types { - names.entry(trait_ref).or_default().push(assoc_item.name); + names.entry(trait_ref).or_default().push(assoc_item.name()); names_len += 1; let violations = @@ -805,10 +813,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { return None; }; - let assoc_item = tcx.associated_items(trait_def).find_by_name_and_kind( + let assoc_item = tcx.associated_items(trait_def).find_by_ident_and_kind( tcx, ident, - ty::AssocKind::Type, + ty::AssocTag::Type, trait_def, ); @@ -848,16 +856,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let mut names: UnordMap<_, usize> = Default::default(); for (item, _) in &missing_assoc_types { types_count += 1; - *names.entry(item.name).or_insert(0) += 1; + *names.entry(item.name()).or_insert(0) += 1; } let mut dupes = false; let mut shadows = false; for (item, trait_ref) in &missing_assoc_types { - let prefix = if names[&item.name] > 1 { + let name = item.name(); + let prefix = if names[&name] > 1 { let trait_def_id = trait_ref.def_id(); dupes = true; format!("{}::", tcx.def_path_str(trait_def_id)) - } else if bound_names.get(&item.name).is_some_and(|x| *x != item) { + } else if bound_names.get(&name).is_some_and(|x| *x != item) { let trait_def_id = trait_ref.def_id(); shadows = true; format!("{}::", tcx.def_path_str(trait_def_id)) @@ -867,7 +876,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let mut is_shadowed = false; - if let Some(assoc_item) = bound_names.get(&item.name) + if let Some(assoc_item) = bound_names.get(&name) && *assoc_item != item { is_shadowed = true; @@ -876,17 +885,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { if assoc_item.def_id.is_local() { ", consider renaming it" } else { "" }; err.span_label( tcx.def_span(assoc_item.def_id), - format!("`{}{}` shadowed here{}", prefix, item.name, rename_message), + format!("`{}{}` shadowed here{}", prefix, name, rename_message), ); } let rename_message = if is_shadowed { ", consider renaming it" } else { "" }; if let Some(sp) = tcx.hir_span_if_local(item.def_id) { - err.span_label( - sp, - format!("`{}{}` defined here{}", prefix, item.name, rename_message), - ); + err.span_label(sp, format!("`{}{}` defined here{}", prefix, name, rename_message)); } } if potential_assoc_types.len() == missing_assoc_types.len() { @@ -899,7 +905,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { { let types: Vec<_> = missing_assoc_types .iter() - .map(|(item, _)| format!("{} = Type", item.name)) + .map(|(item, _)| format!("{} = Type", item.name())) .collect(); let code = if let Some(snippet) = snippet.strip_suffix('>') { // The user wrote `Trait<'a>` or similar and we don't have a type we can @@ -934,16 +940,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let mut names: FxIndexMap<_, usize> = FxIndexMap::default(); for (item, _) in &missing_assoc_types { types_count += 1; - *names.entry(item.name).or_insert(0) += 1; + *names.entry(item.name()).or_insert(0) += 1; } let mut label = vec![]; for (item, trait_ref) in &missing_assoc_types { - let postfix = if names[&item.name] > 1 { + let name = item.name(); + let postfix = if names[&name] > 1 { format!(" (from trait `{}`)", trait_ref.print_trait_sugared()) } else { String::new() }; - label.push(format!("`{}`{}", item.name, postfix)); + label.push(format!("`{}`{}", name, postfix)); } if !label.is_empty() { err.span_label( @@ -1018,12 +1025,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .map(|simple_ty| tcx.incoherent_impls(simple_ty)) }) && let name = Symbol::intern(&format!("{ident2}_{ident3}")) - && let Some(ty::AssocItem { kind: ty::AssocKind::Fn, .. }) = inherent_impls + && let Some(item) = inherent_impls .iter() .flat_map(|inherent_impl| { tcx.associated_items(inherent_impl).filter_by_name_unhygienic(name) }) .next() + && item.is_fn() { Err(struct_span_code_err!(self.dcx(), span, E0223, "ambiguous associated type") .with_span_suggestion_verbose( @@ -1625,10 +1633,10 @@ fn generics_args_err_extend<'a>( } } -pub(crate) fn assoc_kind_str(kind: ty::AssocKind) -> &'static str { - match kind { - ty::AssocKind::Fn => "function", - ty::AssocKind::Const => "constant", - ty::AssocKind::Type => "type", +pub(crate) fn assoc_tag_str(assoc_tag: ty::AssocTag) -> &'static str { + match assoc_tag { + ty::AssocTag::Fn => "function", + ty::AssocTag::Const => "constant", + ty::AssocTag::Type => "type", } } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs index 8e62dce21913..483b61add338 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs @@ -501,8 +501,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let names: Vec<_> = tcx .associated_items(trait_def_id) .in_definition_order() - .filter(|assoc| assoc.kind.namespace() == Namespace::ValueNS) - .map(|cand| cand.name) + .filter(|assoc| assoc.namespace() == Namespace::ValueNS) + .map(|cand| cand.name()) .collect(); if let Some(typo) = find_best_match_for_name(&names, segment.ident.name, None) { diag.span_suggestion_verbose( diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index b4a71edc118c..7605c6c6a420 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -38,8 +38,8 @@ use rustc_middle::middle::stability::AllowUnstable; use rustc_middle::mir::interpret::LitToConstInput; use rustc_middle::ty::print::PrintPolyTraitRefExt as _; use rustc_middle::ty::{ - self, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, ParamEnv, Ty, TyCtxt, - TypeVisitableExt, TypingMode, Upcast, fold_regions, + self, AssocTag, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, ParamEnv, Ty, + TyCtxt, TypeVisitableExt, TypingMode, Upcast, fold_regions, }; use rustc_middle::{bug, span_bug}; use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS; @@ -51,7 +51,7 @@ use rustc_trait_selection::traits::wf::object_region_bounds; use rustc_trait_selection::traits::{self, ObligationCtxt}; use tracing::{debug, instrument}; -use self::errors::assoc_kind_str; +use self::errors::assoc_tag_str; use crate::check::check_abi_fn_ptr; use crate::errors::{AmbiguousLifetimeBound, BadReturnTypeNotation, NoVariantNamed}; use crate::hir_ty_lowering::errors::{GenericsArgsErrExtend, prohibit_assoc_item_constraint}; @@ -147,7 +147,7 @@ pub trait HirTyLowerer<'tcx> { &self, span: Span, def_id: LocalDefId, - assoc_name: Ident, + assoc_ident: Ident, ) -> ty::EarlyBinder<'tcx, &'tcx [(ty::Clause<'tcx>, Span)]>; /// Lower an associated type/const (from a trait) to a projection. @@ -168,7 +168,7 @@ pub trait HirTyLowerer<'tcx> { item_def_id: DefId, item_segment: &hir::PathSegment<'tcx>, poly_trait_ref: ty::PolyTraitRef<'tcx>, - kind: ty::AssocKind, + assoc_tag: ty::AssocTag, ) -> Result<(DefId, GenericArgsRef<'tcx>), ErrorGuaranteed>; fn lower_fn_sig( @@ -251,10 +251,10 @@ enum LowerAssocMode { } impl LowerAssocMode { - fn kind(self) -> ty::AssocKind { + fn assoc_tag(self) -> ty::AssocTag { match self { - LowerAssocMode::Type { .. } => ty::AssocKind::Type, - LowerAssocMode::Const => ty::AssocKind::Const, + LowerAssocMode::Type { .. } => ty::AssocTag::Type, + LowerAssocMode::Const => ty::AssocTag::Const, } } @@ -268,7 +268,8 @@ impl LowerAssocMode { fn permit_variants(self) -> bool { match self { LowerAssocMode::Type { permit_variants } => permit_variants, - // FIXME(mgca): Support paths like `Option::::None` or `Option::::Some` which resolve to const ctors/fn items respectively + // FIXME(mgca): Support paths like `Option::::None` or `Option::::Some` which + // resolve to const ctors/fn items respectively. LowerAssocMode::Const => false, } } @@ -932,12 +933,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { fn probe_trait_that_defines_assoc_item( &self, trait_def_id: DefId, - assoc_kind: ty::AssocKind, - assoc_name: Ident, + assoc_tag: AssocTag, + assoc_ident: Ident, ) -> bool { self.tcx() .associated_items(trait_def_id) - .find_by_name_and_kind(self.tcx(), assoc_name, assoc_kind, trait_def_id) + .find_by_ident_and_kind(self.tcx(), assoc_ident, assoc_tag, trait_def_id) .is_some() } @@ -964,7 +965,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } /// Search for a trait bound on a type parameter whose trait defines the associated item - /// given by `assoc_name` and `kind`. + /// given by `assoc_ident` and `kind`. /// /// This fails if there is no such bound in the list of candidates or if there are multiple /// candidates in which case it reports ambiguity. @@ -975,14 +976,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { &self, ty_param_def_id: LocalDefId, ty_param_span: Span, - kind: ty::AssocKind, - assoc_name: Ident, + assoc_tag: AssocTag, + assoc_ident: Ident, span: Span, ) -> Result, ErrorGuaranteed> { - debug!(?ty_param_def_id, ?assoc_name, ?span); + debug!(?ty_param_def_id, ?assoc_ident, ?span); let tcx = self.tcx(); - let predicates = &self.probe_ty_param_bounds(span, ty_param_def_id, assoc_name); + let predicates = &self.probe_ty_param_bounds(span, ty_param_def_id, assoc_ident); debug!("predicates={:#?}", predicates); self.probe_single_bound_for_assoc_item( @@ -990,17 +991,18 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let trait_refs = predicates .iter_identity_copied() .filter_map(|(p, _)| Some(p.as_trait_clause()?.map_bound(|t| t.trait_ref))); - traits::transitive_bounds_that_define_assoc_item(tcx, trait_refs, assoc_name) + traits::transitive_bounds_that_define_assoc_item(tcx, trait_refs, assoc_ident) }, AssocItemQSelf::TyParam(ty_param_def_id, ty_param_span), - kind, - assoc_name, + assoc_tag, + assoc_ident, span, None, ) } - /// Search for a single trait bound whose trait defines the associated item given by `assoc_name`. + /// Search for a single trait bound whose trait defines the associated item given by + /// `assoc_ident`. /// /// This fails if there is no such bound in the list of candidates or if there are multiple /// candidates in which case it reports ambiguity. @@ -1009,8 +1011,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { &self, all_candidates: impl Fn() -> I, qself: AssocItemQSelf, - assoc_kind: ty::AssocKind, - assoc_name: Ident, + assoc_tag: AssocTag, + assoc_ident: Ident, span: Span, constraint: Option<&hir::AssocItemConstraint<'tcx>>, ) -> Result, ErrorGuaranteed> @@ -1020,15 +1022,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let tcx = self.tcx(); let mut matching_candidates = all_candidates().filter(|r| { - self.probe_trait_that_defines_assoc_item(r.def_id(), assoc_kind, assoc_name) + self.probe_trait_that_defines_assoc_item(r.def_id(), assoc_tag, assoc_ident) }); let Some(bound) = matching_candidates.next() else { let reported = self.complain_about_assoc_item_not_found( all_candidates, qself, - assoc_kind, - assoc_name, + assoc_tag, + assoc_ident, span, constraint, ); @@ -1039,12 +1041,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { if let Some(bound2) = matching_candidates.next() { debug!(?bound2); - let assoc_kind_str = errors::assoc_kind_str(assoc_kind); + let assoc_kind_str = errors::assoc_tag_str(assoc_tag); let qself_str = qself.to_string(tcx); let mut err = self.dcx().create_err(crate::errors::AmbiguousAssocItem { span, assoc_kind: assoc_kind_str, - assoc_name, + assoc_ident, qself: &qself_str, }); // Provide a more specific error code index entry for equality bindings. @@ -1058,20 +1060,21 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { }, ); - // FIXME(#97583): Print associated item bindings properly (i.e., not as equality predicates!). + // FIXME(#97583): Print associated item bindings properly (i.e., not as equality + // predicates!). // FIXME: Turn this into a structured, translateable & more actionable suggestion. let mut where_bounds = vec![]; for bound in [bound, bound2].into_iter().chain(matching_candidates) { let bound_id = bound.def_id(); let bound_span = tcx .associated_items(bound_id) - .find_by_name_and_kind(tcx, assoc_name, assoc_kind, bound_id) + .find_by_ident_and_kind(tcx, assoc_ident, assoc_tag, bound_id) .and_then(|item| tcx.hir_span_if_local(item.def_id)); if let Some(bound_span) = bound_span { err.span_label( bound_span, - format!("ambiguous `{assoc_name}` from `{}`", bound.print_trait_sugared(),), + format!("ambiguous `{assoc_ident}` from `{}`", bound.print_trait_sugared(),), ); if let Some(constraint) = constraint { match constraint.kind { @@ -1087,7 +1090,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } // FIXME(#97583): This isn't syntactically well-formed! where_bounds.push(format!( - " T: {trait}::{assoc_name} = {term}", + " T: {trait}::{assoc_ident} = {term}", trait = bound.print_only_trait_path(), )); } @@ -1096,7 +1099,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } } else { err.span_suggestion_verbose( - span.with_hi(assoc_name.span.lo()), + span.with_hi(assoc_ident.span.lo()), "use fully-qualified syntax to disambiguate", format!("<{qself_str} as {}>::", bound.print_only_trait_path()), Applicability::MaybeIncorrect, @@ -1104,7 +1107,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } } else { err.note(format!( - "associated {assoc_kind_str} `{assoc_name}` could derive from `{}`", + "associated {assoc_kind_str} `{assoc_ident}` could derive from `{}`", bound.print_only_trait_path(), )); } @@ -1264,7 +1267,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { qself_ty, hir_ref_id, span, - mode.kind(), + mode.assoc_tag(), )? { return Ok(LoweredAssoc::Term(did, args)); } @@ -1295,7 +1298,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ) }, AssocItemQSelf::SelfTyAlias, - mode.kind(), + mode.assoc_tag(), assoc_ident, span, None, @@ -1307,12 +1310,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ) => self.probe_single_ty_param_bound_for_assoc_item( param_did.expect_local(), qself.span, - mode.kind(), + mode.assoc_tag(), assoc_ident, span, )?, _ => { - let kind_str = assoc_kind_str(mode.kind()); + let kind_str = assoc_tag_str(mode.assoc_tag()); let reported = if variant_resolution.is_some() { // Variant in type position let msg = format!("expected {kind_str}, found variant `{assoc_ident}`"); @@ -1419,7 +1422,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { &[qself_ty.to_string()], &traits, assoc_ident.name, - mode.kind(), + mode.assoc_tag(), ) }; return Err(reported); @@ -1428,10 +1431,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let trait_did = bound.def_id(); let assoc_item = self - .probe_assoc_item(assoc_ident, mode.kind(), hir_ref_id, span, trait_did) + .probe_assoc_item(assoc_ident, mode.assoc_tag(), hir_ref_id, span, trait_did) .expect("failed to find associated item"); - let (def_id, args) = - self.lower_assoc_shared(span, assoc_item.def_id, assoc_segment, bound, mode.kind())?; + let (def_id, args) = self.lower_assoc_shared( + span, + assoc_item.def_id, + assoc_segment, + bound, + mode.assoc_tag(), + )?; let result = LoweredAssoc::Term(def_id, args); if let Some(variant_def_id) = variant_resolution { @@ -1468,20 +1476,21 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { self_ty: Ty<'tcx>, block: HirId, span: Span, - kind: ty::AssocKind, + assoc_tag: ty::AssocTag, ) -> Result)>, ErrorGuaranteed> { let tcx = self.tcx(); if !tcx.features().inherent_associated_types() { - match kind { - // Don't attempt to look up inherent associated types when the feature is not enabled. - // Theoretically it'd be fine to do so since we feature-gate their definition site. - // However, due to current limitations of the implementation (caused by us performing - // selection during HIR ty lowering instead of in the trait solver), IATs can lead to cycle - // errors (#108491) which mask the feature-gate error, needlessly confusing users - // who use IATs by accident (#113265). - ty::AssocKind::Type => return Ok(None), - ty::AssocKind::Const => { + match assoc_tag { + // Don't attempt to look up inherent associated types when the feature is not + // enabled. Theoretically it'd be fine to do so since we feature-gate their + // definition site. However, due to current limitations of the implementation + // (caused by us performing selection during HIR ty lowering instead of in the + // trait solver), IATs can lead to cycle errors (#108491) which mask the + // feature-gate error, needlessly confusing users who use IATs by accident + // (#113265). + ty::AssocTag::Type => return Ok(None), + ty::AssocTag::Const => { // We also gate the mgca codepath for type-level uses of inherent consts // with the inherent_associated_types feature gate since it relies on the // same machinery and has similar rough edges. @@ -1493,7 +1502,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ) .emit()); } - ty::AssocKind::Fn => unreachable!(), + ty::AssocTag::Fn => unreachable!(), } } @@ -1502,7 +1511,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .inherent_impls(adt_did) .iter() .filter_map(|&impl_| { - let (item, scope) = self.probe_assoc_item_unchecked(name, kind, block, impl_)?; + let (item, scope) = + self.probe_assoc_item_unchecked(name, assoc_tag, block, impl_)?; Some((impl_, (item.def_id, scope))) }) .collect(); @@ -1541,7 +1551,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { self_ty, |self_ty| { self.select_inherent_assoc_candidates( - infcx, name, span, self_ty, param_env, candidates, kind, + infcx, name, span, self_ty, param_env, candidates, assoc_tag, ) }, )?; @@ -1569,7 +1579,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { self_ty: Ty<'tcx>, param_env: ParamEnv<'tcx>, candidates: Vec<(DefId, (DefId, DefId))>, - kind: ty::AssocKind, + assoc_tag: ty::AssocTag, ) -> Result<(DefId, (DefId, DefId)), ErrorGuaranteed> { let tcx = self.tcx(); let mut fulfillment_errors = Vec::new(); @@ -1620,7 +1630,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { candidates, fulfillment_errors, span, - kind, + assoc_tag, )), &[applicable_candidate] => Ok(applicable_candidate), @@ -1639,12 +1649,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { fn probe_assoc_item( &self, ident: Ident, - kind: ty::AssocKind, + assoc_tag: ty::AssocTag, block: HirId, span: Span, scope: DefId, ) -> Option { - let (item, scope) = self.probe_assoc_item_unchecked(ident, kind, block, scope)?; + let (item, scope) = self.probe_assoc_item_unchecked(ident, assoc_tag, block, scope)?; self.check_assoc_item(item.def_id, ident, scope, block, span); Some(item) } @@ -1656,7 +1666,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { fn probe_assoc_item_unchecked( &self, ident: Ident, - kind: ty::AssocKind, + assoc_tag: ty::AssocTag, block: HirId, scope: DefId, ) -> Option<(ty::AssocItem, /*scope*/ DefId)> { @@ -1669,7 +1679,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let item = tcx .associated_items(scope) .filter_by_name_unhygienic(ident.name) - .find(|i| i.kind == kind && i.ident(tcx).normalize_to_macros_2_0() == ident)?; + .find(|i| i.as_tag() == assoc_tag && i.ident(tcx).normalize_to_macros_2_0() == ident)?; Some((*item, def_scope)) } @@ -1721,9 +1731,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { tcx.associated_items(*trait_def_id) .in_definition_order() .any(|i| { - i.kind.namespace() == Namespace::TypeNS + i.namespace() == Namespace::TypeNS && i.ident(tcx).normalize_to_macros_2_0() == assoc_ident - && matches!(i.kind, ty::AssocKind::Type) + && i.is_type() }) // Consider only accessible traits && tcx.visibility(*trait_def_id) @@ -1769,7 +1779,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { item_def_id, trait_segment, item_segment, - ty::AssocKind::Type, + ty::AssocTag::Type, ) { Ok((item_def_id, item_args)) => { Ty::new_projection_from_args(self.tcx(), item_def_id, item_args) @@ -1794,7 +1804,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { item_def_id, trait_segment, item_segment, - ty::AssocKind::Const, + ty::AssocTag::Const, ) { Ok((item_def_id, item_args)) => { let uv = ty::UnevaluatedConst::new(item_def_id, item_args); @@ -1812,7 +1822,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { item_def_id: DefId, trait_segment: &hir::PathSegment<'tcx>, item_segment: &hir::PathSegment<'tcx>, - kind: ty::AssocKind, + assoc_tag: ty::AssocTag, ) -> Result<(DefId, GenericArgsRef<'tcx>), ErrorGuaranteed> { let tcx = self.tcx(); @@ -1820,7 +1830,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { debug!(?trait_def_id); let Some(self_ty) = opt_self_ty else { - return Err(self.error_missing_qpath_self_ty(trait_def_id, span, item_segment, kind)); + return Err(self.error_missing_qpath_self_ty( + trait_def_id, + span, + item_segment, + assoc_tag, + )); }; debug!(?self_ty); @@ -1839,7 +1854,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { trait_def_id: DefId, span: Span, item_segment: &hir::PathSegment<'tcx>, - kind: ty::AssocKind, + assoc_tag: ty::AssocTag, ) -> ErrorGuaranteed { let tcx = self.tcx(); let path_str = tcx.def_path_str(trait_def_id); @@ -1876,7 +1891,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // FIXME: also look at `tcx.generics_of(self.item_def_id()).params` any that // references the trait. Relevant for the first case in // `src/test/ui/associated-types/associated-types-in-ambiguous-context.rs` - self.report_ambiguous_assoc(span, &type_names, &[path_str], item_segment.ident.name, kind) + self.report_ambiguous_assoc( + span, + &type_names, + &[path_str], + item_segment.ident.name, + assoc_tag, + ) } pub fn prohibit_generic_args<'a>( @@ -2858,10 +2879,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let trait_ref = self.lower_impl_trait_ref(i.of_trait.as_ref()?, self.lower_ty(i.self_ty)); - let assoc = tcx.associated_items(trait_ref.def_id).find_by_name_and_kind( + let assoc = tcx.associated_items(trait_ref.def_id).find_by_ident_and_kind( tcx, *ident, - ty::AssocKind::Fn, + ty::AssocTag::Fn, trait_ref.def_id, )?; diff --git a/compiler/rustc_hir_analysis/src/hir_wf_check.rs b/compiler/rustc_hir_analysis/src/hir_wf_check.rs index c01b81563dcf..64c1a78bd1c8 100644 --- a/compiler/rustc_hir_analysis/src/hir_wf_check.rs +++ b/compiler/rustc_hir_analysis/src/hir_wf_check.rs @@ -4,7 +4,7 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::traits::{ObligationCause, WellFormedLoc}; use rustc_middle::bug; use rustc_middle::query::Providers; -use rustc_middle::ty::{self, TyCtxt, TypingMode, fold_regions}; +use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt, TypingMode, fold_regions}; use rustc_span::def_id::LocalDefId; use rustc_trait_selection::traits::{self, ObligationCtxt}; use tracing::debug; @@ -77,6 +77,15 @@ fn diagnostic_hir_wf_check<'tcx>( let tcx_ty = fold_regions(self.tcx, tcx_ty, |r, _| { if r.is_bound() { self.tcx.lifetimes.re_erased } else { r } }); + + // We may be checking the WFness of a type in an opaque with a non-lifetime bound. + // Perhaps we could rebind all the escaping bound vars, but they're coming from + // arbitrary debruijn indices and aren't particularly important anyways, since they + // are only coming from `feature(non_lifetime_binders)` anyways. + if tcx_ty.has_escaping_bound_vars() { + return; + } + let cause = traits::ObligationCause::new( ty.span, self.def_id, diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check.rs b/compiler/rustc_hir_analysis/src/impl_wf_check.rs index c30b39dfe765..cbdc501291bc 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check.rs @@ -112,14 +112,14 @@ pub(crate) fn enforce_impl_lifetime_params_are_constrained( .flat_map(|def_id| { let item = tcx.associated_item(def_id); match item.kind { - ty::AssocKind::Type => { + ty::AssocKind::Type { .. } => { if item.defaultness(tcx).has_value() { cgp::parameters_for(tcx, tcx.type_of(def_id).instantiate_identity(), true) } else { vec![] } } - ty::AssocKind::Fn | ty::AssocKind::Const => vec![], + ty::AssocKind::Fn { .. } | ty::AssocKind::Const { .. } => vec![], } }) .collect(); diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index e7ecd727a852..e1ad8124aea7 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -59,7 +59,6 @@ This API is completely unstable and subject to change. #![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] -#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(assert_matches)] diff --git a/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs index a0faa5e8429e..780c27d45954 100644 --- a/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs +++ b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs @@ -24,8 +24,8 @@ pub(super) fn infer_predicates( // If new predicates were added then we need to re-calculate // all crates since there could be new implied predicates. - loop { - let mut predicates_added = false; + for i in 0.. { + let mut predicates_added = vec![]; // Visit all the crates and infer predicates for id in tcx.hir_free_items() { @@ -83,14 +83,27 @@ pub(super) fn infer_predicates( .get(&item_did.to_def_id()) .map_or(0, |p| p.as_ref().skip_binder().len()); if item_required_predicates.len() > item_predicates_len { - predicates_added = true; + predicates_added.push(item_did); global_inferred_outlives .insert(item_did.to_def_id(), ty::EarlyBinder::bind(item_required_predicates)); } } - if !predicates_added { + if predicates_added.is_empty() { + // We've reached a fixed point. break; + } else if !tcx.recursion_limit().value_within_limit(i) { + let msg = if let &[id] = &predicates_added[..] { + format!("overflow computing implied lifetime bounds for `{}`", tcx.def_path_str(id),) + } else { + "overflow computing implied lifetime bounds".to_string() + }; + tcx.dcx() + .struct_span_fatal( + predicates_added.iter().map(|id| tcx.def_span(*id)).collect::>(), + msg, + ) + .emit(); } } diff --git a/compiler/rustc_hir_analysis/src/outlives/utils.rs b/compiler/rustc_hir_analysis/src/outlives/utils.rs index d0a2a2230ab7..044fb64ca821 100644 --- a/compiler/rustc_hir_analysis/src/outlives/utils.rs +++ b/compiler/rustc_hir_analysis/src/outlives/utils.rs @@ -146,7 +146,7 @@ pub(crate) fn insert_outlives_predicate<'tcx>( fn is_free_region(region: Region<'_>) -> bool { // First, screen for regions that might appear in a type header. - match *region { + match region.kind() { // These correspond to `T: 'a` relationships: // // struct Foo<'a, T> { diff --git a/compiler/rustc_hir_analysis/src/variance/constraints.rs b/compiler/rustc_hir_analysis/src/variance/constraints.rs index 8475903c68fd..23223de918cf 100644 --- a/compiler/rustc_hir_analysis/src/variance/constraints.rs +++ b/compiler/rustc_hir_analysis/src/variance/constraints.rs @@ -428,7 +428,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { region: ty::Region<'tcx>, variance: VarianceTermPtr<'a>, ) { - match *region { + match region.kind() { ty::ReEarlyParam(ref data) => { self.add_constraint(current, data.index, variance); } diff --git a/compiler/rustc_hir_analysis/src/variance/mod.rs b/compiler/rustc_hir_analysis/src/variance/mod.rs index 0800d99e9452..dbba45dc7bb5 100644 --- a/compiler/rustc_hir_analysis/src/variance/mod.rs +++ b/compiler/rustc_hir_analysis/src/variance/mod.rs @@ -44,13 +44,13 @@ fn variances_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Variance] { return &[]; } - match tcx.def_kind(item_def_id) { + let kind = tcx.def_kind(item_def_id); + match kind { DefKind::Fn | DefKind::AssocFn | DefKind::Enum | DefKind::Struct | DefKind::Union - | DefKind::Variant | DefKind::Ctor(..) => { // These are inferred. let crate_map = tcx.crate_variances(()); @@ -89,7 +89,11 @@ fn variances_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Variance] { } // Variance not relevant. - span_bug!(tcx.def_span(item_def_id), "asked to compute variance for wrong kind of item"); + span_bug!( + tcx.def_span(item_def_id), + "asked to compute variance for {}", + kind.descr(item_def_id.to_def_id()) + ); } #[derive(Debug, Copy, Clone)] diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 8c0c17f7a7d6..ff4385c3bcce 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -397,7 +397,7 @@ impl<'a> State<'a> { self.pclose(); } hir::TyKind::BareFn(f) => { - self.print_ty_fn(f.abi, f.safety, f.decl, None, f.generic_params, f.param_names); + self.print_ty_fn(f.abi, f.safety, f.decl, None, f.generic_params, f.param_idents); } hir::TyKind::UnsafeBinder(unsafe_binder) => { self.print_unsafe_binder(unsafe_binder); @@ -473,14 +473,14 @@ impl<'a> State<'a> { self.maybe_print_comment(item.span.lo()); self.print_attrs_as_outer(self.attrs(item.hir_id())); match item.kind { - hir::ForeignItemKind::Fn(sig, arg_names, generics) => { + hir::ForeignItemKind::Fn(sig, arg_idents, generics) => { self.head(""); self.print_fn( sig.decl, sig.header, Some(item.ident.name), generics, - arg_names, + arg_idents, None, ); self.end(); // end head-ibox @@ -899,10 +899,10 @@ impl<'a> State<'a> { ident: Ident, m: &hir::FnSig<'_>, generics: &hir::Generics<'_>, - arg_names: &[Option], + arg_idents: &[Option], body_id: Option, ) { - 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_idents, body_id); } fn print_trait_item(&mut self, ti: &hir::TraitItem<'_>) { @@ -914,8 +914,8 @@ impl<'a> State<'a> { hir::TraitItemKind::Const(ty, default) => { self.print_associated_const(ti.ident, ti.generics, ty, default); } - hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Required(arg_names)) => { - self.print_method_sig(ti.ident, sig, ti.generics, arg_names, None); + hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Required(arg_idents)) => { + self.print_method_sig(ti.ident, sig, ti.generics, arg_idents, None); self.word(";"); } hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => { @@ -960,12 +960,16 @@ impl<'a> State<'a> { fn print_local( &mut self, + super_: bool, init: Option<&hir::Expr<'_>>, els: Option<&hir::Block<'_>>, decl: impl Fn(&mut Self), ) { self.space_if_not_bol(); self.ibox(INDENT_UNIT); + if super_ { + self.word_nbsp("super"); + } self.word_nbsp("let"); self.ibox(INDENT_UNIT); @@ -995,7 +999,9 @@ impl<'a> State<'a> { self.maybe_print_comment(st.span.lo()); match st.kind { hir::StmtKind::Let(loc) => { - self.print_local(loc.init, loc.els, |this| this.print_local_decl(loc)); + self.print_local(loc.super_.is_some(), loc.init, loc.els, |this| { + this.print_local_decl(loc) + }); } hir::StmtKind::Item(item) => self.ann.nested(self, Nested::Item(item)), hir::StmtKind::Expr(expr) => { @@ -1488,7 +1494,7 @@ impl<'a> State<'a> { // Print `let _t = $init;`: let temp = Ident::from_str("_t"); - self.print_local(Some(init), None, |this| this.print_ident(temp)); + self.print_local(false, Some(init), None, |this| this.print_ident(temp)); self.word(";"); // Print `_t`: @@ -1865,9 +1871,11 @@ impl<'a> State<'a> { fn print_pat(&mut self, pat: &hir::Pat<'_>) { self.maybe_print_comment(pat.span.lo()); self.ann.pre(self, AnnNode::Pat(pat)); - // Pat isn't normalized, but the beauty of it - // is that it doesn't matter + // Pat isn't normalized, but the beauty of it is that it doesn't matter. match pat.kind { + // Printing `_` isn't ideal for a missing pattern, but it's easy and good enough. + // E.g. `fn(u32)` gets printed as `fn(_: u32)`. + PatKind::Missing => self.word("_"), PatKind::Wild => self.word("_"), PatKind::Never => self.word("!"), PatKind::Binding(BindingMode(by_ref, mutbl), _, ident, sub) => { @@ -2115,7 +2123,7 @@ impl<'a> State<'a> { header: hir::FnHeader, name: Option, generics: &hir::Generics<'_>, - arg_names: &[Option], + arg_idents: &[Option], body_id: Option, ) { self.print_fn_header_info(header); @@ -2127,16 +2135,16 @@ impl<'a> State<'a> { self.print_generic_params(generics.params); self.popen(); - // Make sure we aren't supplied *both* `arg_names` and `body_id`. - assert!(arg_names.is_empty() || body_id.is_none()); + // Make sure we aren't supplied *both* `arg_idents` and `body_id`. + assert!(arg_idents.is_empty() || body_id.is_none()); let mut i = 0; let mut print_arg = |s: &mut Self, ty: Option<&hir::Ty<'_>>| { if i == 0 && decl.implicit_self.has_implicit_self() { s.print_implicit_self(&decl.implicit_self); } else { - if let Some(arg_name) = arg_names.get(i) { - if let Some(arg_name) = arg_name { - s.word(arg_name.to_string()); + if let Some(arg_ident) = arg_idents.get(i) { + if let Some(arg_ident) = arg_ident { + s.word(arg_ident.to_string()); s.word(":"); s.space(); } @@ -2157,7 +2165,9 @@ impl<'a> State<'a> { s.end(); }); if decl.c_variadic { - self.word(", "); + if !decl.inputs.is_empty() { + self.word(", "); + } print_arg(self, None); self.word("..."); } @@ -2445,7 +2455,7 @@ impl<'a> State<'a> { decl: &hir::FnDecl<'_>, name: Option, generic_params: &[hir::GenericParam<'_>], - arg_names: &[Option], + arg_idents: &[Option], ) { self.ibox(INDENT_UNIT); self.print_formal_generic_params(generic_params); @@ -2460,7 +2470,7 @@ impl<'a> State<'a> { }, name, generics, - arg_names, + arg_idents, None, ); self.end(); diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl index 872861d6289d..9e1b70f5767b 100644 --- a/compiler/rustc_hir_typeck/messages.ftl +++ b/compiler/rustc_hir_typeck/messages.ftl @@ -148,7 +148,7 @@ hir_typeck_never_type_fallback_flowing_into_unsafe_path = never type fallback af hir_typeck_never_type_fallback_flowing_into_unsafe_union_field = never type fallback affects this union access .help = specify the type explicitly -hir_typeck_no_associated_item = no {$item_kind} named `{$item_name}` found for {$ty_prefix} `{$ty_str}`{$trait_missing_method -> +hir_typeck_no_associated_item = no {$item_kind} named `{$item_ident}` found for {$ty_prefix} `{$ty_str}`{$trait_missing_method -> [true] {""} *[other] {" "}in the current scope } diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index 8f5fddd19d7f..b19d9efe2c6f 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -1042,30 +1042,31 @@ impl<'a, 'tcx> CastCheck<'tcx> { m_cast: ty::TypeAndMut<'tcx>, ) -> Result> { // array-ptr-cast: allow mut-to-mut, mut-to-const, const-to-const - if m_expr.mutbl >= m_cast.mutbl { - if let ty::Array(ety, _) = m_expr.ty.kind() { - // Due to the limitations of LLVM global constants, - // region pointers end up pointing at copies of - // vector elements instead of the original values. - // To allow raw pointers to work correctly, we - // need to special-case obtaining a raw pointer - // from a region pointer to a vector. + if m_expr.mutbl >= m_cast.mutbl + && let ty::Array(ety, _) = m_expr.ty.kind() + && fcx.can_eq(fcx.param_env, *ety, m_cast.ty) + { + // Due to the limitations of LLVM global constants, + // region pointers end up pointing at copies of + // vector elements instead of the original values. + // To allow raw pointers to work correctly, we + // need to special-case obtaining a raw pointer + // from a region pointer to a vector. - // Coerce to a raw pointer so that we generate RawPtr in MIR. - let array_ptr_type = Ty::new_ptr(fcx.tcx, m_expr.ty, m_expr.mutbl); - fcx.coerce(self.expr, self.expr_ty, array_ptr_type, AllowTwoPhase::No, None) - .unwrap_or_else(|_| { - bug!( + // Coerce to a raw pointer so that we generate RawPtr in MIR. + let array_ptr_type = Ty::new_ptr(fcx.tcx, m_expr.ty, m_expr.mutbl); + fcx.coerce(self.expr, self.expr_ty, array_ptr_type, AllowTwoPhase::No, None) + .unwrap_or_else(|_| { + bug!( "could not cast from reference to array to pointer to array ({:?} to {:?})", self.expr_ty, array_ptr_type, ) - }); + }); - // this will report a type mismatch if needed - fcx.demand_eqtype(self.span, *ety, m_cast.ty); - return Ok(CastKind::ArrayPtrCast); - } + // this will report a type mismatch if needed + fcx.demand_eqtype(self.span, *ety, m_cast.ty); + return Ok(CastKind::ArrayPtrCast); } Err(CastError::IllegalCast) diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs index dabae7b1d094..2189fdf0f343 100644 --- a/compiler/rustc_hir_typeck/src/check.rs +++ b/compiler/rustc_hir_typeck/src/check.rs @@ -5,7 +5,7 @@ use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::intravisit::Visitor; use rustc_hir::lang_items::LangItem; -use rustc_hir_analysis::check::{check_function_signature, forbid_intrinsic_abi}; +use rustc_hir_analysis::check::check_function_signature; use rustc_infer::infer::RegionVariableOrigin; use rustc_infer::traits::WellFormedLoc; use rustc_middle::ty::{self, Binder, Ty, TyCtxt}; @@ -50,8 +50,6 @@ pub(super) fn check_fn<'a, 'tcx>( let span = body.value.span; - forbid_intrinsic_abi(tcx, span, fn_sig.abi); - GatherLocalsVisitor::new(fcx).visit_body(body); // C-variadic fns also have a `VaList` input that's not listed in `fn_sig` diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index 467ca26e7eab..b8968b58769a 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -970,7 +970,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.typeck_results.borrow_mut().user_provided_sigs.insert(expr_def_id, c_result); // Normalize only after registering in `user_provided_sigs`. - self.normalize(self.tcx.hir_span(hir_id), result) + self.normalize(self.tcx.def_span(expr_def_id), result) } /// Invoked when we are translating the coroutine that results diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index f42ca3af2b35..fd899425f62d 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -37,7 +37,6 @@ use std::ops::Deref; -use rustc_abi::ExternAbi; use rustc_attr_parsing::InlineAttr; use rustc_errors::codes::*; use rustc_errors::{Applicability, Diag, struct_span_code_err}; @@ -104,15 +103,6 @@ fn coerce_mutbls<'tcx>( if from_mutbl >= to_mutbl { Ok(()) } else { Err(TypeError::Mutability) } } -/// Do not require any adjustments, i.e. coerce `x -> x`. -fn identity(_: Ty<'_>) -> Vec> { - vec![] -} - -fn simple<'tcx>(kind: Adjust) -> impl FnOnce(Ty<'tcx>) -> Vec> { - move |target| vec![Adjustment { kind, target }] -} - /// This always returns `Ok(...)`. fn success<'tcx>( adj: Vec>, @@ -132,7 +122,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { Coerce { fcx, cause, allow_two_phase, use_lub: false, coerce_never } } - fn unify(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> InferResult<'tcx, Ty<'tcx>> { + fn unify_raw(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> InferResult<'tcx, Ty<'tcx>> { debug!("unify(a: {:?}, b: {:?}, use_lub: {})", a, b, self.use_lub); self.commit_if_ok(|_| { let at = self.at(&self.cause, self.fcx.param_env); @@ -162,13 +152,30 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { }) } + /// Unify two types (using sub or lub). + fn unify(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> { + self.unify_raw(a, b) + .and_then(|InferOk { value: ty, obligations }| success(vec![], ty, obligations)) + } + /// Unify two types (using sub or lub) and produce a specific coercion. - fn unify_and(&self, a: Ty<'tcx>, b: Ty<'tcx>, f: F) -> CoerceResult<'tcx> - where - F: FnOnce(Ty<'tcx>) -> Vec>, - { - self.unify(a, b) - .and_then(|InferOk { value: ty, obligations }| success(f(ty), ty, obligations)) + fn unify_and( + &self, + a: Ty<'tcx>, + b: Ty<'tcx>, + adjustments: impl IntoIterator>, + final_adjustment: Adjust, + ) -> CoerceResult<'tcx> { + self.unify_raw(a, b).and_then(|InferOk { value: ty, obligations }| { + success( + adjustments + .into_iter() + .chain(std::iter::once(Adjustment { target: ty, kind: final_adjustment })) + .collect(), + ty, + obligations, + ) + }) } #[instrument(skip(self))] @@ -181,10 +188,14 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // Coercing from `!` to any type is allowed: if a.is_never() { if self.coerce_never { - return success(simple(Adjust::NeverToAny)(b), b, PredicateObligations::new()); + return success( + vec![Adjustment { kind: Adjust::NeverToAny, target: b }], + b, + PredicateObligations::new(), + ); } else { // Otherwise the only coercion we can do is unification. - return self.unify_and(a, b, identity); + return self.unify(a, b); } } @@ -192,7 +203,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // we have no information about the source type. This will always // ultimately fall back to some form of subtyping. if a.is_ty_var() { - return self.coerce_from_inference_variable(a, b, identity); + return self.coerce_from_inference_variable(a, b); } // Consider coercing the subtype to a DST @@ -248,7 +259,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { ty::FnPtr(a_sig_tys, a_hdr) => { // We permit coercion of fn pointers to drop the // unsafe qualifier. - self.coerce_from_fn_pointer(a, a_sig_tys.with(a_hdr), b) + self.coerce_from_fn_pointer(a_sig_tys.with(a_hdr), b) } ty::Closure(closure_def_id_a, args_a) => { // Non-capturing closures are coercible to @@ -258,7 +269,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { } _ => { // Otherwise, just use unification rules. - self.unify_and(a, b, identity) + self.unify(a, b) } } } @@ -266,12 +277,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { /// Coercing *from* an inference variable. In this case, we have no information /// about the source type, so we can't really do a true coercion and we always /// fall back to subtyping (`unify_and`). - fn coerce_from_inference_variable( - &self, - a: Ty<'tcx>, - b: Ty<'tcx>, - make_adjustments: impl FnOnce(Ty<'tcx>) -> Vec>, - ) -> CoerceResult<'tcx> { + fn coerce_from_inference_variable(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> { debug!("coerce_from_inference_variable(a={:?}, b={:?})", a, b); assert!(a.is_ty_var() && self.shallow_resolve(a) == a); assert!(self.shallow_resolve(b) == b); @@ -299,12 +305,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { "coerce_from_inference_variable: two inference variables, target_ty={:?}, obligations={:?}", target_ty, obligations ); - let adjustments = make_adjustments(target_ty); - InferResult::Ok(InferOk { value: (adjustments, target_ty), obligations }) + success(vec![], target_ty, obligations) } else { // One unresolved type variable: just apply subtyping, we may be able // to do something useful. - self.unify_and(a, b, make_adjustments) + self.unify(a, b) } } @@ -332,7 +337,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { coerce_mutbls(mt_a.mutbl, mutbl_b)?; (r_a, mt_a) } - _ => return self.unify_and(a, b, identity), + _ => return self.unify(a, b), }; let span = self.cause.span; @@ -438,7 +443,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { referent_ty, mutbl_b, // [1] above ); - match self.unify(derefd_ty_a, b) { + match self.unify_raw(derefd_ty_a, b) { Ok(ok) => { found = Some(ok); break; @@ -580,13 +585,13 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // We only have the latter, so we use an inference variable // for the former and let type inference do the rest. let coerce_target = self.next_ty_var(self.cause.span); - let mut coercion = self.unify_and(coerce_target, target, |target| { - let unsize = Adjustment { kind: Adjust::Pointer(PointerCoercion::Unsize), target }; - match reborrow { - None => vec![unsize], - Some((ref deref, ref autoref)) => vec![deref.clone(), autoref.clone(), unsize], - } - })?; + + let mut coercion = self.unify_and( + coerce_target, + target, + reborrow.into_iter().flat_map(|(deref, autoref)| [deref, autoref]), + Adjust::Pointer(PointerCoercion::Unsize), + )?; let mut selcx = traits::SelectionContext::new(self); @@ -709,7 +714,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { && let ty::Dynamic(b_data, _, ty::DynStar) = b.kind() && a_data.principal_def_id() == b_data.principal_def_id() { - return self.unify_and(a, b, |_| vec![]); + return self.unify(a, b); } // Check the obligations of the cast -- for example, when casting @@ -809,23 +814,15 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // To complete the reborrow, we need to make sure we can unify the inner types, and if so we // add the adjustments. - self.unify_and(a, b, |_inner_ty| { - vec![Adjustment { kind: Adjust::ReborrowPin(mut_b), target: b }] - }) + self.unify_and(a, b, [], Adjust::ReborrowPin(mut_b)) } - fn coerce_from_safe_fn( + fn coerce_from_safe_fn( &self, - a: Ty<'tcx>, fn_ty_a: ty::PolyFnSig<'tcx>, b: Ty<'tcx>, - to_unsafe: F, - normal: G, - ) -> CoerceResult<'tcx> - where - F: FnOnce(Ty<'tcx>) -> Vec>, - G: FnOnce(Ty<'tcx>) -> Vec>, - { + adjustment: Option, + ) -> CoerceResult<'tcx> { self.commit_if_ok(|snapshot| { let outer_universe = self.infcx.universe(); @@ -834,9 +831,19 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { && hdr_b.safety.is_unsafe() { let unsafe_a = self.tcx.safe_to_unsafe_fn_ty(fn_ty_a); - self.unify_and(unsafe_a, b, to_unsafe) + self.unify_and( + unsafe_a, + b, + adjustment + .map(|kind| Adjustment { kind, target: Ty::new_fn_ptr(self.tcx, fn_ty_a) }), + Adjust::Pointer(PointerCoercion::UnsafeFnPointer), + ) } else { - self.unify_and(a, b, normal) + let a = Ty::new_fn_ptr(self.tcx, fn_ty_a); + match adjustment { + Some(adjust) => self.unify_and(a, b, [], adjust), + None => self.unify(a, b), + } }; // FIXME(#73154): This is a hack. Currently LUB can generate @@ -853,7 +860,6 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { fn coerce_from_fn_pointer( &self, - a: Ty<'tcx>, fn_ty_a: ty::PolyFnSig<'tcx>, b: Ty<'tcx>, ) -> CoerceResult<'tcx> { @@ -862,15 +868,9 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { //! let b = self.shallow_resolve(b); - debug!("coerce_from_fn_pointer(a={:?}, b={:?})", a, b); + debug!(?fn_ty_a, ?b, "coerce_from_fn_pointer"); - self.coerce_from_safe_fn( - a, - fn_ty_a, - b, - simple(Adjust::Pointer(PointerCoercion::UnsafeFnPointer)), - identity, - ) + self.coerce_from_safe_fn(fn_ty_a, b, None) } fn coerce_from_fn_item(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> { @@ -917,30 +917,16 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { self.at(&self.cause, self.param_env).normalize(a_sig); obligations.extend(o1); - let a_fn_pointer = Ty::new_fn_ptr(self.tcx, a_sig); let InferOk { value, obligations: o2 } = self.coerce_from_safe_fn( - a_fn_pointer, a_sig, b, - |unsafe_ty| { - vec![ - Adjustment { - kind: Adjust::Pointer(PointerCoercion::ReifyFnPointer), - target: a_fn_pointer, - }, - Adjustment { - kind: Adjust::Pointer(PointerCoercion::UnsafeFnPointer), - target: unsafe_ty, - }, - ] - }, - simple(Adjust::Pointer(PointerCoercion::ReifyFnPointer)), + Some(Adjust::Pointer(PointerCoercion::ReifyFnPointer)), )?; obligations.extend(o2); Ok(InferOk { value, obligations }) } - _ => self.unify_and(a, b, identity), + _ => self.unify(a, b), } } @@ -984,10 +970,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { self.unify_and( pointer_ty, b, - simple(Adjust::Pointer(PointerCoercion::ClosureFnPointer(safety))), + [], + Adjust::Pointer(PointerCoercion::ClosureFnPointer(safety)), ) } - _ => self.unify_and(a, b, identity), + _ => self.unify(a, b), } } @@ -1002,7 +989,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { let (is_ref, mt_a) = match *a.kind() { ty::Ref(_, ty, mutbl) => (true, ty::TypeAndMut { ty, mutbl }), ty::RawPtr(ty, mutbl) => (false, ty::TypeAndMut { ty, mutbl }), - _ => return self.unify_and(a, b, identity), + _ => return self.unify(a, b), }; coerce_mutbls(mt_a.mutbl, mutbl_b)?; @@ -1012,16 +999,16 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // representation, we still register an Adjust::DerefRef so that // regionck knows that the region for `a` must be valid here. if is_ref { - self.unify_and(a_raw, b, |target| { - vec![ - Adjustment { kind: Adjust::Deref(None), target: mt_a.ty }, - Adjustment { kind: Adjust::Borrow(AutoBorrow::RawPtr(mutbl_b)), target }, - ] - }) + self.unify_and( + a_raw, + b, + [Adjustment { kind: Adjust::Deref(None), target: mt_a.ty }], + Adjust::Borrow(AutoBorrow::RawPtr(mutbl_b)), + ) } else if mt_a.mutbl != mutbl_b { - self.unify_and(a_raw, b, simple(Adjust::Pointer(PointerCoercion::MutToConstPointer))) + self.unify_and(a_raw, b, [], Adjust::Pointer(PointerCoercion::MutToConstPointer)) } else { - self.unify_and(a_raw, b, identity) + self.unify(a_raw, b) } } } @@ -1119,9 +1106,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let cause = self.cause(DUMMY_SP, ObligationCauseCode::ExprAssignable); // We don't ever need two-phase here since we throw out the result of the coercion. let coerce = Coerce::new(self, cause, AllowTwoPhase::No, true); - coerce - .autoderef(DUMMY_SP, expr_ty) - .find_map(|(ty, steps)| self.probe(|_| coerce.unify(ty, target)).ok().map(|_| steps)) + coerce.autoderef(DUMMY_SP, expr_ty).find_map(|(ty, steps)| { + self.probe(|_| coerce.unify_raw(ty, target)).ok().map(|_| steps) + }) } /// Given a type, this function will calculate and return the type given @@ -1240,10 +1227,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } }; if let (Some(a_sig), Some(b_sig)) = (a_sig, b_sig) { - // Intrinsics are not coercible to function pointers. - if a_sig.abi() == ExternAbi::RustIntrinsic || b_sig.abi() == ExternAbi::RustIntrinsic { - return Err(TypeError::IntrinsicCast); - } // The signature must match. let (a_sig, b_sig) = self.normalize(new.span, (a_sig, b_sig)); let sig = self diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index b845e2190ef0..d1bc54ed73ea 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -865,10 +865,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // `&'name Ty` -> `&'name mut Ty` or `&Ty` -> `&mut Ty` vec![( ty_ref.1.ty.span.shrink_to_lo(), - format!( - "{}mut ", - if ty_ref.0.ident.span.lo() == ty_ref.0.ident.span.hi() { "" } else { " " }, - ), + format!("{}mut ", if ty_ref.0.ident.span.is_empty() { "" } else { " " },), )] }; sugg.extend([ @@ -1092,14 +1089,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// This function checks whether the method is not static and does not accept other parameters than `self`. fn has_only_self_parameter(&self, method: &AssocItem) -> bool { - match method.kind { - ty::AssocKind::Fn => { - method.fn_has_self_parameter - && self.tcx.fn_sig(method.def_id).skip_binder().inputs().skip_binder().len() - == 1 - } - _ => false, - } + method.is_method() + && self.tcx.fn_sig(method.def_id).skip_binder().inputs().skip_binder().len() == 1 } /// If the given `HirId` corresponds to a block with a trailing expression, return that expression diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index b73cd26927a5..9e7305430e5f 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -5,7 +5,7 @@ use std::borrow::Cow; use rustc_errors::codes::*; use rustc_errors::{ Applicability, Diag, DiagArgValue, DiagSymbolList, EmissionGuarantee, IntoDiagArg, MultiSpan, - SubdiagMessageOp, Subdiagnostic, + Subdiagnostic, }; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_middle::ty::{self, Ty}; @@ -270,11 +270,7 @@ pub(crate) struct SuggestAnnotations { pub suggestions: Vec, } impl Subdiagnostic for SuggestAnnotations { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { if self.suggestions.is_empty() { return; } @@ -337,11 +333,7 @@ pub(crate) struct TypeMismatchFruTypo { } impl Subdiagnostic for TypeMismatchFruTypo { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { diag.arg("expr", self.expr.as_deref().unwrap_or("NONE")); // Only explain that `a ..b` is a range if it's split up @@ -599,11 +591,7 @@ pub(crate) struct RemoveSemiForCoerce { } impl Subdiagnostic for RemoveSemiForCoerce { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { let mut multispan: MultiSpan = self.semi.into(); multispan.push_span_label(self.expr, fluent::hir_typeck_remove_semi_for_coerce_expr); multispan.push_span_label(self.ret, fluent::hir_typeck_remove_semi_for_coerce_ret); @@ -727,7 +715,7 @@ pub(crate) struct NoAssociatedItem { #[primary_span] pub span: Span, pub item_kind: &'static str, - pub item_name: Ident, + pub item_ident: Ident, pub ty_prefix: Cow<'static, str>, pub ty_str: String, pub trait_missing_method: bool, @@ -778,20 +766,16 @@ pub(crate) enum CastUnknownPointerSub { } impl rustc_errors::Subdiagnostic for CastUnknownPointerSub { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { match self { CastUnknownPointerSub::To(span) => { - let msg = f(diag, crate::fluent_generated::hir_typeck_label_to); + let msg = diag.eagerly_translate(fluent::hir_typeck_label_to); diag.span_label(span, msg); - let msg = f(diag, crate::fluent_generated::hir_typeck_note); + let msg = diag.eagerly_translate(fluent::hir_typeck_note); diag.note(msg); } CastUnknownPointerSub::From(span) => { - let msg = f(diag, crate::fluent_generated::hir_typeck_label_from); + let msg = diag.eagerly_translate(fluent::hir_typeck_label_from); diag.span_label(span, msg); } } diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 45ab8e03db57..d6a7bfc446a4 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -482,7 +482,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // All of these constitute a read, or match on something that isn't `!`, // which would require a `NeverToAny` coercion. - hir::PatKind::Binding(_, _, _, _) + hir::PatKind::Missing + | hir::PatKind::Binding(_, _, _, _) | hir::PatKind::Struct(_, _, _) | hir::PatKind::TupleStruct(_, _, _) | hir::PatKind::Tuple(_, _) @@ -1599,11 +1600,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Ok(method) } Err(error) => { - if segment.ident.name == kw::Empty { - span_bug!(rcvr.span, "empty method name") - } else { - Err(self.report_method_error(expr.hir_id, rcvr_t, error, expected, false)) - } + Err(self.report_method_error(expr.hir_id, rcvr_t, error, expected, false)) } }; @@ -2204,8 +2201,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let fields = listify(&missing_mandatory_fields, |f| format!("`{f}`")).unwrap(); self.dcx() .struct_span_err( - span.shrink_to_hi(), - format!("missing mandatory field{s} {fields}"), + span.shrink_to_lo(), + format!("missing field{s} {fields} in initializer"), + ) + .with_span_label( + span.shrink_to_lo(), + "fields that do not have a defaulted value must be provided explicitly", ) .emit(); return; @@ -2583,9 +2584,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .into_iter() .flat_map(|i| self.tcx.associated_items(i).in_definition_order()) // Only assoc fn with no receivers. - .filter(|item| { - matches!(item.kind, ty::AssocKind::Fn) && !item.fn_has_self_parameter - }) + .filter(|item| item.is_fn() && !item.is_method()) .filter_map(|item| { // Only assoc fns that return `Self` let fn_sig = self.tcx.fn_sig(item.def_id).skip_binder(); @@ -2598,8 +2597,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return None; } let input_len = fn_sig.inputs().skip_binder().len(); - let order = !item.name.as_str().starts_with("new"); - Some((order, item.name, input_len)) + let name = item.name(); + let order = !name.as_str().starts_with("new"); + Some((order, name, input_len)) }) .collect::>(); items.sort_by_key(|(order, _, _)| *order); @@ -2915,8 +2915,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } // We failed to check the expression, report an error. - // Emits an error if we deref an infer variable, like calling `.field` on a base type of &_. - self.structurally_resolve_type(autoderef.span(), autoderef.final_ty(false)); + // Emits an error if we deref an infer variable, like calling `.field` on a base type + // of `&_`. We can also use this to suppress unnecessary "missing field" errors that + // will follow ambiguity errors. + let final_ty = self.structurally_resolve_type(autoderef.span(), autoderef.final_ty(false)); + if let ty::Error(_) = final_ty.kind() { + return final_ty; + } if let Some((adjustments, did)) = private_candidate { // (#90483) apply adjustments to avoid ExprUseVisitor from @@ -2932,9 +2937,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return Ty::new_error(self.tcx(), guar); } - let guar = if field.name == kw::Empty { - self.dcx().span_bug(field.span, "field name with no name") - } else if self.method_exists_for_diagnostic( + let guar = if self.method_exists_for_diagnostic( field, base_ty, expr.hir_id, diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs index 64176dacb73a..f5e0f01e4c57 100644 --- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs @@ -611,6 +611,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx for pat in pats { self.cat_pattern(discr_place.clone(), pat, &mut |place, pat| { match &pat.kind { + PatKind::Missing => unreachable!(), PatKind::Binding(.., opt_sub_pat) => { // If the opt_sub_pat is None, then the binding does not count as // a wildcard for the purpose of borrowing discr. @@ -999,6 +1000,8 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx // determines whether to borrow *at the level of the deref pattern* rather than // borrowing the bound place (since that inner place is inside the temporary that // stores the result of calling `deref()`/`deref_mut()` so can't be captured). + // HACK: this could be a fake pattern corresponding to a deref inserted by match + // ergonomics, in which case `pat.hir_id` will be the id of the subpattern. let mutable = self.cx.typeck_results().pat_has_ref_mut_binding(subpattern); let mutability = if mutable { hir::Mutability::Mut } else { hir::Mutability::Not }; @@ -1226,9 +1229,9 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx // actually this is somewhat "disjoint" from the code below // that aims to account for `ref x`. if let Some(vec) = self.cx.typeck_results().pat_adjustments().get(pat.hir_id) { - if let Some(first_ty) = vec.first() { - debug!("pat_ty(pat={:?}) found adjusted ty `{:?}`", pat, first_ty); - return Ok(*first_ty); + if let Some(first_adjust) = vec.first() { + debug!("pat_ty(pat={:?}) found adjustment `{:?}`", pat, first_adjust); + return Ok(first_adjust.source); } } else if let PatKind::Ref(subpat, _) = pat.kind && self.cx.typeck_results().skipped_ref_pats().contains(pat.hir_id) @@ -1501,16 +1504,21 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx let mut projections = base_place.place.projections; let node_ty = self.cx.typeck_results().node_type(node); - // Opaque types can't have field projections, but we can instead convert - // the current place in-place (heh) to the hidden type, and then apply all - // follow up projections on that. - if node_ty != place_ty - && self - .cx - .try_structurally_resolve_type(self.cx.tcx().hir_span(base_place.hir_id), place_ty) - .is_impl_trait() - { - projections.push(Projection { kind: ProjectionKind::OpaqueCast, ty: node_ty }); + if !self.cx.tcx().next_trait_solver_globally() { + // Opaque types can't have field projections, but we can instead convert + // the current place in-place (heh) to the hidden type, and then apply all + // follow up projections on that. + if node_ty != place_ty + && self + .cx + .try_structurally_resolve_type( + self.cx.tcx().hir_span(base_place.hir_id), + place_ty, + ) + .is_impl_trait() + { + projections.push(Projection { kind: ProjectionKind::OpaqueCast, ty: node_ty }); + } } projections.push(Projection { kind, ty }); PlaceWithHirId::new(node, base_place.place.base_ty, base_place.place.base, projections) @@ -1674,12 +1682,31 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx // Then we see that to get the same result, we must start with // `deref { deref { place_foo }}` instead of `place_foo` since the pattern is now `Some(x,)` // and not `&&Some(x,)`, even though its assigned type is that of `&&Some(x,)`. - for _ in - 0..self.cx.typeck_results().pat_adjustments().get(pat.hir_id).map_or(0, |v| v.len()) - { + let typeck_results = self.cx.typeck_results(); + let adjustments: &[adjustment::PatAdjustment<'tcx>] = + typeck_results.pat_adjustments().get(pat.hir_id).map_or(&[], |v| &**v); + let mut adjusts = adjustments.iter().peekable(); + while let Some(adjust) = adjusts.next() { debug!("applying adjustment to place_with_id={:?}", place_with_id); - place_with_id = self.cat_deref(pat.hir_id, place_with_id)?; + place_with_id = match adjust.kind { + adjustment::PatAdjust::BuiltinDeref => self.cat_deref(pat.hir_id, place_with_id)?, + adjustment::PatAdjust::OverloadedDeref => { + // This adjustment corresponds to an overloaded deref; it borrows the scrutinee to + // call `Deref::deref` or `DerefMut::deref_mut`. Invoke the callback before setting + // `place_with_id` to the temporary storing the result of the deref. + // HACK(dianne): giving the callback a fake deref pattern makes sure it behaves the + // same as it would if this were an explicit deref pattern. + op(&place_with_id, &hir::Pat { kind: PatKind::Deref(pat), ..*pat })?; + let target_ty = match adjusts.peek() { + Some(&&next_adjust) => next_adjust.source, + // At the end of the deref chain, we get `pat`'s scrutinee. + None => self.pat_ty_unadjusted(pat)?, + }; + self.pat_deref_temp(pat.hir_id, pat, target_ty)? + } + }; } + drop(typeck_results); // explicitly release borrow of typeck results, just in case. let place_with_id = place_with_id; // lose mutability debug!("applied adjustment derefs to get place_with_id={:?}", place_with_id); @@ -1782,14 +1809,8 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx self.cat_pattern(subplace, subpat, op)?; } PatKind::Deref(subpat) => { - let mutable = self.cx.typeck_results().pat_has_ref_mut_binding(subpat); - let mutability = if mutable { hir::Mutability::Mut } else { hir::Mutability::Not }; - let re_erased = self.cx.tcx().lifetimes.re_erased; let ty = self.pat_ty_adjusted(subpat)?; - let ty = Ty::new_ref(self.cx.tcx(), re_erased, ty, mutability); - // A deref pattern generates a temporary. - let base = self.cat_rvalue(pat.hir_id, ty); - let place = self.cat_deref(pat.hir_id, base)?; + let place = self.pat_deref_temp(pat.hir_id, subpat, ty)?; self.cat_pattern(place, subpat, op)?; } @@ -1832,6 +1853,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx | PatKind::Expr(..) | PatKind::Range(..) | PatKind::Never + | PatKind::Missing | PatKind::Wild | PatKind::Err(_) => { // always ok @@ -1841,6 +1863,23 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx Ok(()) } + /// Represents the place of the temp that stores the scrutinee of a deref pattern's interior. + fn pat_deref_temp( + &self, + hir_id: HirId, + inner: &hir::Pat<'_>, + target_ty: Ty<'tcx>, + ) -> Result, Cx::Error> { + let mutable = self.cx.typeck_results().pat_has_ref_mut_binding(inner); + let mutability = if mutable { hir::Mutability::Mut } else { hir::Mutability::Not }; + let re_erased = self.cx.tcx().lifetimes.re_erased; + let ty = Ty::new_ref(self.cx.tcx(), re_erased, target_ty, mutability); + // A deref pattern stores the result of `Deref::deref` or `DerefMut::deref_mut` ... + let base = self.cat_rvalue(hir_id, ty); + // ... and the inner pattern matches on the place behind that reference. + self.cat_deref(hir_id, base) + } + fn is_multivariant_adt(&self, ty: Ty<'tcx>, span: Span) -> bool { if let ty::Adt(def, _) = self.cx.try_structurally_resolve_type(span, ty).kind() { // Note that if a non-exhaustive SingleVariant is defined in another crate, we need diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 91190a32ff54..87d92b3fbde8 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -27,9 +27,9 @@ use rustc_middle::ty::{ }; use rustc_middle::{bug, span_bug}; use rustc_session::lint; +use rustc_span::Span; use rustc_span::def_id::LocalDefId; use rustc_span::hygiene::DesugaringKind; -use rustc_span::{Span, kw}; use rustc_trait_selection::error_reporting::infer::need_type_info::TypeAnnotationNeeded; use rustc_trait_selection::traits::{ self, NormalizeExt, ObligationCauseCode, StructurallyNormalizeExt, @@ -833,7 +833,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let trait_missing_method = matches!(error, method::MethodError::NoMatch(_)) && ty.normalized.is_trait(); - assert_ne!(item_name.name, kw::Empty); self.report_method_error( hir_id, ty.normalized, diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index f4bd7ec701f8..da0e8e362d66 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -616,7 +616,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { 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 + && assoc.is_method() { Some(*receiver) } else { @@ -642,8 +642,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { TraitsInScope, |mut ctxt| ctxt.probe_for_similar_candidate(), ) - && let ty::AssocKind::Fn = assoc.kind - && assoc.fn_has_self_parameter + && assoc.is_method() { let args = self.infcx.fresh_args_for_item(call_name.span, assoc.def_id); let fn_sig = tcx.fn_sig(assoc.def_id).instantiate(tcx, args); @@ -684,10 +683,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .all(|(expected, found)| self.may_coerce(*expected, *found)) && fn_sig.inputs()[1..].len() == input_types.len() { + let assoc_name = assoc.name(); err.span_suggestion_verbose( call_name.span, - format!("you might have meant to use `{}`", assoc.name), - assoc.name, + format!("you might have meant to use `{}`", assoc_name), + assoc_name, Applicability::MaybeIncorrect, ); return; @@ -707,7 +707,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { tcx.def_span(assoc.def_id), format!( "there's is a method with similar name `{}`, but the arguments don't match", - assoc.name, + assoc.name(), ), ); return; @@ -719,7 +719,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { format!( "there's is a method with similar name `{}`, but their argument count \ doesn't match", - assoc.name, + assoc.name(), ), ); return; @@ -1136,7 +1136,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && let self_implicit = matches!(call_expr.kind, hir::ExprKind::MethodCall(..)) as usize && let Some(Some(arg)) = - self.tcx.fn_arg_names(fn_def_id).get(expected_idx.as_usize() + self_implicit) + self.tcx.fn_arg_idents(fn_def_id).get(expected_idx.as_usize() + self_implicit) && arg.name != kw::SelfLower { format!("/* {} */", arg.name) @@ -2619,7 +2619,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { is_method: bool, ) -> Option<(IndexVec, FnParam<'_>)>, &hir::Generics<'_>)> { - let (sig, generics, body_id, param_names) = match self.tcx.hir_get_if_local(def_id)? { + let (sig, generics, body_id, params) = match self.tcx.hir_get_if_local(def_id)? { hir::Node::TraitItem(&hir::TraitItem { generics, kind: hir::TraitItemKind::Fn(sig, trait_fn), @@ -2661,7 +2661,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { None } }); - match (body_id, param_names) { + match (body_id, params) { (Some(_), Some(_)) | (None, None) => unreachable!(), (Some(body), None) => { let params = self.tcx.hir_body(body).params; @@ -2678,7 +2678,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { params.get(is_method as usize..params.len() - sig.decl.c_variadic as usize)?; debug_assert_eq!(params.len(), fn_inputs.len()); Some(( - fn_inputs.zip(params.iter().map(|&ident| FnParam::Name(ident))).collect(), + fn_inputs.zip(params.iter().map(|&ident| FnParam::Ident(ident))).collect(), generics, )) } @@ -2709,14 +2709,14 @@ impl<'tcx> Visitor<'tcx> for FindClosureArg<'tcx> { #[derive(Clone, Copy)] enum FnParam<'hir> { Param(&'hir hir::Param<'hir>), - Name(Option), + Ident(Option), } impl FnParam<'_> { fn span(&self) -> Span { match self { Self::Param(param) => param.span, - Self::Name(ident) => { + Self::Ident(ident) => { if let Some(ident) = ident { ident.span } else { @@ -2738,7 +2738,7 @@ impl FnParam<'_> { { Some(ident.name) } - FnParam::Name(ident) + FnParam::Ident(ident) if let Some(ident) = ident && ident.name != kw::Underscore => { diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index e14f1528d2c4..934820eb4daf 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -314,7 +314,7 @@ impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> { item_def_id: DefId, item_segment: &rustc_hir::PathSegment<'tcx>, poly_trait_ref: ty::PolyTraitRef<'tcx>, - _kind: ty::AssocKind, + _assoc_tag: ty::AssocTag, ) -> Result<(DefId, ty::GenericArgsRef<'tcx>), ErrorGuaranteed> { let trait_ref = self.instantiate_binder_with_fresh_vars( span, @@ -488,7 +488,7 @@ fn parse_never_type_options_attr( item.span(), format!( "unknown or duplicate never type option: `{}` (supported: `fallback`, `diverging_block_default`)", - item.name_or_empty() + item.name().unwrap() ), ); } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 912098c4e2d6..91eb1989864f 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -381,9 +381,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut suggestions = methods .iter() .filter_map(|conversion_method| { + let conversion_method_name = conversion_method.name(); let receiver_method_ident = expr.method_ident(); if let Some(method_ident) = receiver_method_ident - && method_ident.name == conversion_method.name + && method_ident.name == conversion_method_name { return None; // do not suggest code that is already there (#53348) } @@ -391,20 +392,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { 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) + && 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())] + vec![(receiver_method.ident.span, conversion_method_name.to_string())] } else if expr.precedence() < ExprPrecedence::Unambiguous { vec![ (expr.span.shrink_to_lo(), "(".to_string()), - (expr.span.shrink_to_hi(), format!(").{}()", conversion_method.name)), + (expr.span.shrink_to_hi(), format!(").{}()", conversion_method_name)), ] } else { - vec![(expr.span.shrink_to_hi(), format!(".{}()", conversion_method.name))] + vec![(expr.span.shrink_to_hi(), format!(".{}()", conversion_method_name))] }; let struct_pat_shorthand_field = self.tcx.hir_maybe_get_struct_pattern_shorthand_field(expr); diff --git a/compiler/rustc_hir_typeck/src/gather_locals.rs b/compiler/rustc_hir_typeck/src/gather_locals.rs index 48fd5f1f9824..5d87e800096f 100644 --- a/compiler/rustc_hir_typeck/src/gather_locals.rs +++ b/compiler/rustc_hir_typeck/src/gather_locals.rs @@ -43,7 +43,7 @@ pub(super) struct Declaration<'a> { impl<'a> From<&'a hir::LetStmt<'a>> for Declaration<'a> { fn from(local: &'a hir::LetStmt<'a>) -> Self { - let hir::LetStmt { hir_id, pat, ty, span, init, els, source: _ } = *local; + let hir::LetStmt { hir_id, super_: _, pat, ty, span, init, els, source: _ } = *local; Declaration { hir_id, pat, ty, span, init, origin: DeclOrigin::LocalDecl { els } } } } diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index 46389668de7c..af8ec3739347 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -1,7 +1,6 @@ // tidy-alphabetical-start #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] -#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![feature(array_windows)] #![feature(box_patterns)] #![feature(if_let_guard)] @@ -117,7 +116,7 @@ fn typeck_with_inspect<'tcx>( let id = tcx.local_def_id_to_hir_id(def_id); let node = tcx.hir_node(id); - let span = tcx.hir_span(id); + let span = tcx.def_span(def_id); // Figure out what primary body this item has. let body_id = node.body_id().unwrap_or_else(|| { @@ -266,7 +265,7 @@ fn infer_type_if_missing<'tcx>(fcx: &FnCtxt<'_, 'tcx>, node: Node<'tcx>) -> Opti let expected_type = if let Some(&hir::Ty { kind: hir::TyKind::Infer(()), span, .. }) = node.ty() { if let Some(item) = tcx.opt_associated_item(def_id.into()) - && let ty::AssocKind::Const = item.kind + && let ty::AssocKind::Const { .. } = item.kind && let ty::AssocItemContainer::Impl = item.container && let Some(trait_item_def_id) = item.trait_item_def_id { diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs index 4008021c3a85..1b67e2306aa7 100644 --- a/compiler/rustc_hir_typeck/src/method/mod.rs +++ b/compiler/rustc_hir_typeck/src/method/mod.rs @@ -379,7 +379,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; let def_id = method_item.def_id; - if method_item.kind != ty::AssocKind::Fn { + if !method_item.is_fn() { span_bug!(tcx.def_span(def_id), "expected `{m_name}` to be an associated function"); } @@ -529,17 +529,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - let def_kind = pick.item.kind.as_def_kind(); + let def_kind = pick.item.as_def_kind(); tcx.check_stability(pick.item.def_id, Some(expr_id), span, Some(method_name.span)); Ok((def_kind, pick.item.def_id)) } - /// Finds item with name `item_name` defined in impl/trait `def_id` + /// Finds item with name `item_ident` defined in impl/trait `def_id` /// and return it, or `None`, if no such item was defined there. - fn associated_value(&self, def_id: DefId, item_name: Ident) -> Option { + fn associated_value(&self, def_id: DefId, item_ident: Ident) -> Option { self.tcx .associated_items(def_id) - .find_by_name_and_namespace(self.tcx, item_name, Namespace::ValueNS, def_id) + .find_by_ident_and_namespace(self.tcx, item_ident, Namespace::ValueNS, def_id) .copied() } } diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 0a01ec89a327..1d3a081cbb88 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -992,7 +992,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { fn matches_return_type(&self, method: ty::AssocItem, expected: Ty<'tcx>) -> bool { match method.kind { - ty::AssocKind::Fn => self.probe(|_| { + ty::AssocKind::Fn { .. } => self.probe(|_| { let args = self.fresh_args_for_item(self.span, method.def_id); let fty = self.tcx.fn_sig(method.def_id).instantiate(self.tcx, args); let fty = self.instantiate_binder_with_fresh_vars(self.span, infer::FnCall, fty); @@ -1583,7 +1583,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { }, None, ) { - self.private_candidate.set(Some((pick.item.kind.as_def_kind(), pick.item.def_id))); + self.private_candidate.set(Some((pick.item.as_def_kind(), pick.item.def_id))); } } None @@ -1671,16 +1671,7 @@ impl<'tcx> Pick<'tcx> { /// Do not use for type checking. pub(crate) fn differs_from(&self, other: &Self) -> bool { let Self { - item: - AssocItem { - def_id, - name: _, - kind: _, - container: _, - trait_item_def_id: _, - fn_has_self_parameter: _, - opt_rpitit_info: _, - }, + item: AssocItem { def_id, kind: _, container: _, trait_item_def_id: _ }, kind: _, import_ids: _, autoderefs: _, @@ -1703,7 +1694,7 @@ impl<'tcx> Pick<'tcx> { if self.unstable_candidates.is_empty() { return; } - let def_kind = self.item.kind.as_def_kind(); + let def_kind = self.item.as_def_kind(); tcx.node_span_lint(lint::builtin::UNSTABLE_NAME_COLLISIONS, scope_expr_id, span, |lint| { lint.primary_message(format!( "{} {} with this name may be added to the standard library in the future", @@ -1712,7 +1703,7 @@ impl<'tcx> Pick<'tcx> { )); match (self.item.kind, self.item.container) { - (ty::AssocKind::Fn, _) => { + (ty::AssocKind::Fn { .. }, _) => { // FIXME: This should be a `span_suggestion` instead of `help` // However `self.span` only // highlights the method name, so we can't use it. Also consider reusing @@ -1723,17 +1714,12 @@ impl<'tcx> Pick<'tcx> { tcx.def_path_str(self.item.def_id), )); } - (ty::AssocKind::Const, ty::AssocItemContainer::Trait) => { + (ty::AssocKind::Const { name }, ty::AssocItemContainer::Trait) => { let def_id = self.item.container_id(tcx); lint.span_suggestion( span, "use the fully qualified path to the associated const", - format!( - "<{} as {}>::{}", - self.self_ty, - tcx.def_path_str(def_id), - self.item.name - ), + format!("<{} as {}>::{}", self.self_ty, tcx.def_path_str(def_id), name), Applicability::MachineApplicable, ); } @@ -2222,7 +2208,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { let best_name = { let names = applicable_close_candidates .iter() - .map(|cand| cand.name) + .map(|cand| cand.name()) .collect::>(); find_best_match_for_name_with_substrings( &names, @@ -2234,10 +2220,12 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { applicable_close_candidates .iter() .find(|cand| self.matches_by_doc_alias(cand.def_id)) - .map(|cand| cand.name) + .map(|cand| cand.name()) }); Ok(best_name.and_then(|best_name| { - applicable_close_candidates.into_iter().find(|method| method.name == best_name) + applicable_close_candidates + .into_iter() + .find(|method| method.name() == best_name) })) } }) @@ -2252,10 +2240,10 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { // In Path mode (i.e., resolving a value like `T::next`), consider any // associated value (i.e., methods, constants) but not types. match self.mode { - Mode::MethodCall => item.fn_has_self_parameter, + Mode::MethodCall => item.is_method(), Mode::Path => match item.kind { - ty::AssocKind::Type => false, - ty::AssocKind::Fn | ty::AssocKind::Const => true, + ty::AssocKind::Type { .. } => false, + ty::AssocKind::Fn { .. } | ty::AssocKind::Const { .. } => true, }, } // FIXME -- check for types that deref to `Self`, @@ -2277,7 +2265,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { impl_ty: Ty<'tcx>, args: GenericArgsRef<'tcx>, ) -> (Ty<'tcx>, Option>) { - if item.kind == ty::AssocKind::Fn && self.mode == Mode::MethodCall { + if item.is_fn() && self.mode == Mode::MethodCall { let sig = self.xform_method_sig(item.def_id, args); (sig.inputs()[0], Some(sig.output())) } else { @@ -2328,8 +2316,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { /// Determine if the given associated item type is relevant in the current context. fn is_relevant_kind_for_mode(&self, kind: ty::AssocKind) -> bool { match (self.mode, kind) { - (Mode::MethodCall, ty::AssocKind::Fn) => true, - (Mode::Path, ty::AssocKind::Const | ty::AssocKind::Fn) => true, + (Mode::MethodCall, ty::AssocKind::Fn { .. }) => true, + (Mode::Path, ty::AssocKind::Const { .. } | ty::AssocKind::Fn { .. }) => true, _ => false, } } @@ -2346,8 +2334,9 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { let hir_id = self.fcx.tcx.local_def_id_to_hir_id(local_def_id); let attrs = self.fcx.tcx.hir_attrs(hir_id); for attr in attrs { - if sym::doc == attr.name_or_empty() { - } else if sym::rustc_confusables == attr.name_or_empty() { + if attr.has_name(sym::doc) { + // do nothing + } else if attr.has_name(sym::rustc_confusables) { let Some(confusables) = attr.meta_item_list() else { continue; }; @@ -2367,7 +2356,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { continue; }; for v in values { - if v.name_or_empty() != sym::alias { + if !v.has_name(sym::alias) { continue; } if let Some(nested) = v.meta_item_list() { @@ -2411,7 +2400,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } match edit_distance_with_substrings( name.as_str(), - x.name.as_str(), + x.name().as_str(), max_dist, ) { Some(d) => d > 0, diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 246b23f11b68..6a9fd7cdd483 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -25,6 +25,7 @@ use rustc_middle::bug; use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams, simplify_type}; use rustc_middle::ty::print::{ PrintTraitRefExt as _, with_crate_prefix, with_forced_trimmed_paths, + with_no_visible_paths_if_doc_hidden, }; use rustc_middle::ty::{self, GenericArgKind, IsSuggestable, Ty, TyCtxt, TypeVisitableExt}; use rustc_span::def_id::DefIdSet; @@ -584,7 +585,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, mut span: Span, rcvr_ty: Ty<'tcx>, - item_name: Ident, + item_ident: Ident, expr_id: hir::HirId, source: SelfSource<'tcx>, args: Option<&'tcx [hir::Expr<'tcx>]>, @@ -615,7 +616,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else if rcvr_ty.is_enum() { "variant or associated item" } else { - match (item_name.as_str().chars().next(), rcvr_ty.is_fresh_ty()) { + match (item_ident.as_str().chars().next(), rcvr_ty.is_fresh_ty()) { (Some(name), false) if name.is_lowercase() => "function or associated item", (Some(_), false) => "associated item", (Some(_), true) | (None, false) => "variant or associated item", @@ -630,7 +631,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { rcvr_ty, source, span, - item_name, + item_ident, &short_ty_str, &mut ty_file, ) { @@ -642,13 +643,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { source, span, item_kind, - item_name, + item_ident, &short_ty_str, &mut ty_file, ) { return guar; } - span = item_name.span; + span = item_ident.span; // Don't show generic arguments when the method can't be found in any implementation (#81576). let mut ty_str_reported = ty_str.clone(); @@ -660,7 +661,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.tcx .inherent_impls(adt_def.did()) .into_iter() - .any(|def_id| self.associated_value(*def_id, item_name).is_some()) + .any(|def_id| self.associated_value(*def_id, item_ident).is_some()) } else { false } @@ -677,14 +678,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let is_write = sugg_span.ctxt().outer_expn_data().macro_def_id.is_some_and(|def_id| { tcx.is_diagnostic_item(sym::write_macro, def_id) || tcx.is_diagnostic_item(sym::writeln_macro, def_id) - }) && item_name.name == sym::write_fmt; + }) && item_ident.name == sym::write_fmt; let mut err = if is_write && let SelfSource::MethodCall(rcvr_expr) = source { self.suggest_missing_writer(rcvr_ty, rcvr_expr) } else { let mut err = self.dcx().create_err(NoAssociatedItem { span, item_kind, - item_name, + item_ident, ty_prefix: if trait_missing_method { // FIXME(mu001999) E0599 maybe not suitable here because it is for types Cow::from("trait") @@ -698,7 +699,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if is_method { self.suggest_use_shadowed_binding_with_method( source, - item_name, + item_ident, &ty_str_reported, &mut err, ); @@ -709,10 +710,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = ty.kind && let Res::SelfTyAlias { alias_to: impl_def_id, .. } = path.res && let DefKind::Impl { .. } = self.tcx.def_kind(impl_def_id) - && let Some(candidate) = tcx.associated_items(impl_def_id).find_by_name_and_kind( + && let Some(candidate) = tcx.associated_items(impl_def_id).find_by_ident_and_kind( self.tcx, - item_name, - ty::AssocKind::Type, + item_ident, + ty::AssocTag::Type, impl_def_id, ) && let Some(adt_def) = tcx.type_of(candidate.def_id).skip_binder().ty_adt_def() @@ -721,7 +722,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { let def_path = tcx.def_path_str(adt_def.did()); err.span_suggestion( - ty.span.to(item_name.span), + ty.span.to(item_ident.span), format!("to construct a value of type `{}`, use the explicit path", def_path), def_path, Applicability::MachineApplicable, @@ -749,7 +750,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.find_builder_fn(&mut err, rcvr_ty, expr_id); } - if tcx.ty_is_opaque_future(rcvr_ty) && item_name.name == sym::poll { + if tcx.ty_is_opaque_future(rcvr_ty) && item_ident.name == sym::poll { err.help(format!( "method `poll` found on `Pin<&mut {ty_str}>`, \ see documentation for `std::pin::Pin`" @@ -764,7 +765,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { self.suggest_await_before_method( &mut err, - item_name, + item_ident, rcvr_ty, cal, span, @@ -786,7 +787,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let SelfSource::MethodCall(rcvr_expr) = source && let ty::RawPtr(ty, ptr_mutbl) = *rcvr_ty.kind() && let Ok(pick) = self.lookup_probe_for_diagnostic( - item_name, + item_ident, Ty::new_ref(tcx, ty::Region::new_error_misc(tcx), ty, ptr_mutbl), self.tcx.hir_expect_expr(self.tcx.parent_hir_id(rcvr_expr.hir_id)), ProbeScope::TraitsInScope, @@ -807,7 +808,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; err.span_note( tcx.def_span(pick.item.def_id), - format!("the method `{item_name}` exists on the type `{ty}`", ty = pick.self_ty), + format!("the method `{item_ident}` exists on the type `{ty}`", ty = pick.self_ty), ); let mut_str = ptr_mutbl.ptr_str(); err.note(format!( @@ -833,7 +834,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.suggest_fn_call(&mut err, rcvr_expr, rcvr_ty, |output_ty| { let call_expr = self.tcx.hir_expect_expr(self.tcx.parent_hir_id(rcvr_expr.hir_id)); let probe = self.lookup_probe_for_diagnostic( - item_name, + item_ident, output_ty, call_expr, ProbeScope::AllTraits, @@ -872,13 +873,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { static_candidates, rcvr_ty, source, - item_name, + item_ident, args, sugg_span, ); self.note_candidates_on_method_error( rcvr_ty, - item_name, + item_ident, source, args, span, @@ -889,7 +890,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else if static_candidates.len() > 1 { self.note_candidates_on_method_error( rcvr_ty, - item_name, + item_ident, source, args, span, @@ -903,7 +904,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut restrict_type_params = false; let mut suggested_derive = false; let mut unsatisfied_bounds = false; - if item_name.name == sym::count && self.is_slice_ty(rcvr_ty, span) { + if item_ident.name == sym::count && self.is_slice_ty(rcvr_ty, span) { let msg = "consider using `len` instead"; if let SelfSource::MethodCall(_expr) = source { err.span_suggestion_short(span, msg, "len", Applicability::MachineApplicable); @@ -1348,7 +1349,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; let primary_message = primary_message.unwrap_or_else(|| { format!( - "the {item_kind} `{item_name}` exists for {actual_prefix} `{ty_str}`, \ + "the {item_kind} `{item_ident}` exists for {actual_prefix} `{ty_str}`, \ but its trait bounds were not satisfied" ) }); @@ -1378,7 +1379,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // `Pin<&Self>`. if targs.len() == 1 { let mut item_segment = hir::PathSegment::invalid(); - item_segment.ident = item_name; + item_segment.ident = item_ident; for t in [Ty::new_mut_ref, Ty::new_imm_ref, |_, _, t| t] { let new_args = tcx.mk_args_from_iter(targs.iter().map(|arg| match arg.as_type() { @@ -1422,9 +1423,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::Adt(adt, _) => self.tcx.is_lang_item(adt.did(), LangItem::String), _ => false, }; - if is_string_or_ref_str && item_name.name == sym::iter { + if is_string_or_ref_str && item_ident.name == sym::iter { err.span_suggestion_verbose( - item_name.span, + item_ident.span, "because of the in-memory representation of `&str`, to obtain \ an `Iterator` over each of its codepoint use method `chars`", "chars", @@ -1438,10 +1439,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .into_iter() .copied() .filter(|def_id| { - if let Some(assoc) = self.associated_value(*def_id, item_name) { + if let Some(assoc) = self.associated_value(*def_id, item_ident) { // Check for both mode is the same so we avoid suggesting // incorrect associated item. - match (mode, assoc.fn_has_self_parameter, source) { + match (mode, assoc.is_method(), source) { (Mode::MethodCall, true, SelfSource::MethodCall(_)) => { // We check that the suggest type is actually // different from the received one @@ -1499,7 +1500,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // If the method name is the name of a field with a function or closure type, // give a helping note that it has to be called as `(x.f)(...)`. if let SelfSource::MethodCall(expr) = source { - if !self.suggest_calling_field_as_fn(span, rcvr_ty, expr, item_name, &mut err) + if !self.suggest_calling_field_as_fn(span, rcvr_ty, expr, item_ident, &mut err) && similar_candidate.is_none() && !custom_span_label { @@ -1512,7 +1513,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let confusable_suggested = self.confusable_method_name( &mut err, rcvr_ty, - item_name, + item_ident, args.map(|args| { args.iter() .map(|expr| { @@ -1530,12 +1531,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { source, span, rcvr_ty, - item_name, + item_ident, expected.only_has_type(self), ); } - self.suggest_unwrapping_inner_self(&mut err, source, rcvr_ty, item_name); + self.suggest_unwrapping_inner_self(&mut err, source, rcvr_ty, item_ident); for (span, mut bounds) in bound_spans { if !tcx.sess.source_map().is_span_accessible(span) { @@ -1546,7 +1547,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let pre = if Some(span) == ty_span { ty_span.take(); format!( - "{item_kind} `{item_name}` not found for this {} because it ", + "{item_kind} `{item_ident}` not found for this {} because it ", rcvr_ty.prefix_string(self.tcx) ) } else { @@ -1566,7 +1567,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.span_label( span, format!( - "{item_kind} `{item_name}` not found for this {}", + "{item_kind} `{item_ident}` not found for this {}", rcvr_ty.prefix_string(self.tcx) ), ); @@ -1578,7 +1579,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &mut err, span, rcvr_ty, - item_name, + item_ident, args.map(|args| args.len() + 1), source, no_match_data.out_of_scope_traits.clone(), @@ -1595,7 +1596,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let adt_def = rcvr_ty.ty_adt_def().expect("enum is not an ADT"); if let Some(var_name) = edit_distance::find_best_match_for_name( &adt_def.variants().iter().map(|s| s.name).collect::>(), - item_name.name, + item_ident.name, None, ) && let Some(variant) = adt_def.variants().iter().find(|s| s.name == var_name) { @@ -1721,7 +1722,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // that had unsatisfied trait bounds if unsatisfied_predicates.is_empty() // ...or if we already suggested that name because of `rustc_confusable` annotation. - && Some(similar_candidate.name) != confusable_suggested + && Some(similar_candidate.name()) != confusable_suggested { self.find_likely_intended_associated_item( &mut err, @@ -1736,14 +1737,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if !find_candidate_for_method { self.lookup_segments_chain_for_no_match_method( &mut err, - item_name, + item_ident, item_kind, source, no_match_data, ); } - self.note_derefed_ty_has_method(&mut err, source, rcvr_ty, item_name, expected); + self.note_derefed_ty_has_method(&mut err, source, rcvr_ty, item_ident, expected); err.emit() } @@ -1818,12 +1819,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { mode: Mode, ) { let tcx = self.tcx; - let def_kind = similar_candidate.kind.as_def_kind(); + let def_kind = similar_candidate.as_def_kind(); let an = self.tcx.def_kind_descr_article(def_kind, similar_candidate.def_id); + let similar_candidate_name = similar_candidate.name(); let msg = format!( "there is {an} {} `{}` with a similar name", self.tcx.def_kind_descr(def_kind, similar_candidate.def_id), - similar_candidate.name, + similar_candidate_name, ); // Methods are defined within the context of a struct and their first parameter // is always `self`, which represents the instance of the struct the method is @@ -1833,7 +1835,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ty_args = self.infcx.fresh_args_for_item(span, similar_candidate.def_id); let fn_sig = tcx.fn_sig(similar_candidate.def_id).instantiate(tcx, ty_args); let fn_sig = self.instantiate_binder_with_fresh_vars(span, infer::FnCall, fn_sig); - if similar_candidate.fn_has_self_parameter { + if similar_candidate.is_method() { if let Some(args) = args && fn_sig.inputs()[1..].len() == args.len() { @@ -1842,7 +1844,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.span_suggestion_verbose( span, msg, - similar_candidate.name, + similar_candidate_name, Applicability::MaybeIncorrect, ); } else { @@ -1864,7 +1866,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.span_suggestion_verbose( span, msg, - similar_candidate.name, + similar_candidate_name, Applicability::MaybeIncorrect, ); } else { @@ -1877,7 +1879,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.span_suggestion_verbose( span, msg, - similar_candidate.name, + similar_candidate_name, Applicability::MaybeIncorrect, ); } else { @@ -1901,7 +1903,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { if let Some(candidates) = find_attr!(self.tcx.get_all_attrs(inherent_method.def_id), AttributeKind::Confusables{symbols, ..} => symbols) && candidates.contains(&item_name.name) - && let ty::AssocKind::Fn = inherent_method.kind + && inherent_method.is_fn() { let args = ty::GenericArgs::identity_for_item(self.tcx, inherent_method.def_id) @@ -1917,6 +1919,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { infer::FnCall, fn_sig, ); + let name = inherent_method.name(); if let Some(ref args) = call_args && fn_sig.inputs()[1..] .iter() @@ -1926,20 +1929,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { err.span_suggestion_verbose( item_name.span, - format!("you might have meant to use `{}`", inherent_method.name), - inherent_method.name, + format!("you might have meant to use `{}`", name), + name, Applicability::MaybeIncorrect, ); - return Some(inherent_method.name); + return Some(name); } else if let None = call_args { err.span_note( self.tcx.def_span(inherent_method.def_id), - format!( - "you might have meant to use method `{}`", - inherent_method.name, - ), + format!("you might have meant to use method `{}`", name), ); - return Some(inherent_method.name); + return Some(name); } } } @@ -2115,8 +2115,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Only assoc fn with no receivers and only if // they are resolvable .filter(|item| { - matches!(item.kind, ty::AssocKind::Fn) - && !item.fn_has_self_parameter + matches!(item.kind, ty::AssocKind::Fn { has_self: false, .. }) && self .probe_for_name( Mode::Path, @@ -2260,7 +2259,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; let assoc = self.associated_value(assoc_did, item_name)?; - if assoc.kind != ty::AssocKind::Fn { + if !assoc.is_fn() { return None; } @@ -3207,7 +3206,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // If this method receives `&self`, then the provided // argument _should_ coerce, so it's valid to suggest // just changing the path. - && pick.item.fn_has_self_parameter + && pick.item.is_method() && let Some(self_ty) = self.tcx.fn_sig(pick.item.def_id).instantiate_identity().inputs().skip_binder().get(0) && self_ty.is_ref() @@ -3328,7 +3327,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let path_strings = candidates.iter().map(|trait_did| { format!( "{prefix}{}{postfix}\n", - with_crate_prefix!(self.tcx.def_path_str(*trait_did)), + with_no_visible_paths_if_doc_hidden!(with_crate_prefix!( + self.tcx.def_path_str(*trait_did) + )), ) }); @@ -3336,7 +3337,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let parent_did = parent_map.get(trait_did).unwrap(); format!( "{prefix}{}::*{postfix} // trait {}\n", - with_crate_prefix!(self.tcx.def_path_str(*parent_did)), + with_no_visible_paths_if_doc_hidden!(with_crate_prefix!( + self.tcx.def_path_str(*parent_did) + )), self.tcx.item_name(*trait_did), ) }); @@ -3555,7 +3558,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { || (("Pin::new" == *pre) && ((sym::as_ref == item_name.name) || !unpin)) || inputs_len.is_some_and(|inputs_len| { - pick.item.kind == ty::AssocKind::Fn + pick.item.is_fn() && self .tcx .fn_sig(pick.item.def_id) @@ -3613,7 +3616,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && pick.autoderefs == 0 // Check that the method of the same name that was found on the new `Pin` // receiver has the same number of arguments that appear in the user's code. - && inputs_len.is_some_and(|inputs_len| pick.item.kind == ty::AssocKind::Fn && self.tcx.fn_sig(pick.item.def_id).skip_binder().skip_binder().inputs().len() == inputs_len) + && inputs_len.is_some_and(|inputs_len| pick.item.is_fn() && self.tcx.fn_sig(pick.item.def_id).skip_binder().skip_binder().inputs().len() == inputs_len) { let indent = self .tcx @@ -3751,7 +3754,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && self .associated_value(info.def_id, item_name) .filter(|item| { - if let ty::AssocKind::Fn = item.kind { + if item.is_fn() { let id = item .def_id .as_local() @@ -4274,17 +4277,17 @@ fn print_disambiguation_help<'tcx>( item: ty::AssocItem, ) -> Option { let trait_impl_type = trait_ref.self_ty().peel_refs(); - let trait_ref = if item.fn_has_self_parameter { + let trait_ref = if item.is_method() { trait_ref.print_only_trait_name().to_string() } else { format!("<{} as {}>", trait_ref.args[0], trait_ref.print_only_trait_name()) }; Some( - if matches!(item.kind, ty::AssocKind::Fn) + if item.is_fn() && let SelfSource::MethodCall(receiver) = source && let Some(args) = args { - let def_kind_descr = tcx.def_kind_descr(item.kind.as_def_kind(), item.def_id); + let def_kind_descr = tcx.def_kind_descr(item.as_def_kind(), item.def_id); let item_name = item.ident(tcx); let first_input = tcx.fn_sig(item.def_id).instantiate_identity().skip_binder().inputs().get(0); @@ -4299,7 +4302,7 @@ fn print_disambiguation_help<'tcx>( let args = if let Some(first_arg_type) = first_arg_type && (first_arg_type == tcx.types.self_param || first_arg_type == trait_impl_type - || item.fn_has_self_parameter) + || item.is_method()) { Some(receiver) } else { diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs index 93f77b8409f0..0e42a84ca32a 100644 --- a/compiler/rustc_hir_typeck/src/op.rs +++ b/compiler/rustc_hir_typeck/src/op.rs @@ -372,7 +372,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .associated_item_def_ids(def_id) .iter() .find(|item_def_id| { - self.tcx.associated_item(*item_def_id).name == sym::Output + self.tcx.associated_item(*item_def_id).name() == sym::Output }) .cloned() }); diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 9766ceda5696..e5e4fc7f8b77 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -9,11 +9,13 @@ use rustc_errors::{ Applicability, Diag, ErrorGuaranteed, MultiSpan, pluralize, struct_span_code_err, }; use rustc_hir::def::{CtorKind, DefKind, Res}; +use rustc_hir::def_id::DefId; use rustc_hir::pat_util::EnumerateAndAdjustIterator; use rustc_hir::{ self as hir, BindingMode, ByRef, ExprKind, HirId, LangItem, Mutability, Pat, PatExpr, PatExprKind, PatKind, expr_needs_parens, }; +use rustc_hir_analysis::autoderef::report_autoderef_recursion_limit_error; use rustc_infer::infer; use rustc_middle::traits::PatternOriginExpr; use rustc_middle::ty::{self, Ty, TypeVisitableExt}; @@ -29,11 +31,12 @@ use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode}; use tracing::{debug, instrument, trace}; use ty::VariantDef; +use ty::adjustment::{PatAdjust, PatAdjustment}; use super::report_unexpected_variant_res; use crate::expectation::Expectation; use crate::gather_locals::DeclOrigin; -use crate::{FnCtxt, LoweredTy, errors}; +use crate::{FnCtxt, errors}; const CANNOT_IMPLICITLY_DEREF_POINTER_TRAIT_OBJ: &str = "\ This error indicates that a pointer to a trait type cannot be implicitly dereferenced by a \ @@ -161,15 +164,35 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Mode for adjusting the expected type and binding mode. #[derive(Clone, Copy, Debug, PartialEq, Eq)] enum AdjustMode { - /// Peel off all immediate reference types. - Peel, - /// Reset binding mode to the initial mode. - /// Used for destructuring assignment, where we don't want any match ergonomics. - Reset, + /// Peel off all immediate reference types. If the `deref_patterns` feature is enabled, this + /// also peels smart pointer ADTs. + Peel { kind: PeelKind }, /// Pass on the input binding mode and expected type. Pass, } +/// Restrictions on what types to peel when adjusting the expected type and binding mode. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +enum PeelKind { + /// Only peel reference types. This is used for explicit `deref!(_)` patterns, which dereference + /// any number of `&`/`&mut` references, plus a single smart pointer. + ExplicitDerefPat, + /// Implicitly peel any number of references, and if `deref_patterns` is enabled, smart pointer + /// ADTs. In order to peel only as much as necessary for the pattern to match, the `until_adt` + /// field contains the ADT def that the pattern is a constructor for, if applicable, so that we + /// don't peel it. See [`ResolvedPat`] for more information. + Implicit { until_adt: Option }, +} + +impl AdjustMode { + const fn peel_until_adt(opt_adt_def: Option) -> AdjustMode { + AdjustMode::Peel { kind: PeelKind::Implicit { until_adt: opt_adt_def } } + } + const fn peel_all() -> AdjustMode { + AdjustMode::peel_until_adt(None) + } +} + /// `ref mut` bindings (explicit or match-ergonomics) are not allowed behind an `&` reference. /// Normally, the borrow checker enforces this, but for (currently experimental) match ergonomics, /// we track this when typing patterns for two purposes: @@ -245,6 +268,47 @@ enum InheritedRefMatchRule { }, } +/// When checking patterns containing paths, we need to know the path's resolution to determine +/// whether to apply match ergonomics and implicitly dereference the scrutinee. For instance, when +/// the `deref_patterns` feature is enabled and we're matching against a scrutinee of type +/// `Cow<'a, Option>`, we insert an implicit dereference to allow the pattern `Some(_)` to type, +/// but we must not dereference it when checking the pattern `Cow::Borrowed(_)`. +/// +/// `ResolvedPat` contains the information from resolution needed to determine match ergonomics +/// adjustments, and to finish checking the pattern once we know its adjusted type. +#[derive(Clone, Copy, Debug)] +struct ResolvedPat<'tcx> { + /// The type of the pattern, to be checked against the type of the scrutinee after peeling. This + /// is also used to avoid peeling the scrutinee's constructors (see the `Cow` example above). + ty: Ty<'tcx>, + kind: ResolvedPatKind<'tcx>, +} + +#[derive(Clone, Copy, Debug)] +enum ResolvedPatKind<'tcx> { + Path { res: Res, pat_res: Res, segments: &'tcx [hir::PathSegment<'tcx>] }, + Struct { variant: &'tcx VariantDef }, + TupleStruct { res: Res, variant: &'tcx VariantDef }, +} + +impl<'tcx> ResolvedPat<'tcx> { + fn adjust_mode(&self) -> AdjustMode { + if let ResolvedPatKind::Path { res, .. } = self.kind + && matches!(res, Res::Def(DefKind::Const | DefKind::AssocConst, _)) + { + // These constants can be of a reference type, e.g. `const X: &u8 = &0;`. + // Peeling the reference types too early will cause type checking failures. + // Although it would be possible to *also* peel the types of the constants too. + AdjustMode::Pass + } else { + // The remaining possible resolutions for path, struct, and tuple struct patterns are + // ADT constructors. As such, we may peel references freely, but we must not peel the + // ADT itself from the scrutinee if it's a smart pointer. + AdjustMode::peel_until_adt(self.ty.ty_adt_def().map(|adt| adt.did())) + } + } +} + impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Experimental pattern feature: after matching against a shared reference, do we limit the /// default binding mode in subpatterns to be `ref` when it would otherwise be `ref mut`? @@ -321,79 +385,35 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Conversely, inside this module, `check_pat_top` should never be used. #[instrument(level = "debug", skip(self, pat_info))] fn check_pat(&self, pat: &'tcx Pat<'tcx>, expected: Ty<'tcx>, pat_info: PatInfo<'tcx>) { - let PatInfo { binding_mode, max_ref_mutbl, top_info: ti, current_depth, .. } = pat_info; - - let path_res = match pat.kind { + // For patterns containing paths, we need the path's resolution to determine whether to + // implicitly dereference the scrutinee before matching. + let opt_path_res = match pat.kind { PatKind::Expr(PatExpr { kind: PatExprKind::Path(qpath), hir_id, span }) => { - Some(self.resolve_ty_and_res_fully_qualified_call(qpath, *hir_id, *span)) + Some(self.resolve_pat_path(*hir_id, *span, qpath)) } + PatKind::Struct(ref qpath, ..) => Some(self.resolve_pat_struct(pat, qpath)), + PatKind::TupleStruct(ref qpath, ..) => Some(self.resolve_pat_tuple_struct(pat, qpath)), _ => None, }; - let adjust_mode = self.calc_adjust_mode(pat, path_res.map(|(res, ..)| res)); - let (expected, binding_mode, max_ref_mutbl) = - self.calc_default_binding_mode(pat, expected, binding_mode, adjust_mode, max_ref_mutbl); - let pat_info = PatInfo { - binding_mode, - max_ref_mutbl, - top_info: ti, - decl_origin: pat_info.decl_origin, - current_depth: current_depth + 1, - }; - - let ty = match pat.kind { - PatKind::Wild | PatKind::Err(_) => expected, - // We allow any type here; we ensure that the type is uninhabited during match checking. - PatKind::Never => expected, - PatKind::Expr(PatExpr { kind: PatExprKind::Path(qpath), hir_id, span }) => { - let ty = self.check_pat_path( - *hir_id, - pat.hir_id, - *span, - qpath, - path_res.unwrap(), - expected, - &pat_info.top_info, - ); - self.write_ty(*hir_id, ty); - ty - } - PatKind::Expr(lt) => self.check_pat_lit(pat.span, lt, expected, &pat_info.top_info), - PatKind::Range(lhs, rhs, _) => { - self.check_pat_range(pat.span, lhs, rhs, expected, &pat_info.top_info) - } - PatKind::Binding(ba, var_id, ident, sub) => { - self.check_pat_ident(pat, ba, var_id, ident, sub, expected, pat_info) - } - PatKind::TupleStruct(ref qpath, subpats, ddpos) => { - self.check_pat_tuple_struct(pat, qpath, subpats, ddpos, expected, pat_info) - } - PatKind::Struct(ref qpath, fields, has_rest_pat) => { - self.check_pat_struct(pat, qpath, fields, has_rest_pat, expected, pat_info) - } - PatKind::Guard(pat, cond) => { - self.check_pat(pat, expected, pat_info); - self.check_expr_has_type_or_error(cond, self.tcx.types.bool, |_| {}); - expected - } - PatKind::Or(pats) => { - for pat in pats { - self.check_pat(pat, expected, pat_info); - } - expected - } - PatKind::Tuple(elements, ddpos) => { - self.check_pat_tuple(pat.span, elements, ddpos, expected, pat_info) - } - PatKind::Box(inner) => self.check_pat_box(pat.span, inner, expected, pat_info), - PatKind::Deref(inner) => self.check_pat_deref(pat.span, inner, expected, pat_info), - PatKind::Ref(inner, mutbl) => self.check_pat_ref(pat, inner, mutbl, expected, pat_info), - PatKind::Slice(before, slice, after) => { - self.check_pat_slice(pat.span, before, slice, after, expected, pat_info) - } - }; - + let adjust_mode = self.calc_adjust_mode(pat, opt_path_res); + let ty = self.check_pat_inner(pat, opt_path_res, adjust_mode, expected, pat_info); self.write_ty(pat.hir_id, ty); + // If we implicitly inserted overloaded dereferences before matching, check the pattern to + // see if the dereferenced types need `DerefMut` bounds. + if let Some(derefed_tys) = self.typeck_results.borrow().pat_adjustments().get(pat.hir_id) + && derefed_tys.iter().any(|adjust| adjust.kind == PatAdjust::OverloadedDeref) + { + self.register_deref_mut_bounds_if_needed( + pat.span, + pat, + derefed_tys.iter().filter_map(|adjust| match adjust.kind { + PatAdjust::OverloadedDeref => Some(adjust.source), + PatAdjust::BuiltinDeref => None, + }), + ); + } + // (note_1): In most of the cases where (note_1) is referenced // (literals and constants being the exception), we relate types // using strict equality, even though subtyping would be sufficient. @@ -437,62 +457,226 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // `regions-relate-bound-regions-on-closures-to-inference-variables.rs`, } - /// Compute the new expected type and default binding mode from the old ones - /// as well as the pattern form we are currently checking. - fn calc_default_binding_mode( + // Helper to avoid resolving the same path pattern several times. + fn check_pat_inner( &self, pat: &'tcx Pat<'tcx>, - expected: Ty<'tcx>, - def_br: ByRef, + opt_path_res: Option, ErrorGuaranteed>>, adjust_mode: AdjustMode, - max_ref_mutbl: MutblCap, - ) -> (Ty<'tcx>, ByRef, MutblCap) { + expected: Ty<'tcx>, + pat_info: PatInfo<'tcx>, + ) -> Ty<'tcx> { #[cfg(debug_assertions)] - if def_br == ByRef::Yes(Mutability::Mut) - && max_ref_mutbl != MutblCap::Mut + if pat_info.binding_mode == ByRef::Yes(Mutability::Mut) + && pat_info.max_ref_mutbl != MutblCap::Mut && self.downgrade_mut_inside_shared() { span_bug!(pat.span, "Pattern mutability cap violated!"); } - match adjust_mode { - AdjustMode::Pass => (expected, def_br, max_ref_mutbl), - AdjustMode::Reset => (expected, ByRef::No, MutblCap::Mut), - AdjustMode::Peel => self.peel_off_references(pat, expected, def_br, max_ref_mutbl), + + // Resolve type if needed. + let expected = if let AdjustMode::Peel { .. } = adjust_mode + && pat.default_binding_modes + { + self.try_structurally_resolve_type(pat.span, expected) + } else { + expected + }; + let old_pat_info = pat_info; + let pat_info = PatInfo { current_depth: old_pat_info.current_depth + 1, ..old_pat_info }; + + match pat.kind { + // Peel off a `&` or `&mut` from the scrutinee type. See the examples in + // `tests/ui/rfcs/rfc-2005-default-binding-mode`. + _ if let AdjustMode::Peel { .. } = adjust_mode + && pat.default_binding_modes + && let ty::Ref(_, inner_ty, inner_mutability) = *expected.kind() => + { + debug!("inspecting {:?}", expected); + + debug!("current discriminant is Ref, inserting implicit deref"); + // Preserve the reference type. We'll need it later during THIR lowering. + self.typeck_results + .borrow_mut() + .pat_adjustments_mut() + .entry(pat.hir_id) + .or_default() + .push(PatAdjustment { kind: PatAdjust::BuiltinDeref, source: expected }); + + let mut binding_mode = ByRef::Yes(match pat_info.binding_mode { + // If default binding mode is by value, make it `ref` or `ref mut` + // (depending on whether we observe `&` or `&mut`). + ByRef::No | + // When `ref mut`, stay a `ref mut` (on `&mut`) or downgrade to `ref` (on `&`). + ByRef::Yes(Mutability::Mut) => inner_mutability, + // Once a `ref`, always a `ref`. + // This is because a `& &mut` cannot mutate the underlying value. + ByRef::Yes(Mutability::Not) => Mutability::Not, + }); + + let mut max_ref_mutbl = pat_info.max_ref_mutbl; + if self.downgrade_mut_inside_shared() { + binding_mode = binding_mode.cap_ref_mutability(max_ref_mutbl.as_mutbl()); + } + if binding_mode == ByRef::Yes(Mutability::Not) { + max_ref_mutbl = MutblCap::Not; + } + debug!("default binding mode is now {:?}", binding_mode); + + // Use the old pat info to keep `current_depth` to its old value. + let new_pat_info = PatInfo { binding_mode, max_ref_mutbl, ..old_pat_info }; + // Recurse with the new expected type. + self.check_pat_inner(pat, opt_path_res, adjust_mode, inner_ty, new_pat_info) + } + // If `deref_patterns` is enabled, peel a smart pointer from the scrutinee type. See the + // examples in `tests/ui/pattern/deref_patterns/`. + _ if self.tcx.features().deref_patterns() + && let AdjustMode::Peel { kind: PeelKind::Implicit { until_adt } } = adjust_mode + && pat.default_binding_modes + // For simplicity, only apply overloaded derefs if `expected` is a known ADT. + // FIXME(deref_patterns): we'll get better diagnostics for users trying to + // implicitly deref generics if we allow them here, but primitives, tuples, and + // inference vars definitely should be stopped. Figure out what makes most sense. + && let ty::Adt(scrutinee_adt, _) = *expected.kind() + // Don't peel if the pattern type already matches the scrutinee. E.g., stop here if + // matching on a `Cow<'a, T>` scrutinee with a `Cow::Owned(_)` pattern. + && until_adt != Some(scrutinee_adt.did()) + // At this point, the pattern isn't able to match `expected` without peeling. Check + // that it implements `Deref` before assuming it's a smart pointer, to get a normal + // type error instead of a missing impl error if not. This only checks for `Deref`, + // not `DerefPure`: we require that too, but we want a trait error if it's missing. + && let Some(deref_trait) = self.tcx.lang_items().deref_trait() + && self + .type_implements_trait(deref_trait, [expected], self.param_env) + .may_apply() => + { + debug!("scrutinee ty {expected:?} is a smart pointer, inserting overloaded deref"); + // The scrutinee is a smart pointer; implicitly dereference it. This adds a + // requirement that `expected: DerefPure`. + let mut inner_ty = self.deref_pat_target(pat.span, expected); + // Once we've checked `pat`, we'll add a `DerefMut` bound if it contains any + // `ref mut` bindings. See `Self::register_deref_mut_bounds_if_needed`. + + let mut typeck_results = self.typeck_results.borrow_mut(); + let mut pat_adjustments_table = typeck_results.pat_adjustments_mut(); + let pat_adjustments = pat_adjustments_table.entry(pat.hir_id).or_default(); + // We may reach the recursion limit if a user matches on a type `T` satisfying + // `T: Deref`; error gracefully in this case. + // FIXME(deref_patterns): If `deref_patterns` stabilizes, it may make sense to move + // this check out of this branch. Alternatively, this loop could be implemented with + // autoderef and this check removed. For now though, don't break code compiling on + // stable with lots of `&`s and a low recursion limit, if anyone's done that. + if self.tcx.recursion_limit().value_within_limit(pat_adjustments.len()) { + // Preserve the smart pointer type for THIR lowering and closure upvar analysis. + pat_adjustments + .push(PatAdjustment { kind: PatAdjust::OverloadedDeref, source: expected }); + } else { + let guar = report_autoderef_recursion_limit_error(self.tcx, pat.span, expected); + inner_ty = Ty::new_error(self.tcx, guar); + } + drop(typeck_results); + + // Recurse, using the old pat info to keep `current_depth` to its old value. + // Peeling smart pointers does not update the default binding mode. + self.check_pat_inner(pat, opt_path_res, adjust_mode, inner_ty, old_pat_info) + } + PatKind::Missing | PatKind::Wild | PatKind::Err(_) => expected, + // We allow any type here; we ensure that the type is uninhabited during match checking. + PatKind::Never => expected, + PatKind::Expr(PatExpr { kind: PatExprKind::Path(_), hir_id, .. }) => { + let ty = match opt_path_res.unwrap() { + Ok(ref pr) => { + self.check_pat_path(pat.hir_id, pat.span, pr, expected, &pat_info.top_info) + } + Err(guar) => Ty::new_error(self.tcx, guar), + }; + self.write_ty(*hir_id, ty); + ty + } + PatKind::Expr(lt) => self.check_pat_lit(pat.span, lt, expected, &pat_info.top_info), + PatKind::Range(lhs, rhs, _) => { + self.check_pat_range(pat.span, lhs, rhs, expected, &pat_info.top_info) + } + PatKind::Binding(ba, var_id, ident, sub) => { + self.check_pat_ident(pat, ba, var_id, ident, sub, expected, pat_info) + } + PatKind::TupleStruct(ref qpath, subpats, ddpos) => match opt_path_res.unwrap() { + Ok(ResolvedPat { ty, kind: ResolvedPatKind::TupleStruct { res, variant } }) => self + .check_pat_tuple_struct( + pat, qpath, subpats, ddpos, res, ty, variant, expected, pat_info, + ), + Err(guar) => { + let ty_err = Ty::new_error(self.tcx, guar); + for subpat in subpats { + self.check_pat(subpat, ty_err, pat_info); + } + ty_err + } + Ok(pr) => span_bug!(pat.span, "tuple struct pattern resolved to {pr:?}"), + }, + PatKind::Struct(_, fields, has_rest_pat) => match opt_path_res.unwrap() { + Ok(ResolvedPat { ty, kind: ResolvedPatKind::Struct { variant } }) => self + .check_pat_struct(pat, fields, has_rest_pat, ty, variant, expected, pat_info), + Err(guar) => { + let ty_err = Ty::new_error(self.tcx, guar); + for field in fields { + self.check_pat(field.pat, ty_err, pat_info); + } + ty_err + } + Ok(pr) => span_bug!(pat.span, "struct pattern resolved to {pr:?}"), + }, + PatKind::Guard(pat, cond) => { + self.check_pat(pat, expected, pat_info); + self.check_expr_has_type_or_error(cond, self.tcx.types.bool, |_| {}); + expected + } + PatKind::Or(pats) => { + for pat in pats { + self.check_pat(pat, expected, pat_info); + } + expected + } + PatKind::Tuple(elements, ddpos) => { + self.check_pat_tuple(pat.span, elements, ddpos, expected, pat_info) + } + PatKind::Box(inner) => self.check_pat_box(pat.span, inner, expected, pat_info), + PatKind::Deref(inner) => self.check_pat_deref(pat.span, inner, expected, pat_info), + PatKind::Ref(inner, mutbl) => self.check_pat_ref(pat, inner, mutbl, expected, pat_info), + PatKind::Slice(before, slice, after) => { + self.check_pat_slice(pat.span, before, slice, after, expected, pat_info) + } } } /// How should the binding mode and expected type be adjusted? /// - /// When the pattern is a path pattern, `opt_path_res` must be `Some(res)`. - fn calc_adjust_mode(&self, pat: &'tcx Pat<'tcx>, opt_path_res: Option) -> AdjustMode { - // When we perform destructuring assignment, we disable default match bindings, which are - // unintuitive in this context. - if !pat.default_binding_modes { - return AdjustMode::Reset; - } + /// When the pattern contains a path, `opt_path_res` must be `Some(path_res)`. + fn calc_adjust_mode( + &self, + pat: &'tcx Pat<'tcx>, + opt_path_res: Option, ErrorGuaranteed>>, + ) -> AdjustMode { match &pat.kind { // Type checking these product-like types successfully always require // that the expected type be of those types and not reference types. + PatKind::Tuple(..) + | PatKind::Range(..) + | PatKind::Slice(..) => AdjustMode::peel_all(), + // When checking an explicit deref pattern, only peel reference types. + // FIXME(deref_patterns): If box patterns and deref patterns need to coexist, box + // patterns may want `PeelKind::Implicit`, stopping on encountering a box. + | PatKind::Box(_) + | PatKind::Deref(_) => AdjustMode::Peel { kind: PeelKind::ExplicitDerefPat }, + // A never pattern behaves somewhat like a literal or unit variant. + PatKind::Never => AdjustMode::peel_all(), + // For patterns with paths, how we peel the scrutinee depends on the path's resolution. PatKind::Struct(..) | PatKind::TupleStruct(..) - | PatKind::Tuple(..) - | PatKind::Box(_) - | PatKind::Deref(_) - | PatKind::Range(..) - | PatKind::Slice(..) => AdjustMode::Peel, - // A never pattern behaves somewhat like a literal or unit variant. - PatKind::Never => AdjustMode::Peel, - PatKind::Expr(PatExpr { kind: PatExprKind::Path(_), .. }) => match opt_path_res.unwrap() { - // These constants can be of a reference type, e.g. `const X: &u8 = &0;`. - // Peeling the reference types too early will cause type checking failures. - // Although it would be possible to *also* peel the types of the constants too. - Res::Def(DefKind::Const | DefKind::AssocConst, _) => AdjustMode::Pass, - // In the `ValueNS`, we have `SelfCtor(..) | Ctor(_, Const), _)` remaining which - // could successfully compile. The former being `Self` requires a unit struct. - // In either case, and unlike constants, the pattern itself cannot be - // a reference type wherefore peeling doesn't give up any expressiveness. - _ => AdjustMode::Peel, - }, + | PatKind::Expr(PatExpr { kind: PatExprKind::Path(_), .. }) => { + // If there was an error resolving the path, default to peeling everything. + opt_path_res.unwrap().map_or(AdjustMode::peel_all(), |pr| pr.adjust_mode()) + } // String and byte-string literals result in types `&str` and `&[u8]` respectively. // All other literals result in non-reference types. @@ -501,13 +685,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Call `resolve_vars_if_possible` here for inline const blocks. PatKind::Expr(lt) => match self.resolve_vars_if_possible(self.check_pat_expr_unadjusted(lt)).kind() { ty::Ref(..) => AdjustMode::Pass, - _ => AdjustMode::Peel, + _ => { + // Path patterns have already been handled, and inline const blocks currently + // aren't possible to write, so any handling for them would be untested. + if cfg!(debug_assertions) + && self.tcx.features().deref_patterns() + && !matches!(lt.kind, PatExprKind::Lit { .. }) + { + span_bug!(lt.span, "FIXME(deref_patterns): adjust mode unimplemented for {:?}", lt.kind); + } + AdjustMode::peel_all() + } }, // Ref patterns are complicated, we handle them in `check_pat_ref`. - PatKind::Ref(..) => AdjustMode::Pass, + PatKind::Ref(..) + // No need to do anything on a missing pattern. + | PatKind::Missing // A `_` pattern works with any expected type, so there's no need to do anything. - PatKind::Wild + | PatKind::Wild // A malformed pattern doesn't have an expected type, so let's just accept any type. | PatKind::Err(_) // Bindings also work with whatever the expected type is, @@ -524,64 +720,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - /// Peel off as many immediately nested `& mut?` from the expected type as possible - /// and return the new expected type and binding default binding mode. - /// The adjustments vector, if non-empty is stored in a table. - fn peel_off_references( - &self, - pat: &'tcx Pat<'tcx>, - expected: Ty<'tcx>, - mut def_br: ByRef, - mut max_ref_mutbl: MutblCap, - ) -> (Ty<'tcx>, ByRef, MutblCap) { - let mut expected = self.try_structurally_resolve_type(pat.span, expected); - // Peel off as many `&` or `&mut` from the scrutinee type as possible. For example, - // for `match &&&mut Some(5)` the loop runs three times, aborting when it reaches - // the `Some(5)` which is not of type Ref. - // - // For each ampersand peeled off, update the binding mode and push the original - // type into the adjustments vector. - // - // See the examples in `ui/match-defbm*.rs`. - let mut pat_adjustments = vec![]; - while let ty::Ref(_, inner_ty, inner_mutability) = *expected.kind() { - debug!("inspecting {:?}", expected); - - debug!("current discriminant is Ref, inserting implicit deref"); - // Preserve the reference type. We'll need it later during THIR lowering. - pat_adjustments.push(expected); - - expected = self.try_structurally_resolve_type(pat.span, inner_ty); - def_br = ByRef::Yes(match def_br { - // If default binding mode is by value, make it `ref` or `ref mut` - // (depending on whether we observe `&` or `&mut`). - ByRef::No | - // When `ref mut`, stay a `ref mut` (on `&mut`) or downgrade to `ref` (on `&`). - ByRef::Yes(Mutability::Mut) => inner_mutability, - // Once a `ref`, always a `ref`. - // This is because a `& &mut` cannot mutate the underlying value. - ByRef::Yes(Mutability::Not) => Mutability::Not, - }); - } - - if self.downgrade_mut_inside_shared() { - def_br = def_br.cap_ref_mutability(max_ref_mutbl.as_mutbl()); - } - if def_br == ByRef::Yes(Mutability::Not) { - max_ref_mutbl = MutblCap::Not; - } - - if !pat_adjustments.is_empty() { - debug!("default binding mode is now {:?}", def_br); - self.typeck_results - .borrow_mut() - .pat_adjustments_mut() - .insert(pat.hir_id, pat_adjustments); - } - - (expected, def_br, max_ref_mutbl) - } - fn check_pat_expr_unadjusted(&self, lt: &'tcx hir::PatExpr<'tcx>) -> Ty<'tcx> { let ty = match <.kind { rustc_hir::PatExprKind::Lit { lit, negated } => { @@ -1032,7 +1170,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | PatKind::Tuple(..) | PatKind::Slice(..) => "binding", - PatKind::Wild + PatKind::Missing + | PatKind::Wild | PatKind::Never | PatKind::Binding(..) | PatKind::Box(..) @@ -1139,27 +1278,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Ok(()) } - fn check_pat_struct( + fn resolve_pat_struct( &self, pat: &'tcx Pat<'tcx>, qpath: &hir::QPath<'tcx>, + ) -> Result, ErrorGuaranteed> { + // Resolve the path and check the definition for errors. + let (variant, pat_ty) = self.check_struct_path(qpath, pat.hir_id)?; + Ok(ResolvedPat { ty: pat_ty, kind: ResolvedPatKind::Struct { variant } }) + } + + fn check_pat_struct( + &self, + pat: &'tcx Pat<'tcx>, fields: &'tcx [hir::PatField<'tcx>], has_rest_pat: bool, + pat_ty: Ty<'tcx>, + variant: &'tcx VariantDef, expected: Ty<'tcx>, pat_info: PatInfo<'tcx>, ) -> Ty<'tcx> { - // Resolve the path and check the definition for errors. - let (variant, pat_ty) = match self.check_struct_path(qpath, pat.hir_id) { - Ok(data) => data, - Err(guar) => { - let err = Ty::new_error(self.tcx, guar); - for field in fields { - self.check_pat(field.pat, err, pat_info); - } - return err; - } - }; - // Type-check the path. let _ = self.demand_eqtype_pat(pat.span, expected, pat_ty, &pat_info.top_info); @@ -1170,31 +1308,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - fn check_pat_path( + fn resolve_pat_path( &self, path_id: HirId, - pat_id_for_diag: HirId, span: Span, - qpath: &hir::QPath<'_>, - path_resolution: (Res, Option>, &'tcx [hir::PathSegment<'tcx>]), - expected: Ty<'tcx>, - ti: &TopInfo<'tcx>, - ) -> Ty<'tcx> { + qpath: &'tcx hir::QPath<'_>, + ) -> Result, ErrorGuaranteed> { let tcx = self.tcx; - // We have already resolved the path. - let (res, opt_ty, segments) = path_resolution; + let (res, opt_ty, segments) = + self.resolve_ty_and_res_fully_qualified_call(qpath, path_id, span); match res { Res::Err => { let e = self.dcx().span_delayed_bug(qpath.span(), "`Res::Err` but no error emitted"); self.set_tainted_by_errors(e); - return Ty::new_error(tcx, e); + return Err(e); } Res::Def(DefKind::AssocFn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::Variant, _) => { let expected = "unit struct, unit variant or constant"; let e = report_unexpected_variant_res(tcx, res, None, qpath, span, E0533, expected); - return Ty::new_error(tcx, e); + return Err(e); } Res::SelfCtor(def_id) => { if let ty::Adt(adt_def, _) = *tcx.type_of(def_id).skip_binder().kind() @@ -1212,7 +1346,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { E0533, "unit struct", ); - return Ty::new_error(tcx, e); + return Err(e); } } Res::Def( @@ -1225,15 +1359,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => bug!("unexpected pattern resolution: {:?}", res), } - // Type-check the path. + // Find the type of the path pattern, for later checking. let (pat_ty, pat_res) = self.instantiate_value_path(segments, opt_ty, res, span, span, path_id); + Ok(ResolvedPat { ty: pat_ty, kind: ResolvedPatKind::Path { res, pat_res, segments } }) + } + + fn check_pat_path( + &self, + pat_id_for_diag: HirId, + span: Span, + resolved: &ResolvedPat<'tcx>, + expected: Ty<'tcx>, + ti: &TopInfo<'tcx>, + ) -> Ty<'tcx> { if let Err(err) = - self.demand_suptype_with_origin(&self.pattern_cause(ti, span), expected, pat_ty) + self.demand_suptype_with_origin(&self.pattern_cause(ti, span), expected, resolved.ty) { - self.emit_bad_pat_path(err, pat_id_for_diag, span, res, pat_res, pat_ty, segments); + self.emit_bad_pat_path(err, pat_id_for_diag, span, resolved); } - pat_ty + resolved.ty } fn maybe_suggest_range_literal( @@ -1276,11 +1421,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { mut e: Diag<'_>, hir_id: HirId, pat_span: Span, - res: Res, - pat_res: Res, - pat_ty: Ty<'tcx>, - segments: &'tcx [hir::PathSegment<'tcx>], + resolved_pat: &ResolvedPat<'tcx>, ) { + let ResolvedPatKind::Path { res, pat_res, segments } = resolved_pat.kind else { + span_bug!(pat_span, "unexpected resolution for path pattern: {resolved_pat:?}"); + }; + if let Some(span) = self.tcx.hir_res_span(pat_res) { e.span_label(span, format!("{} defined here", res.descr())); if let [hir::PathSegment { ident, .. }] = &*segments { @@ -1303,7 +1449,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } _ => { - let (type_def_id, item_def_id) = match pat_ty.kind() { + let (type_def_id, item_def_id) = match resolved_pat.ty.kind() { ty::Adt(def, _) => match res { Res::Def(DefKind::Const, def_id) => (Some(def.did()), Some(def_id)), _ => (None, None), @@ -1343,12 +1489,61 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { e.emit(); } + fn resolve_pat_tuple_struct( + &self, + pat: &'tcx Pat<'tcx>, + qpath: &'tcx hir::QPath<'tcx>, + ) -> Result, ErrorGuaranteed> { + let tcx = self.tcx; + let report_unexpected_res = |res: Res| { + let expected = "tuple struct or tuple variant"; + let e = report_unexpected_variant_res(tcx, res, None, qpath, pat.span, E0164, expected); + Err(e) + }; + + // Resolve the path and check the definition for errors. + let (res, opt_ty, segments) = + self.resolve_ty_and_res_fully_qualified_call(qpath, pat.hir_id, pat.span); + if res == Res::Err { + let e = self.dcx().span_delayed_bug(pat.span, "`Res::Err` but no error emitted"); + self.set_tainted_by_errors(e); + return Err(e); + } + + // Type-check the path. + let (pat_ty, res) = + self.instantiate_value_path(segments, opt_ty, res, pat.span, pat.span, pat.hir_id); + if !pat_ty.is_fn() { + return report_unexpected_res(res); + } + + let variant = match res { + Res::Err => { + self.dcx().span_bug(pat.span, "`Res::Err` but no error emitted"); + } + Res::Def(DefKind::AssocConst | DefKind::AssocFn, _) => { + return report_unexpected_res(res); + } + Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) => tcx.expect_variant_res(res), + _ => bug!("unexpected pattern resolution: {:?}", res), + }; + + // Replace constructor type with constructed type for tuple struct patterns. + let pat_ty = pat_ty.fn_sig(tcx).output(); + let pat_ty = pat_ty.no_bound_vars().expect("expected fn type"); + + Ok(ResolvedPat { ty: pat_ty, kind: ResolvedPatKind::TupleStruct { res, variant } }) + } + fn check_pat_tuple_struct( &self, pat: &'tcx Pat<'tcx>, qpath: &'tcx hir::QPath<'tcx>, subpats: &'tcx [Pat<'tcx>], ddpos: hir::DotDotPos, + res: Res, + pat_ty: Ty<'tcx>, + variant: &'tcx VariantDef, expected: Ty<'tcx>, pat_info: PatInfo<'tcx>, ) -> Ty<'tcx> { @@ -1358,46 +1553,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.check_pat(pat, Ty::new_error(tcx, e), pat_info); } }; - let report_unexpected_res = |res: Res| { - let expected = "tuple struct or tuple variant"; - let e = report_unexpected_variant_res(tcx, res, None, qpath, pat.span, E0164, expected); - on_error(e); - e - }; - - // Resolve the path and check the definition for errors. - let (res, opt_ty, segments) = - self.resolve_ty_and_res_fully_qualified_call(qpath, pat.hir_id, pat.span); - if res == Res::Err { - let e = self.dcx().span_delayed_bug(pat.span, "`Res::Err` but no error emitted"); - self.set_tainted_by_errors(e); - on_error(e); - return Ty::new_error(tcx, e); - } - - // Type-check the path. - let (pat_ty, res) = - self.instantiate_value_path(segments, opt_ty, res, pat.span, pat.span, pat.hir_id); - if !pat_ty.is_fn() { - let e = report_unexpected_res(res); - return Ty::new_error(tcx, e); - } - - let variant = match res { - Res::Err => { - self.dcx().span_bug(pat.span, "`Res::Err` but no error emitted"); - } - Res::Def(DefKind::AssocConst | DefKind::AssocFn, _) => { - let e = report_unexpected_res(res); - return Ty::new_error(tcx, e); - } - Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) => tcx.expect_variant_res(res), - _ => bug!("unexpected pattern resolution: {:?}", res), - }; - - // Replace constructor type with constructed type for tuple struct patterns. - let pat_ty = pat_ty.fn_sig(tcx).output(); - let pat_ty = pat_ty.no_bound_vars().expect("expected fn type"); // Type-check the tuple struct pattern against the expected type. let diag = self.demand_eqtype_pat_diag(pat.span, expected, pat_ty, &pat_info.top_info); @@ -2282,36 +2437,49 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected: Ty<'tcx>, pat_info: PatInfo<'tcx>, ) -> Ty<'tcx> { - let tcx = self.tcx; + let target_ty = self.deref_pat_target(span, expected); + self.check_pat(inner, target_ty, pat_info); + self.register_deref_mut_bounds_if_needed(span, inner, [expected]); + expected + } + + fn deref_pat_target(&self, span: Span, source_ty: Ty<'tcx>) -> Ty<'tcx> { // Register a `DerefPure` bound, which is required by all `deref!()` pats. + let tcx = self.tcx; self.register_bound( - expected, + source_ty, tcx.require_lang_item(hir::LangItem::DerefPure, Some(span)), self.misc(span), ); - // ::Target - let ty = Ty::new_projection( + // The expected type for the deref pat's inner pattern is `::Target`. + let target_ty = Ty::new_projection( tcx, tcx.require_lang_item(hir::LangItem::DerefTarget, Some(span)), - [expected], + [source_ty], ); - let ty = self.normalize(span, ty); - let ty = self.try_structurally_resolve_type(span, ty); - self.check_pat(inner, ty, pat_info); + let target_ty = self.normalize(span, target_ty); + self.try_structurally_resolve_type(span, target_ty) + } - // Check if the pattern has any `ref mut` bindings, which would require - // `DerefMut` to be emitted in MIR building instead of just `Deref`. - // We do this *after* checking the inner pattern, since we want to make - // sure to apply any match-ergonomics adjustments. + /// Check if the interior of a deref pattern (either explicit or implicit) has any `ref mut` + /// bindings, which would require `DerefMut` to be emitted in MIR building instead of just + /// `Deref`. We do this *after* checking the inner pattern, since we want to make sure to + /// account for `ref mut` binding modes inherited from implicitly dereferencing `&mut` refs. + fn register_deref_mut_bounds_if_needed( + &self, + span: Span, + inner: &'tcx Pat<'tcx>, + derefed_tys: impl IntoIterator>, + ) { if self.typeck_results.borrow().pat_has_ref_mut_binding(inner) { - self.register_bound( - expected, - tcx.require_lang_item(hir::LangItem::DerefMut, Some(span)), - self.misc(span), - ); + for mutably_derefed_ty in derefed_tys { + self.register_bound( + mutably_derefed_ty, + self.tcx.require_lang_item(hir::LangItem::DerefMut, Some(span)), + self.misc(span), + ); + } } - - expected } // Precondition: Pat is Ref(inner) diff --git a/compiler/rustc_incremental/messages.ftl b/compiler/rustc_incremental/messages.ftl index 2a65101d360d..bbc1fab05dfe 100644 --- a/compiler/rustc_incremental/messages.ftl +++ b/compiler/rustc_incremental/messages.ftl @@ -93,7 +93,7 @@ incremental_undefined_clean_dirty_assertions = incremental_undefined_clean_dirty_assertions_item = clean/dirty auto-assertions not yet defined for Node::Item.node={$kind} -incremental_unknown_item = unknown item `{$name}` +incremental_unknown_rustc_clean_argument = unknown `rustc_clean` argument incremental_unrecognized_depnode = unrecognized `DepNode` variant: {$name} diff --git a/compiler/rustc_incremental/src/errors.rs b/compiler/rustc_incremental/src/errors.rs index b4a207386dc4..dbc72d085be9 100644 --- a/compiler/rustc_incremental/src/errors.rs +++ b/compiler/rustc_incremental/src/errors.rs @@ -107,11 +107,10 @@ pub(crate) struct NotLoaded<'a> { } #[derive(Diagnostic)] -#[diag(incremental_unknown_item)] -pub(crate) struct UnknownItem { +#[diag(incremental_unknown_rustc_clean_argument)] +pub(crate) struct UnknownRustcCleanArgument { #[primary_span] pub span: Span, - pub name: Symbol, } #[derive(Diagnostic)] diff --git a/compiler/rustc_incremental/src/lib.rs b/compiler/rustc_incremental/src/lib.rs index dabfb6a90cad..299ee4876389 100644 --- a/compiler/rustc_incremental/src/lib.rs +++ b/compiler/rustc_incremental/src/lib.rs @@ -2,7 +2,6 @@ // tidy-alphabetical-start #![allow(internal_features)] -#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![deny(missing_docs)] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] diff --git a/compiler/rustc_incremental/src/persist/dirty_clean.rs b/compiler/rustc_incremental/src/persist/dirty_clean.rs index d40a0d514f6f..64166255fa48 100644 --- a/compiler/rustc_incremental/src/persist/dirty_clean.rs +++ b/compiler/rustc_incremental/src/persist/dirty_clean.rs @@ -405,8 +405,7 @@ fn check_config(tcx: TyCtxt<'_>, attr: &Attribute) -> bool { debug!("check_config: searching for cfg {:?}", value); cfg = Some(config.contains(&(value, None))); } else if !(item.has_name(EXCEPT) || item.has_name(LOADED_FROM_DISK)) { - tcx.dcx() - .emit_err(errors::UnknownItem { span: attr.span(), name: item.name_or_empty() }); + tcx.dcx().emit_err(errors::UnknownRustcCleanArgument { span: item.span() }); } } diff --git a/compiler/rustc_incremental/src/persist/fs.rs b/compiler/rustc_incremental/src/persist/fs.rs index 76a1ff3cf382..f0d24d27e85a 100644 --- a/compiler/rustc_incremental/src/persist/fs.rs +++ b/compiler/rustc_incremental/src/persist/fs.rs @@ -290,7 +290,7 @@ pub(crate) fn prepare_session_directory(sess: &Session, crate_name: Symbol) { // Try to remove the session directory we just allocated. We don't // know if there's any garbage in it from the failed copy action. - if let Err(err) = safe_remove_dir_all(&session_dir) { + if let Err(err) = std_fs::remove_dir_all(&session_dir) { sess.dcx().emit_warn(errors::DeletePartial { path: &session_dir, err }); } @@ -324,7 +324,7 @@ pub fn finalize_session_directory(sess: &Session, svh: Option) { incr_comp_session_dir.display() ); - if let Err(err) = safe_remove_dir_all(&*incr_comp_session_dir) { + if let Err(err) = std_fs::remove_dir_all(&*incr_comp_session_dir) { sess.dcx().emit_warn(errors::DeleteFull { path: &incr_comp_session_dir, err }); } @@ -715,7 +715,7 @@ pub(crate) fn garbage_collect_session_directories(sess: &Session) -> io::Result< for directory_name in session_directories { if !lock_file_to_session_dir.items().any(|(_, dir)| *dir == directory_name) { let path = crate_directory.join(directory_name); - if let Err(err) = safe_remove_dir_all(&path) { + if let Err(err) = std_fs::remove_dir_all(&path) { sess.dcx().emit_warn(errors::InvalidGcFailed { path: &path, err }); } } @@ -821,7 +821,7 @@ pub(crate) fn garbage_collect_session_directories(sess: &Session) -> io::Result< all_except_most_recent(deletion_candidates).into_items().all(|(path, lock)| { debug!("garbage_collect_session_directories() - deleting `{}`", path.display()); - if let Err(err) = safe_remove_dir_all(&path) { + if let Err(err) = std_fs::remove_dir_all(&path) { sess.dcx().emit_warn(errors::FinalizedGcFailed { path: &path, err }); } else { delete_session_dir_lock_file(sess, &lock_file_path(&path)); @@ -839,7 +839,7 @@ pub(crate) fn garbage_collect_session_directories(sess: &Session) -> io::Result< fn delete_old(sess: &Session, path: &Path) { debug!("garbage_collect_session_directories() - deleting `{}`", path.display()); - if let Err(err) = safe_remove_dir_all(path) { + if let Err(err) = std_fs::remove_dir_all(path) { sess.dcx().emit_warn(errors::SessionGcFailed { path, err }); } else { delete_session_dir_lock_file(sess, &lock_file_path(path)); @@ -862,30 +862,8 @@ fn all_except_most_recent( } } -/// Since paths of artifacts within session directories can get quite long, we -/// need to support deleting files with very long paths. The regular -/// WinApi functions only support paths up to 260 characters, however. In order -/// to circumvent this limitation, we canonicalize the path of the directory -/// before passing it to std::fs::remove_dir_all(). This will convert the path -/// into the '\\?\' format, which supports much longer paths. -fn safe_remove_dir_all(p: &Path) -> io::Result<()> { - let canonicalized = match try_canonicalize(p) { - Ok(canonicalized) => canonicalized, - Err(err) if err.kind() == io::ErrorKind::NotFound => return Ok(()), - Err(err) => return Err(err), - }; - - std_fs::remove_dir_all(canonicalized) -} - fn safe_remove_file(p: &Path) -> io::Result<()> { - let canonicalized = match try_canonicalize(p) { - Ok(canonicalized) => canonicalized, - Err(err) if err.kind() == io::ErrorKind::NotFound => return Ok(()), - Err(err) => return Err(err), - }; - - match std_fs::remove_file(canonicalized) { + match std_fs::remove_file(p) { Err(err) if err.kind() == io::ErrorKind::NotFound => Ok(()), result => result, } diff --git a/compiler/rustc_index/src/slice.rs b/compiler/rustc_index/src/slice.rs index 67ac805c2bfe..d2702bdb0571 100644 --- a/compiler/rustc_index/src/slice.rs +++ b/compiler/rustc_index/src/slice.rs @@ -1,6 +1,6 @@ use std::fmt; use std::marker::PhantomData; -use std::ops::{Index, IndexMut}; +use std::ops::{Index, IndexMut, RangeBounds}; use std::slice::GetDisjointMutError::*; use std::slice::{self, SliceIndex}; @@ -104,6 +104,17 @@ impl IndexSlice { self.raw.swap(a.index(), b.index()) } + #[inline] + pub fn copy_within( + &mut self, + src: impl IntoSliceIdx>, + dest: I, + ) where + T: Copy, + { + self.raw.copy_within(src.into_slice_idx(), dest.index()); + } + #[inline] pub fn get>( &self, diff --git a/compiler/rustc_index_macros/src/newtype.rs b/compiler/rustc_index_macros/src/newtype.rs index f0b58eabbff9..eedbe630cf2c 100644 --- a/compiler/rustc_index_macros/src/newtype.rs +++ b/compiler/rustc_index_macros/src/newtype.rs @@ -257,6 +257,13 @@ impl Parse for Newtype { } } + impl std::ops::AddAssign for #name { + #[inline] + fn add_assign(&mut self, other: usize) { + *self = *self + other; + } + } + impl rustc_index::Idx for #name { #[inline] fn new(value: usize) -> Self { diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs index 307110d9fbc2..a1a0926cd818 100644 --- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs +++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs @@ -159,7 +159,7 @@ impl CanonicalizeMode for CanonicalizeQueryResponse { ) -> ty::Region<'tcx> { let infcx = canonicalizer.infcx.unwrap(); - if let ty::ReVar(vid) = *r { + if let ty::ReVar(vid) = r.kind() { r = infcx .inner .borrow_mut() @@ -171,7 +171,7 @@ impl CanonicalizeMode for CanonicalizeQueryResponse { ); }; - match *r { + match r.kind() { ty::ReLateParam(_) | ty::ReErased | ty::ReStatic | ty::ReEarlyParam(..) => r, ty::RePlaceholder(placeholder) => canonicalizer.canonical_var_for_region( @@ -227,7 +227,7 @@ impl CanonicalizeMode for CanonicalizeUserTypeAnnotation { canonicalizer: &mut Canonicalizer<'_, 'tcx>, r: ty::Region<'tcx>, ) -> ty::Region<'tcx> { - match *r { + match r.kind() { ty::ReEarlyParam(_) | ty::ReLateParam(_) | ty::ReErased @@ -321,7 +321,7 @@ impl<'cx, 'tcx> TypeFolder> for Canonicalizer<'cx, 'tcx> { } fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { - match *r { + match r.kind() { ty::ReBound(index, ..) => { if index >= self.binder_index { bug!("escaping late-bound region during canonicalization"); diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index d53f631cc07a..5220071c5005 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -432,7 +432,7 @@ impl<'tcx> InferCtxt<'tcx> { } GenericArgKind::Lifetime(result_value) => { // e.g., here `result_value` might be `'?1` in the example above... - if let ty::ReBound(debruijn, br) = *result_value { + if let ty::ReBound(debruijn, br) = result_value.kind() { // ... in which case we would set `canonical_vars[0]` to `Some('static)`. // We only allow a `ty::INNERMOST` index in generic parameters. diff --git a/compiler/rustc_infer/src/infer/freshen.rs b/compiler/rustc_infer/src/infer/freshen.rs index f2bb66ff7368..cae674165f0e 100644 --- a/compiler/rustc_infer/src/infer/freshen.rs +++ b/compiler/rustc_infer/src/infer/freshen.rs @@ -109,7 +109,7 @@ impl<'a, 'tcx> TypeFolder> for TypeFreshener<'a, 'tcx> { } fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { - match *r { + match r.kind() { ty::ReBound(..) => { // leave bound regions alone r 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 91595de97f7d..e3522137d838 100644 --- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs +++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs @@ -218,7 +218,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { true } VarValue::Value(cur_region) => { - match *cur_region { + match cur_region.kind() { // If this empty region is from a universe that can name the // placeholder universe, then the LUB is the Placeholder region // (which is the cur_region). Otherwise, the LUB is the Static @@ -310,7 +310,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { match *b_data { VarValue::Empty(empty_ui) => { - let lub = match *a_region { + let lub = match a_region.kind() { RePlaceholder(placeholder) => { // If this empty region is from a universe that can // name the placeholder, then the placeholder is @@ -350,7 +350,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { // tighter bound than `'static`. // // (This might e.g. arise from being asked to prove `for<'a> { 'b: 'a }`.) - if let ty::RePlaceholder(p) = *lub + if let ty::RePlaceholder(p) = lub.kind() && b_universe.cannot_name(p.universe) { lub = self.tcx().lifetimes.re_static; @@ -377,7 +377,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { a_ui.min(b_ui) == b_ui } (VarValue::Value(a), VarValue::Empty(_)) => { - match *a { + match a.kind() { // this is always on an error path, // so it doesn't really matter if it's shorter or longer than an empty region ReError(_) => false, @@ -410,7 +410,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { } } (VarValue::Empty(a_ui), VarValue::Value(b)) => { - match *b { + match b.kind() { // this is always on an error path, // so it doesn't really matter if it's shorter or longer than an empty region ReError(_) => false, @@ -479,7 +479,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { /// term "concrete regions"). #[instrument(level = "trace", skip(self), ret)] fn lub_concrete_regions(&self, a: Region<'tcx>, b: Region<'tcx>) -> Region<'tcx> { - match (*a, *b) { + match (a.kind(), b.kind()) { (ReBound(..), _) | (_, ReBound(..)) | (ReErased, _) | (_, ReErased) => { bug!("cannot relate region: LUB({:?}, {:?})", a, b); } @@ -725,7 +725,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { // SubSupConflict(ReLateParam, ReLateParam) when reporting error, and so // the user will more likely get a specific suggestion. fn region_order_key(x: &RegionAndOrigin<'_>) -> u8 { - match *x.region { + match x.region.kind() { ReEarlyParam(_) => 0, ReLateParam(_) => 1, _ => 2, @@ -737,7 +737,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { let node_universe = self.var_infos[node_idx].universe; for lower_bound in &lower_bounds { - let effective_lower_bound = if let ty::RePlaceholder(p) = *lower_bound.region { + let effective_lower_bound = if let ty::RePlaceholder(p) = lower_bound.region.kind() { if node_universe.cannot_name(p.universe) { self.tcx().lifetimes.re_static } else { @@ -785,7 +785,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { .expect("lower_vid_bounds should at least include `node_idx`"); for upper_bound in &upper_bounds { - if let ty::RePlaceholder(p) = *upper_bound.region { + if let ty::RePlaceholder(p) = upper_bound.region.kind() { if min_universe.cannot_name(p.universe) { let origin = self.var_infos[node_idx].origin; errors.push(RegionResolutionError::UpperBoundUniverseConflict( @@ -913,7 +913,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { generic_ty: Ty<'tcx>, min: ty::Region<'tcx>, ) -> bool { - if let ty::ReError(_) = *min { + if let ty::ReError(_) = min.kind() { return true; } @@ -931,18 +931,18 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { } VerifyBound::OutlivedBy(r) => { - let a = match *min { + let a = match min.kind() { ty::ReVar(rid) => var_values.values[rid], _ => VarValue::Value(min), }; - let b = match **r { + let b = match r.kind() { ty::ReVar(rid) => var_values.values[rid], _ => VarValue::Value(*r), }; self.sub_region_values(a, b) } - VerifyBound::IsEmpty => match *min { + VerifyBound::IsEmpty => match min.kind() { ty::ReVar(rid) => match var_values.values[rid] { VarValue::ErrorValue => false, VarValue::Empty(_) => true, @@ -989,7 +989,7 @@ impl<'tcx> LexicalRegionResolutions<'tcx> { tcx: TyCtxt<'tcx>, r: ty::Region<'tcx>, ) -> ty::Region<'tcx> { - let result = match *r { + let result = match r.kind() { ty::ReVar(rid) => match self.values[rid] { VarValue::Empty(_) => r, VarValue::Value(r) => r, diff --git a/compiler/rustc_infer/src/infer/outlives/env.rs b/compiler/rustc_infer/src/infer/outlives/env.rs index e924c974a02c..cb5a33c5c972 100644 --- a/compiler/rustc_infer/src/infer/outlives/env.rs +++ b/compiler/rustc_infer/src/infer/outlives/env.rs @@ -69,7 +69,7 @@ impl<'tcx> OutlivesEnvironment<'tcx> { region_bound_pairs .insert(ty::OutlivesPredicate(GenericKind::Alias(alias_b), r_a)); } - OutlivesBound::RegionSubRegion(r_a, r_b) => match (*r_a, *r_b) { + OutlivesBound::RegionSubRegion(r_a, r_b) => match (r_a.kind(), r_b.kind()) { ( ty::ReStatic | ty::ReEarlyParam(_) | ty::ReLateParam(_), ty::ReStatic | ty::ReEarlyParam(_) | ty::ReLateParam(_), diff --git a/compiler/rustc_infer/src/infer/outlives/for_liveness.rs b/compiler/rustc_infer/src/infer/outlives/for_liveness.rs index 379410641fe5..c44d9723f29d 100644 --- a/compiler/rustc_infer/src/infer/outlives/for_liveness.rs +++ b/compiler/rustc_infer/src/infer/outlives/for_liveness.rs @@ -29,7 +29,7 @@ where } fn visit_region(&mut self, r: ty::Region<'tcx>) { - match *r { + match r.kind() { // ignore bound regions, keep visiting ty::ReBound(_, _) => {} _ => (self.op)(r), diff --git a/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs b/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs index 3cfc58dea05b..e332b6d0447a 100644 --- a/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs +++ b/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs @@ -155,7 +155,7 @@ impl<'a, 'tcx> LeakCheck<'a, 'tcx> { self.scc_universes[scc].take_min(universe, *region); // Detect those SCCs that directly contain a placeholder - if let ty::RePlaceholder(placeholder) = **region { + if let ty::RePlaceholder(placeholder) = region.kind() { if self.outer_universe.cannot_name(placeholder.universe) { // Update `scc_placeholders` to account for the fact that `P: S` must hold. match self.scc_placeholders[scc] { diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs index 57555db37abd..40e2e654b2ea 100644 --- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs +++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs @@ -463,7 +463,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { // cannot add constraints once regions are resolved debug!("origin = {:#?}", origin); - match (*sub, *sup) { + match (sub.kind(), sup.kind()) { (ReBound(..), _) | (_, ReBound(..)) => { span_bug!(origin.span(), "cannot relate bound region: {:?} <= {:?}", sub, sup); } @@ -595,7 +595,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { } pub fn universe(&mut self, region: Region<'tcx>) -> ty::UniverseIndex { - match *region { + match region.kind() { ty::ReStatic | ty::ReErased | ty::ReLateParam(..) @@ -618,9 +618,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { RegionVid::from(value_count)..RegionVid::from(self.storage.unification_table.len()); ( range.clone(), - (range.start.index()..range.end.index()) - .map(|index| self.storage.var_infos[ty::RegionVid::from(index)].origin) - .collect(), + (range.start..range.end).map(|index| self.storage.var_infos[index].origin).collect(), ) } diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs index e16212955ffe..b0ccd35e8f0f 100644 --- a/compiler/rustc_infer/src/infer/relate/generalize.rs +++ b/compiler/rustc_infer/src/infer/relate/generalize.rs @@ -571,7 +571,7 @@ impl<'tcx> TypeRelation> for Generalizer<'_, 'tcx> { ) -> RelateResult<'tcx, ty::Region<'tcx>> { assert_eq!(r, r2); // we are misusing TypeRelation here; both LHS and RHS ought to be == - match *r { + match r.kind() { // Never make variables for regions bound within the type itself, // nor for erased regions. ty::ReBound(..) | ty::ReErased => { diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs index 4a99c2209755..245f1a4ac5ed 100644 --- a/compiler/rustc_infer/src/infer/resolve.rs +++ b/compiler/rustc_infer/src/infer/resolve.rs @@ -89,7 +89,7 @@ impl<'a, 'tcx> TypeFolder> for OpportunisticRegionResolver<'a, 'tcx } fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { - match *r { + match r.kind() { ty::ReVar(vid) => self .infcx .inner @@ -153,7 +153,7 @@ impl<'a, 'tcx> FallibleTypeFolder> for FullTypeResolver<'a, 'tcx> { } fn try_fold_region(&mut self, r: ty::Region<'tcx>) -> Result, Self::Error> { - match *r { + match r.kind() { ty::ReVar(_) => Ok(self .infcx .lexical_region_resolutions diff --git a/compiler/rustc_infer/src/infer/snapshot/fudge.rs b/compiler/rustc_infer/src/infer/snapshot/fudge.rs index b5d3c26b05e0..39c8c40ea7d8 100644 --- a/compiler/rustc_infer/src/infer/snapshot/fudge.rs +++ b/compiler/rustc_infer/src/infer/snapshot/fudge.rs @@ -30,11 +30,12 @@ fn const_vars_since_snapshot<'tcx>( snapshot_var_len: usize, ) -> (Range, Vec) { let range = vars_since_snapshot(table, snapshot_var_len); + let range = range.start.vid..range.end.vid; ( - range.start.vid..range.end.vid, - (range.start.index()..range.end.index()) - .map(|index| match table.probe_value(ConstVid::from_u32(index)) { + range.clone(), + range + .map(|index| match table.probe_value(index) { ConstVariableValue::Known { value: _ } => { ConstVariableOrigin { param_def_id: None, span: rustc_span::DUMMY_SP } } diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs index b537750f1b51..6d5ad96e31c9 100644 --- a/compiler/rustc_infer/src/traits/mod.rs +++ b/compiler/rustc_infer/src/traits/mod.rs @@ -12,6 +12,7 @@ use std::hash::{Hash, Hasher}; use hir::def_id::LocalDefId; use rustc_hir as hir; +use rustc_macros::{TypeFoldable, TypeVisitable}; use rustc_middle::traits::query::NoSolution; use rustc_middle::traits::solve::Certainty; pub use rustc_middle::traits::*; @@ -35,9 +36,11 @@ use crate::infer::InferCtxt; /// either identifying an `impl` (e.g., `impl Eq for i32`) that /// satisfies the obligation, or else finding a bound that is in /// scope. The eventual result is usually a `Selection` (defined below). -#[derive(Clone)] +#[derive(Clone, TypeFoldable, TypeVisitable)] pub struct Obligation<'tcx, T> { /// The reason we have to prove this thing. + #[type_foldable(identity)] + #[type_visitable(ignore)] pub cause: ObligationCause<'tcx>, /// The environment in which we should prove this thing. @@ -51,6 +54,8 @@ pub struct Obligation<'tcx, T> { /// If this goes over a certain threshold, we abort compilation -- /// in such cases, we can not say whether or not the predicate /// holds for certain. Stupid halting problem; such a drag. + #[type_foldable(identity)] + #[type_visitable(ignore)] pub recursion_depth: usize, } diff --git a/compiler/rustc_infer/src/traits/structural_impls.rs b/compiler/rustc_infer/src/traits/structural_impls.rs index 4335073d9bc6..03661ebf7ec5 100644 --- a/compiler/rustc_infer/src/traits/structural_impls.rs +++ b/compiler/rustc_infer/src/traits/structural_impls.rs @@ -1,8 +1,6 @@ use std::fmt; -use rustc_middle::ty::{ - self, FallibleTypeFolder, TyCtxt, TypeFoldable, TypeVisitable, TypeVisitor, try_visit, -}; +use rustc_middle::ty; use crate::traits; use crate::traits::project::Normalized; @@ -34,31 +32,3 @@ impl<'tcx> fmt::Debug for traits::MismatchedProjectionTypes<'tcx> { write!(f, "MismatchedProjectionTypes({:?})", self.err) } } - -/////////////////////////////////////////////////////////////////////////// -// TypeFoldable implementations. - -impl<'tcx, O: TypeFoldable>> TypeFoldable> - for traits::Obligation<'tcx, O> -{ - fn try_fold_with>>( - self, - folder: &mut F, - ) -> Result { - Ok(traits::Obligation { - cause: self.cause, - recursion_depth: self.recursion_depth, - predicate: self.predicate.try_fold_with(folder)?, - param_env: self.param_env.try_fold_with(folder)?, - }) - } -} - -impl<'tcx, O: TypeVisitable>> TypeVisitable> - for traits::Obligation<'tcx, O> -{ - fn visit_with>>(&self, visitor: &mut V) -> V::Result { - try_visit!(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 e36739356648..ff28dbeaee69 100644 --- a/compiler/rustc_interface/Cargo.toml +++ b/compiler/rustc_interface/Cargo.toml @@ -5,7 +5,6 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -rustc-rayon = { version = "0.5.0" } rustc-rayon-core = { version = "0.5.0" } rustc_ast = { path = "../rustc_ast" } rustc_ast_lowering = { path = "../rustc_ast_lowering" } diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index 33b4a48b28de..708fe23b7915 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -348,6 +348,10 @@ pub struct Config { /// the list of queries. pub override_queries: Option, + /// An extra set of symbols to add to the symbol interner, the symbol indices + /// will start at [`PREDEFINED_SYMBOLS_COUNT`](rustc_span::symbol::PREDEFINED_SYMBOLS_COUNT) + pub extra_symbols: Vec<&'static str>, + /// This is a callback from the driver that is called to create a codegen backend. /// /// Has no uses within this repository, but is used by bjorn3 for "the @@ -409,6 +413,7 @@ pub fn run_compiler(config: Config, f: impl FnOnce(&Compiler) -> R + Se &early_dcx, config.opts.edition, config.opts.unstable_opts.threads, + &config.extra_symbols, SourceMapInputs { file_loader, path_mapping, hash_kind, checksum_hash_kind }, |current_gcx| { // The previous `early_dcx` can't be reused here because it doesn't diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 747e36b6a1a2..fde1872fb399 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -800,6 +800,7 @@ pub fn create_and_enter_global_ctxt FnOnce(TyCtxt<'tcx>) -> T>( sess.opts.cg.metadata.clone(), sess.cfg_version, ); + let outputs = util::build_output_filenames(&pre_configured_attrs, sess); let dep_type = DepsType { dep_names: rustc_query_impl::dep_kind_names() }; @@ -955,7 +956,9 @@ fn run_required_analyses(tcx: TyCtxt<'_>) { // Run unsafety check because it's responsible for stealing and // deallocating THIR. tcx.ensure_ok().check_unsafety(def_id); - tcx.ensure_ok().mir_borrowck(def_id) + if !tcx.is_typeck_child(def_id.to_def_id()) { + tcx.ensure_ok().mir_borrowck(def_id) + } }); }); sess.time("MIR_effect_checking", || { diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index a8e556632572..d405d044cae6 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -53,7 +53,7 @@ where checksum_hash_kind, }); - rustc_span::create_session_globals_then(DEFAULT_EDITION, sm_inputs, || { + rustc_span::create_session_globals_then(DEFAULT_EDITION, &[], sm_inputs, || { let temps_dir = sessopts.unstable_opts.temps_dir.as_deref().map(PathBuf::from); let io = CompilerIO { input: Input::Str { name: FileName::Custom(String::new()), input: String::new() }, @@ -614,6 +614,7 @@ fn test_codegen_options_tracking_hash() { tracked!(control_flow_guard, CFGuard::Checks); tracked!(debug_assertions, Some(true)); tracked!(debuginfo, DebugInfo::Limited); + tracked!(dwarf_version, Some(5)); tracked!(embed_bitcode, false); tracked!(force_frame_pointers, FramePointer::Always); tracked!(force_unwind_tables, Some(true)); diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index 83d80938b4e3..c3a939f1ab08 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -117,6 +117,7 @@ fn run_in_thread_with_globals R + Send, R: Send>( thread_stack_size: usize, edition: Edition, sm_inputs: SourceMapInputs, + extra_symbols: &[&'static str], f: F, ) -> R { // The "thread pool" is a single spawned thread in the non-parallel @@ -134,9 +135,12 @@ fn run_in_thread_with_globals R + Send, R: Send>( // name contains null bytes. let r = builder .spawn_scoped(s, move || { - rustc_span::create_session_globals_then(edition, Some(sm_inputs), || { - f(CurrentGcx::new()) - }) + rustc_span::create_session_globals_then( + edition, + extra_symbols, + Some(sm_inputs), + || f(CurrentGcx::new()), + ) }) .unwrap() .join(); @@ -152,6 +156,7 @@ pub(crate) fn run_in_thread_pool_with_globals R + Send, thread_builder_diag: &EarlyDiagCtxt, edition: Edition, threads: usize, + extra_symbols: &[&'static str], sm_inputs: SourceMapInputs, f: F, ) -> R { @@ -168,18 +173,24 @@ pub(crate) fn run_in_thread_pool_with_globals R + Send, let registry = sync::Registry::new(std::num::NonZero::new(threads).unwrap()); if !sync::is_dyn_thread_safe() { - return run_in_thread_with_globals(thread_stack_size, edition, sm_inputs, |current_gcx| { - // Register the thread for use with the `WorkerLocal` type. - registry.register(); + return run_in_thread_with_globals( + thread_stack_size, + edition, + sm_inputs, + extra_symbols, + |current_gcx| { + // Register the thread for use with the `WorkerLocal` type. + registry.register(); - f(current_gcx) - }); + f(current_gcx) + }, + ); } let current_gcx = FromDyn::from(CurrentGcx::new()); let current_gcx2 = current_gcx.clone(); - let builder = rayon::ThreadPoolBuilder::new() + let builder = rayon_core::ThreadPoolBuilder::new() .thread_name(|_| "rustc".to_string()) .acquire_thread_handler(jobserver::acquire_thread) .release_thread_handler(jobserver::release_thread) @@ -230,13 +241,13 @@ pub(crate) fn run_in_thread_pool_with_globals R + Send, // pool. Upon creation, each worker thread created gets a copy of the // session globals in TLS. This is possible because `SessionGlobals` impls // `Send` in the parallel compiler. - rustc_span::create_session_globals_then(edition, Some(sm_inputs), || { + rustc_span::create_session_globals_then(edition, extra_symbols, Some(sm_inputs), || { rustc_span::with_session_globals(|session_globals| { let session_globals = FromDyn::from(session_globals); builder .build_scoped( // Initialize each new worker thread when created. - move |thread: rayon::ThreadBuilder| { + move |thread: rayon_core::ThreadBuilder| { // Register the thread for use with the `WorkerLocal` type. registry.register(); @@ -245,7 +256,9 @@ pub(crate) fn run_in_thread_pool_with_globals R + Send, }) }, // Run `f` on the first thread in the thread pool. - move |pool: &rayon::ThreadPool| pool.install(|| f(current_gcx.into_inner())), + move |pool: &rayon_core::ThreadPool| { + pool.install(|| f(current_gcx.into_inner())) + }, ) .unwrap() }) diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 782d328a9510..60c183bd56b1 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -271,7 +271,7 @@ lint_expectation = this lint expectation is unfulfilled lint_extern_crate_not_idiomatic = `extern crate` is not idiomatic in the new edition .suggestion = convert it to a `use` -lint_extern_without_abi = extern declarations without an explicit ABI are deprecated +lint_extern_without_abi = `extern` declarations without an explicit ABI are deprecated .label = ABI should be specified here .suggestion = explicitly specify the {$default_abi} ABI diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index dae0efcbbc46..e65f4beab241 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -779,21 +779,19 @@ impl EarlyLintPass for AnonymousParameters { } if let ast::AssocItemKind::Fn(box Fn { ref sig, .. }) = it.kind { for arg in sig.decl.inputs.iter() { - if let ast::PatKind::Ident(_, ident, None) = arg.pat.kind { - if ident.name == kw::Empty { - let ty_snip = cx.sess().source_map().span_to_snippet(arg.ty.span); + if let ast::PatKind::Missing = arg.pat.kind { + let ty_snip = cx.sess().source_map().span_to_snippet(arg.ty.span); - let (ty_snip, appl) = if let Ok(ref snip) = ty_snip { - (snip.as_str(), Applicability::MachineApplicable) - } else { - ("", Applicability::HasPlaceholders) - }; - cx.emit_span_lint( - ANONYMOUS_PARAMETERS, - arg.pat.span, - BuiltinAnonymousParams { suggestion: (arg.pat.span, appl), ty_snip }, - ); - } + let (ty_snip, appl) = if let Ok(ref snip) = ty_snip { + (snip.as_str(), Applicability::MachineApplicable) + } else { + ("", Applicability::HasPlaceholders) + }; + cx.emit_span_lint( + ANONYMOUS_PARAMETERS, + arg.pat.span, + BuiltinAnonymousParams { suggestion: (arg.pat.span, appl), ty_snip }, + ); } } } @@ -1990,7 +1988,7 @@ impl ExplicitOutlivesRequirements { inferred_outlives .filter_map(|(clause, _)| match clause.kind().skip_binder() { - ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(a, b)) => match *a { + ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(a, b)) => match a.kind() { ty::ReEarlyParam(ebr) if item_generics.region_param(ebr, tcx).def_id == lifetime.to_def_id() => { @@ -2040,7 +2038,7 @@ impl ExplicitOutlivesRequirements { let is_inferred = match tcx.named_bound_var(lifetime.hir_id) { Some(ResolvedArg::EarlyBound(def_id)) => inferred_outlives .iter() - .any(|r| matches!(**r, ty::ReEarlyParam(ebr) if { item_generics.region_param(ebr, tcx).def_id == def_id.to_def_id() })), + .any(|r| matches!(r.kind(), ty::ReEarlyParam(ebr) if { item_generics.region_param(ebr, tcx).def_id == def_id.to_def_id() })), _ => false, }; diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 885a7308bdc6..3660bb3f780a 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -83,11 +83,6 @@ enum TargetLint { Ignored, } -pub enum FindLintError { - NotFound, - Removed, -} - struct LintAlias { name: &'static str, /// Whether deprecation warnings should be suppressed for this alias. @@ -231,13 +226,24 @@ impl LintStore { } } - pub fn register_group_alias(&mut self, lint_name: &'static str, alias: &'static str) { - self.lint_groups.insert( + fn insert_group(&mut self, name: &'static str, group: LintGroup) { + let previous = self.lint_groups.insert(name, group); + if previous.is_some() { + bug!("group {name:?} already exists"); + } + } + + pub fn register_group_alias(&mut self, group_name: &'static str, alias: &'static str) { + let Some(LintGroup { lint_ids, .. }) = self.lint_groups.get(group_name) else { + bug!("group alias {alias:?} points to unregistered group {group_name:?}") + }; + + self.insert_group( alias, LintGroup { - lint_ids: vec![], + lint_ids: lint_ids.clone(), is_externally_loaded: false, - depr: Some(LintAlias { name: lint_name, silent: true }), + depr: Some(LintAlias { name: group_name, silent: true }), }, ); } @@ -249,24 +255,17 @@ impl LintStore { deprecated_name: Option<&'static str>, to: Vec, ) { - let new = self - .lint_groups - .insert(name, LintGroup { lint_ids: to, is_externally_loaded, depr: None }) - .is_none(); if let Some(deprecated) = deprecated_name { - self.lint_groups.insert( + self.insert_group( deprecated, LintGroup { - lint_ids: vec![], + lint_ids: to.clone(), is_externally_loaded, depr: Some(LintAlias { name, silent: false }), }, ); } - - if !new { - bug!("duplicate specification of lint group {}", name); - } + self.insert_group(name, LintGroup { lint_ids: to, is_externally_loaded, depr: None }); } /// This lint should give no warning and have no effect. @@ -292,23 +291,15 @@ impl LintStore { self.by_name.insert(name.into(), Removed(reason.into())); } - pub fn find_lints(&self, mut lint_name: &str) -> Result, FindLintError> { + pub fn find_lints(&self, lint_name: &str) -> Option<&[LintId]> { match self.by_name.get(lint_name) { - Some(&Id(lint_id)) => Ok(vec![lint_id]), - Some(&Renamed(_, lint_id)) => Ok(vec![lint_id]), - Some(&Removed(_)) => Err(FindLintError::Removed), - Some(&Ignored) => Ok(vec![]), - None => loop { - return match self.lint_groups.get(lint_name) { - Some(LintGroup { lint_ids, depr, .. }) => { - if let Some(LintAlias { name, .. }) = depr { - lint_name = name; - continue; - } - Ok(lint_ids.clone()) - } - None => Err(FindLintError::Removed), - }; + Some(Id(lint_id)) => Some(slice::from_ref(lint_id)), + Some(Renamed(_, lint_id)) => Some(slice::from_ref(lint_id)), + Some(Removed(_)) => None, + Some(Ignored) => Some(&[]), + None => match self.lint_groups.get(lint_name) { + Some(LintGroup { lint_ids, .. }) => Some(lint_ids), + None => None, }, } } @@ -374,8 +365,12 @@ impl LintStore { CheckLintNameResult::MissingTool }; } - Some(LintGroup { lint_ids, .. }) => { - return CheckLintNameResult::Tool(lint_ids, None); + Some(LintGroup { lint_ids, depr, .. }) => { + return if let &Some(LintAlias { name, silent: false }) = depr { + CheckLintNameResult::Tool(lint_ids, Some(name.to_string())) + } else { + CheckLintNameResult::Tool(lint_ids, None) + }; } }, Some(Id(id)) => return CheckLintNameResult::Tool(slice::from_ref(id), None), @@ -393,15 +388,11 @@ impl LintStore { None => self.check_tool_name_for_backwards_compat(&complete_name, "clippy"), Some(LintGroup { lint_ids, depr, .. }) => { // Check if the lint group name is deprecated - if let Some(LintAlias { name, silent }) = depr { - let LintGroup { lint_ids, .. } = self.lint_groups.get(name).unwrap(); - return if *silent { - CheckLintNameResult::Ok(lint_ids) - } else { - CheckLintNameResult::Tool(lint_ids, Some((*name).to_string())) - }; + if let &Some(LintAlias { name, silent: false }) = depr { + CheckLintNameResult::Tool(lint_ids, Some(name.to_string())) + } else { + CheckLintNameResult::Ok(lint_ids) } - CheckLintNameResult::Ok(lint_ids) } }, Some(Id(id)) => CheckLintNameResult::Ok(slice::from_ref(id)), @@ -412,7 +403,7 @@ impl LintStore { fn no_lint_suggestion(&self, lint_name: &str, tool_name: &str) -> CheckLintNameResult<'_> { let name_lower = lint_name.to_lowercase(); - if lint_name.chars().any(char::is_uppercase) && self.find_lints(&name_lower).is_ok() { + if lint_name.chars().any(char::is_uppercase) && self.find_lints(&name_lower).is_some() { // First check if the lint name is (partly) in upper case instead of lower case... return CheckLintNameResult::NoLint(Some((Symbol::intern(&name_lower), false))); } @@ -455,18 +446,8 @@ impl LintStore { None => match self.lint_groups.get(&*complete_name) { // Now we are sure, that this lint exists nowhere None => self.no_lint_suggestion(lint_name, tool_name), - Some(LintGroup { lint_ids, depr, .. }) => { - // Reaching this would be weird, but let's cover this case anyway - if let Some(LintAlias { name, silent }) = depr { - let LintGroup { lint_ids, .. } = self.lint_groups.get(name).unwrap(); - if *silent { - CheckLintNameResult::Tool(lint_ids, Some(complete_name)) - } else { - CheckLintNameResult::Tool(lint_ids, Some((*name).to_string())) - } - } else { - CheckLintNameResult::Tool(lint_ids, Some(complete_name)) - } + Some(LintGroup { lint_ids, .. }) => { + CheckLintNameResult::Tool(lint_ids, Some(complete_name)) } }, Some(Id(id)) => CheckLintNameResult::Tool(slice::from_ref(id), Some(complete_name)), @@ -855,11 +836,11 @@ impl<'tcx> LateContext<'tcx> { &self, self_ty: Ty<'tcx>, trait_id: DefId, - name: &str, + name: Symbol, ) -> Option> { let tcx = self.tcx; tcx.associated_items(trait_id) - .find_by_name_and_kind(tcx, Ident::from_str(name), ty::AssocKind::Type, trait_id) + .find_by_ident_and_kind(tcx, Ident::with_dummy_span(name), ty::AssocTag::Type, trait_id) .and_then(|assoc| { let proj = Ty::new_projection(tcx, assoc.def_id, [self_ty]); tcx.try_normalize_erasing_regions(self.typing_env(), proj).ok() diff --git a/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs b/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs index ec8f84415759..5989ef9519cd 100644 --- a/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs +++ b/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs @@ -69,7 +69,7 @@ impl<'tcx> LateLintPass<'tcx> for DerefIntoDynSupertrait { && let ty::Dynamic(data, _, ty::Dyn) = self_ty.kind() && let Some(self_principal) = data.principal() // `::Target` is `dyn target_principal` - && let Some(target) = cx.get_associated_type(self_ty, did, "Target") + && let Some(target) = cx.get_associated_type(self_ty, did, sym::Target) && let ty::Dynamic(data, _, ty::Dyn) = target.kind() && let Some(target_principal) = data.principal() // `target_principal` is a supertrait of `t_principal` diff --git a/compiler/rustc_lint/src/errors.rs b/compiler/rustc_lint/src/errors.rs index d109a5c90305..586e55c8055c 100644 --- a/compiler/rustc_lint/src/errors.rs +++ b/compiler/rustc_lint/src/errors.rs @@ -1,5 +1,5 @@ use rustc_errors::codes::*; -use rustc_errors::{Diag, EmissionGuarantee, SubdiagMessageOp, Subdiagnostic}; +use rustc_errors::{Diag, EmissionGuarantee, Subdiagnostic}; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_session::lint::Level; use rustc_span::{Span, Symbol}; @@ -26,11 +26,7 @@ pub(crate) enum OverruledAttributeSub { } impl Subdiagnostic for OverruledAttributeSub { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { match self { OverruledAttributeSub::DefaultSource { id } => { diag.note(fluent::lint_default_source); diff --git a/compiler/rustc_lint/src/if_let_rescope.rs b/compiler/rustc_lint/src/if_let_rescope.rs index 39ea8d8e3246..a9b04511c6b4 100644 --- a/compiler/rustc_lint/src/if_let_rescope.rs +++ b/compiler/rustc_lint/src/if_let_rescope.rs @@ -3,9 +3,7 @@ use std::ops::ControlFlow; use hir::intravisit::{self, Visitor}; use rustc_ast::Recovered; -use rustc_errors::{ - Applicability, Diag, EmissionGuarantee, SubdiagMessageOp, Subdiagnostic, SuggestionStyle, -}; +use rustc_errors::{Applicability, Diag, EmissionGuarantee, Subdiagnostic, SuggestionStyle}; use rustc_hir::{self as hir, HirIdSet}; use rustc_macros::{LintDiagnostic, Subdiagnostic}; use rustc_middle::ty::adjustment::Adjust; @@ -327,11 +325,7 @@ struct IfLetRescopeRewrite { } impl Subdiagnostic for IfLetRescopeRewrite { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { let mut suggestions = vec![]; for match_head in self.match_heads { match match_head { @@ -360,7 +354,7 @@ impl Subdiagnostic for IfLetRescopeRewrite { .chain(repeat('}').take(closing_brackets.count)) .collect(), )); - let msg = f(diag, crate::fluent_generated::lint_suggestion); + let msg = diag.eagerly_translate(crate::fluent_generated::lint_suggestion); diag.multipart_suggestion_with_style( msg, suggestions, diff --git a/compiler/rustc_lint/src/impl_trait_overcaptures.rs b/compiler/rustc_lint/src/impl_trait_overcaptures.rs index 26481b97076f..f1dc420aa3c9 100644 --- a/compiler/rustc_lint/src/impl_trait_overcaptures.rs +++ b/compiler/rustc_lint/src/impl_trait_overcaptures.rs @@ -461,7 +461,7 @@ fn extract_def_id_from_arg<'tcx>( arg: ty::GenericArg<'tcx>, ) -> DefId { match arg.unpack() { - ty::GenericArgKind::Lifetime(re) => match *re { + ty::GenericArgKind::Lifetime(re) => match re.kind() { ty::ReEarlyParam(ebr) => generics.region_param(ebr, tcx).def_id, ty::ReBound( _, @@ -530,7 +530,7 @@ impl<'tcx> TypeRelation> for FunctionalVariances<'tcx> { a: ty::Region<'tcx>, _: ty::Region<'tcx>, ) -> RelateResult<'tcx, ty::Region<'tcx>> { - let def_id = match *a { + let def_id = match a.kind() { ty::ReEarlyParam(ebr) => self.generics.region_param(ebr, self.tcx).def_id, ty::ReBound( _, diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index f1fe07cfcfaa..00775647ac61 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -1,10 +1,11 @@ use rustc_ast::attr::AttributeExt; use rustc_ast_pretty::pprust; -use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; +use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; +use rustc_data_structures::unord::UnordSet; use rustc_errors::{Diag, LintDiagnostic, MultiSpan}; use rustc_feature::{Features, GateIssue}; +use rustc_hir::HirId; use rustc_hir::intravisit::{self, Visitor}; -use rustc_hir::{CRATE_HIR_ID, HirId}; use rustc_index::IndexVec; use rustc_middle::bug; use rustc_middle::hir::nested_filter; @@ -115,12 +116,11 @@ impl LintLevelSets { } } -fn lints_that_dont_need_to_run(tcx: TyCtxt<'_>, (): ()) -> FxIndexSet { +fn lints_that_dont_need_to_run(tcx: TyCtxt<'_>, (): ()) -> UnordSet { let store = unerased_lint_store(&tcx.sess); + let root_map = tcx.shallow_lint_levels_on(hir::CRATE_OWNER_ID); - let map = tcx.shallow_lint_levels_on(rustc_hir::CRATE_OWNER_ID); - - let dont_need_to_run: FxIndexSet = store + let mut dont_need_to_run: FxHashSet = store .get_lints() .into_iter() .filter(|lint| { @@ -129,24 +129,31 @@ fn lints_that_dont_need_to_run(tcx: TyCtxt<'_>, (): ()) -> FxIndexSet { lint.future_incompatible.is_some_and(|fut| fut.reason.has_future_breakage()); !has_future_breakage && !lint.eval_always }) - .filter_map(|lint| { - let lint_level = map.lint_level_id_at_node(tcx, LintId::of(lint), CRATE_HIR_ID); - if matches!(lint_level.level, Level::Allow) - || (matches!(lint_level.src, LintLevelSource::Default)) - && lint.default_level(tcx.sess.edition()) == Level::Allow - { - Some(LintId::of(lint)) - } else { - None - } + .filter(|lint| { + let lint_level = + root_map.lint_level_id_at_node(tcx, LintId::of(lint), hir::CRATE_HIR_ID); + // Only include lints that are allowed at crate root or by default. + matches!(lint_level.level, Level::Allow) + || (matches!(lint_level.src, LintLevelSource::Default) + && lint.default_level(tcx.sess.edition()) == Level::Allow) }) + .map(|lint| LintId::of(*lint)) .collect(); - let mut visitor = LintLevelMaximum { tcx, dont_need_to_run }; - visitor.process_opts(); - tcx.hir_walk_attributes(&mut visitor); + for owner in tcx.hir_crate_items(()).owners() { + let map = tcx.shallow_lint_levels_on(owner); - visitor.dont_need_to_run + // All lints that appear with a non-allow level must be run. + for (_, specs) in map.specs.iter() { + for (lint, level_and_source) in specs.iter() { + if !matches!(level_and_source.level, Level::Allow) { + dont_need_to_run.remove(lint); + } + } + } + } + + dont_need_to_run.into() } #[instrument(level = "trace", skip(tcx), ret)] @@ -340,76 +347,6 @@ impl<'tcx> Visitor<'tcx> for LintLevelsBuilder<'_, LintLevelQueryMap<'tcx>> { } } -/// Visitor with the only function of visiting every item-like in a crate and -/// computing the highest level that every lint gets put to. -/// -/// E.g., if a crate has a global #![allow(lint)] attribute, but a single item -/// uses #[warn(lint)], this visitor will set that lint level as `Warn` -struct LintLevelMaximum<'tcx> { - tcx: TyCtxt<'tcx>, - /// The actual list of detected lints. - dont_need_to_run: FxIndexSet, -} - -impl<'tcx> LintLevelMaximum<'tcx> { - fn process_opts(&mut self) { - let store = unerased_lint_store(self.tcx.sess); - for (lint_group, level) in &self.tcx.sess.opts.lint_opts { - if *level != Level::Allow { - let Ok(lints) = store.find_lints(lint_group) else { - return; - }; - for lint in lints { - self.dont_need_to_run.swap_remove(&lint); - } - } - } - } -} - -impl<'tcx> Visitor<'tcx> for LintLevelMaximum<'tcx> { - type NestedFilter = nested_filter::All; - - fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt { - self.tcx - } - - /// FIXME(blyxyas): In a future revision, we should also graph #![allow]s, - /// but that is handled with more care - fn visit_attribute(&mut self, attribute: &'tcx hir::Attribute) { - if matches!( - Level::from_attr(attribute), - Some((Level::Warn | Level::Deny | Level::Forbid | Level::Expect | Level::ForceWarn, _)) - ) { - let store = unerased_lint_store(self.tcx.sess); - // Lint attributes are always a metalist inside a - // metalist (even with just one lint). - let Some(meta_item_list) = attribute.meta_item_list() else { return }; - - for meta_list in meta_item_list { - // Convert Path to String - let Some(meta_item) = meta_list.meta_item() else { return }; - let ident: &str = &meta_item - .path - .segments - .iter() - .map(|segment| segment.ident.as_str()) - .collect::>() - .join("::"); - let Ok(lints) = store.find_lints( - // Lint attributes can only have literals - ident, - ) else { - return; - }; - for lint in lints { - self.dont_need_to_run.swap_remove(&lint); - } - } - } - } -} - pub struct LintLevelsBuilder<'s, P> { sess: &'s Session, features: &'s Features, @@ -580,11 +517,11 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { let lint_flag_val = Symbol::intern(lint_name); - let Ok(ids) = self.store.find_lints(lint_name) else { + let Some(ids) = self.store.find_lints(lint_name) else { // errors already handled above continue; }; - for id in ids { + for &id in ids { // ForceWarn and Forbid cannot be overridden if let Some(LevelAndSource { level: Level::ForceWarn | Level::Forbid, .. }) = self.current_specs().get(&id) diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 9b5c564d3324..212368bea826 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -21,7 +21,6 @@ // tidy-alphabetical-start #![allow(internal_features)] -#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(array_windows)] @@ -125,9 +124,7 @@ use unused::*; #[rustfmt::skip] pub use builtin::{MissingDoc, SoftLints}; -pub use context::{ - CheckLintNameResult, EarlyContext, FindLintError, LateContext, LintContext, LintStore, -}; +pub use context::{CheckLintNameResult, EarlyContext, LateContext, LintContext, LintStore}; pub use early::{EarlyCheckNode, check_ast_node}; pub use late::{check_crate, late_lint_mod, unerased_lint_store}; pub use levels::LintLevelsBuilder; @@ -606,6 +603,11 @@ fn register_builtins(store: &mut LintStore) { "converted into hard error, see issue #127323 \ for more information", ); + store.register_removed( + "undefined_naked_function_abi", + "converted into hard error, see PR #139001 \ + for more information", + ); } fn register_internals(store: &mut LintStore) { diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 55d010e6d34a..8ab64fbd127a 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -6,7 +6,7 @@ use rustc_abi::ExternAbi; use rustc_errors::codes::*; use rustc_errors::{ Applicability, Diag, DiagArgValue, DiagMessage, DiagStyledString, ElidedLifetimeInPathSubdiag, - EmissionGuarantee, LintDiagnostic, MultiSpan, SubdiagMessageOp, Subdiagnostic, SuggestionStyle, + EmissionGuarantee, LintDiagnostic, MultiSpan, Subdiagnostic, SuggestionStyle, }; use rustc_hir::def::Namespace; use rustc_hir::def_id::DefId; @@ -449,11 +449,7 @@ pub(crate) struct BuiltinUnpermittedTypeInitSub { } impl Subdiagnostic for BuiltinUnpermittedTypeInitSub { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { let mut err = self.err; loop { if let Some(span) = err.span { @@ -504,16 +500,12 @@ pub(crate) struct BuiltinClashingExternSub<'a> { } impl Subdiagnostic for BuiltinClashingExternSub<'_> { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { let mut expected_str = DiagStyledString::new(); expected_str.push(self.expected.fn_sig(self.tcx).to_string(), false); let mut found_str = DiagStyledString::new(); found_str.push(self.found.fn_sig(self.tcx).to_string(), true); - diag.note_expected_found(&"", expected_str, &"", found_str); + diag.note_expected_found("", expected_str, "", found_str); } } @@ -824,11 +816,7 @@ pub(crate) struct HiddenUnicodeCodepointsDiagLabels { } impl Subdiagnostic for HiddenUnicodeCodepointsDiagLabels { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { for (c, span) in self.spans { diag.span_label(span, format!("{c:?}")); } @@ -842,11 +830,7 @@ pub(crate) enum HiddenUnicodeCodepointsDiagSub { // Used because of multiple multipart_suggestion and note impl Subdiagnostic for HiddenUnicodeCodepointsDiagSub { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { match self { HiddenUnicodeCodepointsDiagSub::Escape { spans } => { diag.multipart_suggestion_with_style( @@ -1015,11 +999,7 @@ pub(crate) struct NonBindingLetSub { } impl Subdiagnostic for NonBindingLetSub { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { let can_suggest_binding = self.drop_fn_start_end.is_some() || !self.is_assign_desugar; if can_suggest_binding { @@ -1303,11 +1283,7 @@ pub(crate) enum NonSnakeCaseDiagSub { } impl Subdiagnostic for NonSnakeCaseDiagSub { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { match self { NonSnakeCaseDiagSub::Label { span } => { diag.span_label(span, fluent::lint_label); @@ -1629,11 +1605,7 @@ pub(crate) enum OverflowingBinHexSign { } impl Subdiagnostic for OverflowingBinHexSign { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { match self { OverflowingBinHexSign::Positive => { diag.note(fluent::lint_positive_note); diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index df567e80e556..a3e7c84584d3 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -423,11 +423,11 @@ impl<'tcx> LateLintPass<'tcx> for NonSnakeCase { } fn check_trait_item(&mut self, cx: &LateContext<'_>, item: &hir::TraitItem<'_>) { - if let hir::TraitItemKind::Fn(_, hir::TraitFn::Required(pnames)) = item.kind { + if let hir::TraitItemKind::Fn(_, hir::TraitFn::Required(param_idents)) = item.kind { self.check_snake_case(cx, "trait method", &item.ident); - for param_name in pnames { - if let Some(param_name) = param_name { - self.check_snake_case(cx, "variable", param_name); + for param_ident in param_idents { + if let Some(param_ident) = param_ident { + self.check_snake_case(cx, "variable", param_ident); } } } diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index a6c82f574a1c..a084dacfb5be 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -864,8 +864,8 @@ fn ty_is_known_nonnull<'tcx>( return true; } - // `UnsafeCell` has its niche hidden. - if def.is_unsafe_cell() { + // `UnsafeCell` and `UnsafePinned` have their niche hidden. + if def.is_unsafe_cell() || def.is_unsafe_pinned() { return false; } diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 7b43aac90c74..806bca78f787 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -1201,7 +1201,8 @@ impl EarlyLintPass for UnusedParens { // Do not lint on `(..)` as that will result in the other arms being useless. Paren(_) // The other cases do not contain sub-patterns. - | Wild | Never | Rest | Expr(..) | MacCall(..) | Range(..) | Ident(.., None) | Path(..) | Err(_) => {}, + | Missing | Wild | Never | Rest | Expr(..) | MacCall(..) | Range(..) | Ident(.., None) + | Path(..) | Err(_) => {}, // These are list-like patterns; parens can always be removed. TupleStruct(_, _, ps) | Tuple(ps) | Slice(ps) | Or(ps) => for p in ps { self.check_unused_parens_pat(cx, p, false, false, keep_space); diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 8a761a0a0969..b25d2a30681c 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -110,7 +110,6 @@ declare_lint_pass! { UNCONDITIONAL_PANIC, UNCONDITIONAL_RECURSION, UNCOVERED_PARAM_IN_PROJECTION, - UNDEFINED_NAKED_FUNCTION_ABI, UNEXPECTED_CFGS, UNFULFILLED_LINT_EXPECTATIONS, UNINHABITED_STATIC, @@ -2830,39 +2829,6 @@ declare_lint! { "detects deprecation attributes with no effect", } -declare_lint! { - /// The `undefined_naked_function_abi` lint detects naked function definitions that - /// either do not specify an ABI or specify the Rust ABI. - /// - /// ### Example - /// - /// ```rust - /// #![feature(asm_experimental_arch, naked_functions)] - /// - /// use std::arch::naked_asm; - /// - /// #[naked] - /// pub fn default_abi() -> u32 { - /// unsafe { naked_asm!(""); } - /// } - /// - /// #[naked] - /// pub extern "Rust" fn rust_abi() -> u32 { - /// unsafe { naked_asm!(""); } - /// } - /// ``` - /// - /// {{produces}} - /// - /// ### Explanation - /// - /// The Rust ABI is currently undefined. Therefore, naked functions should - /// specify a non-Rust ABI. - pub UNDEFINED_NAKED_FUNCTION_ABI, - Warn, - "undefined naked function ABI" -} - declare_lint! { /// The `ineffective_unstable_trait_impl` lint detects `#[unstable]` attributes which are not used. /// diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 7fdbae3a59d7..b4069b317bfa 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -249,7 +249,7 @@ impl Level { /// Converts an `Attribute` to a level. pub fn from_attr(attr: &impl AttributeExt) -> Option<(Self, Option)> { - Self::from_symbol(attr.name_or_empty(), || Some(attr.id())) + attr.name().and_then(|name| Self::from_symbol(name, || Some(attr.id()))) } /// Converts a `Symbol` to a level. diff --git a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs index 909083d5e865..bc9516b2e0c6 100644 --- a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs +++ b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs @@ -20,14 +20,12 @@ use crate::diagnostics::utils::{ /// The central struct for constructing the `add_to_diag` method from an annotated struct. pub(crate) struct SubdiagnosticDerive { diag: syn::Ident, - f: syn::Ident, } impl SubdiagnosticDerive { pub(crate) fn new() -> Self { let diag = format_ident!("diag"); - let f = format_ident!("f"); - Self { diag, f } + Self { diag } } pub(crate) fn into_tokens(self, mut structure: Structure<'_>) -> TokenStream { @@ -86,19 +84,16 @@ impl SubdiagnosticDerive { }; let diag = &self.diag; - let f = &self.f; // FIXME(edition_2024): Fix the `keyword_idents_2024` lint to not trigger here? #[allow(keyword_idents_2024)] let ret = structure.gen_impl(quote! { gen impl rustc_errors::Subdiagnostic for @Self { - fn add_to_diag_with<__G, __F>( + fn add_to_diag<__G>( self, #diag: &mut rustc_errors::Diag<'_, __G>, - #f: &__F ) where __G: rustc_errors::EmissionGuarantee, - __F: rustc_errors::SubdiagMessageOp<__G>, { #implementation } @@ -384,11 +379,10 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> { Ok(quote! {}) } "subdiagnostic" => { - let f = &self.parent.f; let diag = &self.parent.diag; let binding = &info.binding; self.has_subdiagnostic = true; - Ok(quote! { #binding.add_to_diag_with(#diag, #f); }) + Ok(quote! { #binding.add_to_diag(#diag); }) } _ => { let mut span_attrs = vec![]; @@ -531,12 +525,11 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> { let span_field = self.span_field.value_ref(); let diag = &self.parent.diag; - let f = &self.parent.f; let mut calls = TokenStream::new(); for (kind, slug, no_span) in kind_slugs { let message = format_ident!("__message"); calls.extend( - quote! { let #message = #f(#diag, crate::fluent_generated::#slug.into()); }, + quote! { let #message = #diag.eagerly_translate(crate::fluent_generated::#slug); }, ); let name = format_ident!( diff --git a/compiler/rustc_macros/src/symbols.rs b/compiler/rustc_macros/src/symbols.rs index 37200f62eb5a..0400de622740 100644 --- a/compiler/rustc_macros/src/symbols.rs +++ b/compiler/rustc_macros/src/symbols.rs @@ -142,13 +142,13 @@ pub(super) fn symbols(input: TokenStream) -> TokenStream { output } -struct Preinterned { +struct Predefined { idx: u32, span_of_name: Span, } struct Entries { - map: HashMap, + map: HashMap, } impl Entries { @@ -163,7 +163,7 @@ impl Entries { prev.idx } else { let idx = self.len(); - self.map.insert(s.to_string(), Preinterned { idx, span_of_name: span }); + self.map.insert(s.to_string(), Predefined { idx, span_of_name: span }); idx } } @@ -295,10 +295,14 @@ fn symbols_with_errors(input: TokenStream) -> (TokenStream, Vec) { } let symbol_digits_base = entries.map["0"].idx; - let preinterned_symbols_count = entries.len(); + let predefined_symbols_count = entries.len(); let output = quote! { const SYMBOL_DIGITS_BASE: u32 = #symbol_digits_base; - const PREINTERNED_SYMBOLS_COUNT: u32 = #preinterned_symbols_count; + + /// The number of predefined symbols; this is the the first index for + /// extra pre-interned symbols in an Interner created via + /// [`Interner::with_extra_symbols`]. + pub const PREDEFINED_SYMBOLS_COUNT: u32 = #predefined_symbols_count; #[doc(hidden)] #[allow(non_upper_case_globals)] @@ -315,10 +319,13 @@ fn symbols_with_errors(input: TokenStream) -> (TokenStream, Vec) { } impl Interner { - pub(crate) fn fresh() -> Self { - Interner::prefill(&[ - #prefill_stream - ]) + /// Creates an `Interner` with the predefined symbols from the `symbols!` macro and + /// any extra symbols provided by external drivers such as Clippy + pub(crate) fn with_extra_symbols(extra_symbols: &[&'static str]) -> Self { + Interner::prefill( + &[#prefill_stream], + extra_symbols, + ) } } }; diff --git a/compiler/rustc_macros/src/type_foldable.rs b/compiler/rustc_macros/src/type_foldable.rs index c4f584dca430..85051311bee9 100644 --- a/compiler/rustc_macros/src/type_foldable.rs +++ b/compiler/rustc_macros/src/type_foldable.rs @@ -14,31 +14,33 @@ pub(super) fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_m s.add_bounds(synstructure::AddBounds::Generics); s.bind_with(|_| synstructure::BindStyle::Move); + let try_body_fold = s.each_variant(|vi| { + let bindings = vi.bindings(); + vi.construct(|_, index| { + let bind = &bindings[index]; + + // retain value of fields with #[type_foldable(identity)] + if has_ignore_attr(&bind.ast().attrs, "type_foldable", "identity") { + bind.to_token_stream() + } else { + quote! { + ::rustc_middle::ty::TypeFoldable::try_fold_with(#bind, __folder)? + } + } + }) + }); + let body_fold = s.each_variant(|vi| { let bindings = vi.bindings(); vi.construct(|_, index| { let bind = &bindings[index]; - let mut fixed = false; - // retain value of fields with #[type_foldable(identity)] - bind.ast().attrs.iter().for_each(|x| { - if !x.path().is_ident("type_foldable") { - return; - } - let _ = x.parse_nested_meta(|nested| { - if nested.path.is_ident("identity") { - fixed = true; - } - Ok(()) - }); - }); - - if fixed { + if has_ignore_attr(&bind.ast().attrs, "type_foldable", "identity") { bind.to_token_stream() } else { quote! { - ::rustc_middle::ty::TypeFoldable::try_fold_with(#bind, __folder)? + ::rustc_middle::ty::TypeFoldable::fold_with(#bind, __folder) } } }) @@ -51,8 +53,32 @@ pub(super) fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_m self, __folder: &mut __F ) -> Result { - Ok(match self { #body_fold }) + Ok(match self { #try_body_fold }) + } + + fn fold_with<__F: ::rustc_middle::ty::TypeFolder<::rustc_middle::ty::TyCtxt<'tcx>>>( + self, + __folder: &mut __F + ) -> Self { + match self { #body_fold } } }, ) } + +fn has_ignore_attr(attrs: &[syn::Attribute], name: &'static str, meta: &'static str) -> bool { + let mut ignored = false; + attrs.iter().for_each(|attr| { + if !attr.path().is_ident(name) { + return; + } + let _ = attr.parse_nested_meta(|nested| { + if nested.path.is_ident(meta) { + ignored = true; + } + Ok(()) + }); + }); + + ignored +} diff --git a/compiler/rustc_metadata/src/lib.rs b/compiler/rustc_metadata/src/lib.rs index 028d5c8b6099..3b44c44fcb94 100644 --- a/compiler/rustc_metadata/src/lib.rs +++ b/compiler/rustc_metadata/src/lib.rs @@ -1,6 +1,5 @@ // tidy-alphabetical-start #![allow(internal_features)] -#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(coroutines)] diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs index 130a425e9c74..cee9cff07750 100644 --- a/compiler/rustc_metadata/src/native_libs.rs +++ b/compiler/rustc_metadata/src/native_libs.rs @@ -207,7 +207,7 @@ impl<'tcx> Collector<'tcx> { let sess = self.tcx.sess; - if matches!(abi, ExternAbi::Rust | ExternAbi::RustIntrinsic) { + if matches!(abi, ExternAbi::Rust) { return; } @@ -226,8 +226,8 @@ impl<'tcx> Collector<'tcx> { let mut wasm_import_module = None; let mut import_name_type = None; for item in items.iter() { - match item.name_or_empty() { - sym::name => { + match item.name() { + Some(sym::name) => { if name.is_some() { sess.dcx().emit_err(errors::MultipleNamesInLink { span: item.span() }); continue; @@ -242,7 +242,7 @@ impl<'tcx> Collector<'tcx> { } name = Some((link_name, span)); } - sym::kind => { + Some(sym::kind) => { if kind.is_some() { sess.dcx().emit_err(errors::MultipleKindsInLink { span: item.span() }); continue; @@ -304,7 +304,7 @@ impl<'tcx> Collector<'tcx> { }; kind = Some(link_kind); } - sym::modifiers => { + Some(sym::modifiers) => { if modifiers.is_some() { sess.dcx() .emit_err(errors::MultipleLinkModifiers { span: item.span() }); @@ -316,7 +316,7 @@ impl<'tcx> Collector<'tcx> { }; modifiers = Some((link_modifiers, item.name_value_literal_span().unwrap())); } - sym::cfg => { + Some(sym::cfg) => { if cfg.is_some() { sess.dcx().emit_err(errors::MultipleCfgs { span: item.span() }); continue; @@ -346,7 +346,7 @@ impl<'tcx> Collector<'tcx> { } cfg = Some(link_cfg.clone()); } - sym::wasm_import_module => { + Some(sym::wasm_import_module) => { if wasm_import_module.is_some() { sess.dcx().emit_err(errors::MultipleWasmImport { span: item.span() }); continue; @@ -357,7 +357,7 @@ impl<'tcx> Collector<'tcx> { }; wasm_import_module = Some((link_wasm_import_module, item.span())); } - sym::import_name_type => { + Some(sym::import_name_type) => { if import_name_type.is_some() { sess.dcx() .emit_err(errors::MultipleImportNameType { span: item.span() }); diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 4610a571da08..3c2245347f97 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -562,9 +562,9 @@ impl<'a, 'tcx> SpanDecoder for DecodeContext<'a, 'tcx> { Symbol::intern(s) }) } - SYMBOL_PREINTERNED => { + SYMBOL_PREDEFINED => { let symbol_index = self.read_u32(); - Symbol::new_from_decoded(symbol_index) + Symbol::new(symbol_index) } _ => unreachable!(), } @@ -1313,7 +1313,7 @@ impl<'a> CrateMetadataRef<'a> { fn get_fn_has_self_parameter(self, id: DefIndex, sess: &'a Session) -> bool { self.root .tables - .fn_arg_names + .fn_arg_idents .get(self, id) .expect("argument names not encoded for a function") .decode((self, sess)) @@ -1332,29 +1332,30 @@ impl<'a> CrateMetadataRef<'a> { } fn get_associated_item(self, id: DefIndex, sess: &'a Session) -> ty::AssocItem { - let name = if self.root.tables.opt_rpitit_info.get(self, id).is_some() { - kw::Empty - } else { - self.item_name(id) - }; - let (kind, has_self) = match self.def_kind(id) { - DefKind::AssocConst => (ty::AssocKind::Const, false), - DefKind::AssocFn => (ty::AssocKind::Fn, self.get_fn_has_self_parameter(id, sess)), - DefKind::AssocTy => (ty::AssocKind::Type, false), + let kind = match self.def_kind(id) { + DefKind::AssocConst => ty::AssocKind::Const { name: self.item_name(id) }, + DefKind::AssocFn => ty::AssocKind::Fn { + name: self.item_name(id), + has_self: self.get_fn_has_self_parameter(id, sess), + }, + DefKind::AssocTy => { + let data = if let Some(rpitit_info) = self.root.tables.opt_rpitit_info.get(self, id) + { + ty::AssocTypeData::Rpitit(rpitit_info.decode(self)) + } else { + ty::AssocTypeData::Normal(self.item_name(id)) + }; + ty::AssocKind::Type { data } + } _ => bug!("cannot get associated-item of `{:?}`", self.def_key(id)), }; let container = self.root.tables.assoc_container.get(self, id).unwrap(); - let opt_rpitit_info = - self.root.tables.opt_rpitit_info.get(self, id).map(|d| d.decode(self)); ty::AssocItem { - name, kind, def_id: self.local_def_id(id), trait_item_def_id: self.get_trait_item_def_id(id), container, - fn_has_self_parameter: has_self, - opt_rpitit_info, } } diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 3dc82ce9d183..ecc2dcc5318d 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -286,7 +286,7 @@ provide! { tcx, def_id, other, cdata, rendered_const => { table } rendered_precise_capturing_args => { table } asyncness => { table_direct } - fn_arg_names => { table } + fn_arg_idents => { table } coroutine_kind => { table_direct } coroutine_for_closure => { table } coroutine_by_move_body_def_id => { table } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 167122a9793a..3ea61d1b40a6 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -201,9 +201,9 @@ impl<'a, 'tcx> SpanEncoder for EncodeContext<'a, 'tcx> { } fn encode_symbol(&mut self, symbol: Symbol) { - // if symbol preinterned, emit tag and symbol index - if symbol.is_preinterned() { - self.opaque.emit_u8(SYMBOL_PREINTERNED); + // if symbol predefined, emit tag and symbol index + if symbol.is_predefined() { + self.opaque.emit_u8(SYMBOL_PREDEFINED); self.opaque.emit_u32(symbol.as_u32()); } else { // otherwise write it as string or as offset to it @@ -821,7 +821,9 @@ struct AnalyzeAttrState<'a> { #[inline] fn analyze_attr(attr: &impl AttributeExt, state: &mut AnalyzeAttrState<'_>) -> bool { let mut should_encode = false; - if !rustc_feature::encode_cross_crate(attr.name_or_empty()) { + if let Some(name) = attr.name() + && !rustc_feature::encode_cross_crate(name) + { // Attributes not marked encode-cross-crate don't need to be encoded for downstream crates. } else if attr.doc_str().is_some() { // We keep all doc comments reachable to rustdoc because they might be "imported" into @@ -1099,7 +1101,6 @@ fn should_encode_variances<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, def_kind: Def DefKind::Struct | DefKind::Union | DefKind::Enum - | DefKind::Variant | DefKind::OpaqueTy | DefKind::Fn | DefKind::Ctor(..) @@ -1109,6 +1110,7 @@ fn should_encode_variances<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, def_kind: Def matches!(tcx.opt_rpitit_info(def_id), Some(ty::ImplTraitInTraitData::Trait { .. })) } DefKind::Mod + | DefKind::Variant | DefKind::Field | DefKind::AssocConst | DefKind::TyParam @@ -1338,7 +1340,7 @@ fn should_encode_const(def_kind: DefKind) -> bool { fn should_encode_fn_impl_trait_in_trait<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool { if let Some(assoc_item) = tcx.opt_associated_item(def_id) && assoc_item.container == ty::AssocItemContainer::Trait - && assoc_item.kind == ty::AssocKind::Fn + && assoc_item.is_fn() { true } else { @@ -1469,7 +1471,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } if let DefKind::Fn | DefKind::AssocFn = def_kind { self.tables.asyncness.set_some(def_id.index, tcx.asyncness(def_id)); - record_array!(self.tables.fn_arg_names[def_id] <- tcx.fn_arg_names(def_id)); + record_array!(self.tables.fn_arg_idents[def_id] <- tcx.fn_arg_idents(def_id)); } if let Some(name) = tcx.intrinsic(def_id) { record!(self.tables.intrinsic[def_id] <- name); @@ -1691,7 +1693,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { match item.container { AssocItemContainer::Trait => { - if let ty::AssocKind::Type = item.kind { + if item.is_type() { self.encode_explicit_item_bounds(def_id); self.encode_explicit_item_self_bounds(def_id); if tcx.is_conditionally_const(def_id) { @@ -1706,7 +1708,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } } } - if let Some(rpitit_info) = item.opt_rpitit_info { + if let ty::AssocKind::Type { data: ty::AssocTypeData::Rpitit(rpitit_info) } = item.kind { record!(self.tables.opt_rpitit_info[def_id] <- rpitit_info); if matches!(rpitit_info, ty::ImplTraitInTraitData::Trait { .. }) { record_array!( @@ -2199,7 +2201,7 @@ fn prefetch_mir(tcx: TyCtxt<'_>) { } let reachable_set = tcx.reachable_set(()); - par_for_each_in(tcx.mir_keys(()), |&def_id| { + par_for_each_in(tcx.mir_keys(()), |&&def_id| { let (encode_const, encode_opt) = should_encode_mir(tcx, reachable_set, def_id); if encode_const { diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 96a1f65eeb0f..5aa81f41b7b4 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -36,9 +36,7 @@ use rustc_serialize::opaque::FileEncoder; use rustc_session::config::{SymbolManglingVersion, TargetModifier}; use rustc_session::cstore::{CrateDepKind, ForeignModule, LinkagePreference, NativeLib}; use rustc_span::edition::Edition; -use rustc_span::hygiene::{ - ExpnIndex, MacroKind, SyntaxContextDataNonRecursive as SyntaxContextData, -}; +use rustc_span::hygiene::{ExpnIndex, MacroKind, SyntaxContextKey}; use rustc_span::{self, ExpnData, ExpnHash, ExpnId, Ident, Span, Symbol}; use rustc_target::spec::{PanicStrategy, TargetTuple}; use table::TableBuilder; @@ -195,7 +193,7 @@ enum LazyState { Previous(NonZero), } -type SyntaxContextTable = LazyTable>>; +type SyntaxContextTable = LazyTable>>; type ExpnDataTable = LazyTable>>; type ExpnHashTable = LazyTable>>; @@ -451,7 +449,7 @@ define_tables! { rendered_const: Table>, rendered_precise_capturing_args: Table>>, asyncness: Table, - fn_arg_names: Table>>, + fn_arg_idents: Table>>, coroutine_kind: Table, coroutine_for_closure: Table, adt_destructor: Table>, @@ -586,7 +584,7 @@ impl SpanTag { // Tags for encoding Symbol's const SYMBOL_STR: u8 = 0; const SYMBOL_OFFSET: u8 = 1; -const SYMBOL_PREINTERNED: u8 = 2; +const SYMBOL_PREDEFINED: u8 = 2; pub fn provide(providers: &mut Providers) { encoder::provide(providers); diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index aef56ea46e95..d1bbb0598fec 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -28,7 +28,7 @@ macro_rules! arena_types { rustc_middle::mir::Body<'tcx> >, [decode] typeck_results: rustc_middle::ty::TypeckResults<'tcx>, - [decode] borrowck_result: rustc_middle::mir::BorrowCheckResult<'tcx>, + [decode] borrowck_result: rustc_middle::mir::ConcreteOpaqueTypes<'tcx>, [] resolver: rustc_data_structures::steal::Steal<( rustc_middle::ty::ResolverAstLowering, std::sync::Arc, @@ -89,7 +89,6 @@ macro_rules! arena_types { [] name_set: rustc_data_structures::unord::UnordSet, [] autodiff_item: rustc_ast::expand::autodiff_attrs::AutoDiffItem, [] ordered_name_set: rustc_data_structures::fx::FxIndexSet, - [] pats: rustc_middle::ty::PatternKind<'tcx>, [] valtree: rustc_middle::ty::ValTreeKind<'tcx>, // Note that this deliberately duplicates items in the `rustc_hir::arena`, diff --git a/compiler/rustc_middle/src/hir/map.rs b/compiler/rustc_middle/src/hir/map.rs index 21ab06c98a77..fee707f7b4c9 100644 --- a/compiler/rustc_middle/src/hir/map.rs +++ b/compiler/rustc_middle/src/hir/map.rs @@ -1,3 +1,7 @@ +//! This module used to contain a type called `Map`. That type has since been +//! eliminated, and all its methods are now on `TyCtxt`. But the module name +//! stays as `map` because there isn't an obviously better name for it. + use rustc_abi::ExternAbi; use rustc_ast::visit::{VisitorResult, walk_list}; use rustc_data_structures::fingerprint::Fingerprint; @@ -18,16 +22,6 @@ use crate::middle::debugger_visualizer::DebuggerVisualizerFile; use crate::query::LocalCrate; use crate::ty::TyCtxt; -// FIXME: the structure was necessary in the past but now it -// only serves as "namespace" for HIR-related methods, and can be -// removed if all the methods are reasonably renamed and moved to tcx -// (https://github.com/rust-lang/rust/pull/118256#issuecomment-1826442834). -#[allow(unused)] // FIXME: temporary -#[derive(Copy, Clone)] -pub struct Map<'hir> { - pub(super) tcx: TyCtxt<'hir>, -} - /// An iterator that walks up the ancestor tree of a given `HirId`. /// Constructed using `tcx.hir_parent_iter(hir_id)`. struct ParentHirIterator<'tcx> { @@ -281,7 +275,7 @@ impl<'tcx> TyCtxt<'tcx> { }) } - pub fn hir_body_param_names(self, id: BodyId) -> impl Iterator> { + pub fn hir_body_param_idents(self, id: BodyId) -> impl Iterator> { self.hir_body(id).params.iter().map(|param| match param.pat.kind { PatKind::Binding(_, _, ident, _) => Some(ident), PatKind::Wild => Some(Ident::new(kw::Underscore, param.pat.span)), @@ -335,7 +329,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Returns an iterator of the `DefId`s for all body-owners in this /// crate. If you would prefer to iterate over the bodies - /// themselves, you can do `self.hir().krate().body_ids.iter()`. + /// themselves, you can do `self.hir_crate(()).body_ids.iter()`. #[inline] pub fn hir_body_owners(self) -> impl Iterator { self.hir_crate_items(()).body_owners.iter().copied() @@ -343,7 +337,7 @@ impl<'tcx> TyCtxt<'tcx> { #[inline] pub fn par_hir_body_owners(self, f: impl Fn(LocalDefId) + DynSend + DynSync) { - par_for_each_in(&self.hir_crate_items(()).body_owners[..], |&def_id| f(def_id)); + par_for_each_in(&self.hir_crate_items(()).body_owners[..], |&&def_id| f(def_id)); } pub fn hir_ty_param_owner(self, def_id: LocalDefId) -> LocalDefId { diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index 74369b6636c0..a28dcb0cb8ef 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -83,44 +83,39 @@ impl ModuleItems { &self, f: impl Fn(ItemId) -> Result<(), ErrorGuaranteed> + DynSend + DynSync, ) -> Result<(), ErrorGuaranteed> { - try_par_for_each_in(&self.free_items[..], |&id| f(id)) + try_par_for_each_in(&self.free_items[..], |&&id| f(id)) } pub fn par_trait_items( &self, f: impl Fn(TraitItemId) -> Result<(), ErrorGuaranteed> + DynSend + DynSync, ) -> Result<(), ErrorGuaranteed> { - try_par_for_each_in(&self.trait_items[..], |&id| f(id)) + try_par_for_each_in(&self.trait_items[..], |&&id| f(id)) } pub fn par_impl_items( &self, f: impl Fn(ImplItemId) -> Result<(), ErrorGuaranteed> + DynSend + DynSync, ) -> Result<(), ErrorGuaranteed> { - try_par_for_each_in(&self.impl_items[..], |&id| f(id)) + try_par_for_each_in(&self.impl_items[..], |&&id| f(id)) } pub fn par_foreign_items( &self, f: impl Fn(ForeignItemId) -> Result<(), ErrorGuaranteed> + DynSend + DynSync, ) -> Result<(), ErrorGuaranteed> { - try_par_for_each_in(&self.foreign_items[..], |&id| f(id)) + try_par_for_each_in(&self.foreign_items[..], |&&id| f(id)) } pub fn par_opaques( &self, f: impl Fn(LocalDefId) -> Result<(), ErrorGuaranteed> + DynSend + DynSync, ) -> Result<(), ErrorGuaranteed> { - try_par_for_each_in(&self.opaques[..], |&id| f(id)) + try_par_for_each_in(&self.opaques[..], |&&id| f(id)) } } impl<'tcx> TyCtxt<'tcx> { - #[inline(always)] - pub fn hir(self) -> map::Map<'tcx> { - map::Map { tcx: self } - } - pub fn parent_module(self, id: HirId) -> LocalModDefId { if !id.is_owner() && self.def_kind(id.owner) == DefKind::Mod { LocalModDefId::new_unchecked(id.owner.def_id) @@ -215,9 +210,9 @@ pub fn provide(providers: &mut Providers) { let hir_id = tcx.local_def_id_to_hir_id(def_id); tcx.hir_opt_ident_span(hir_id) }; - providers.fn_arg_names = |tcx, def_id| { + providers.fn_arg_idents = |tcx, def_id| { if let Some(body_id) = tcx.hir_node_by_def_id(def_id).body_id() { - tcx.arena.alloc_from_iter(tcx.hir_body_param_names(body_id)) + tcx.arena.alloc_from_iter(tcx.hir_body_param_idents(body_id)) } else if let Node::TraitItem(&TraitItem { kind: TraitItemKind::Fn(_, TraitFn::Required(idents)), .. @@ -231,7 +226,7 @@ pub fn provide(providers: &mut Providers) { } else { span_bug!( tcx.hir_span(tcx.local_def_id_to_hir_id(def_id)), - "fn_arg_names: unexpected item {:?}", + "fn_arg_idents: unexpected item {:?}", def_id ); } diff --git a/compiler/rustc_middle/src/hir/place.rs b/compiler/rustc_middle/src/hir/place.rs index 60ce8544aa0e..c3d10615cf10 100644 --- a/compiler/rustc_middle/src/hir/place.rs +++ b/compiler/rustc_middle/src/hir/place.rs @@ -40,6 +40,8 @@ pub enum ProjectionKind { /// A conversion from an opaque type to its hidden type so we can /// do further projections on it. + /// + /// This is unused if `-Znext-solver` is enabled. OpaqueCast, } diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs index 3cd148cd4427..5b8603744961 100644 --- a/compiler/rustc_middle/src/infer/canonical.rs +++ b/compiler/rustc_middle/src/infer/canonical.rs @@ -39,15 +39,6 @@ pub type CanonicalVarInfo<'tcx> = ir::CanonicalVarInfo>; pub type CanonicalVarValues<'tcx> = ir::CanonicalVarValues>; pub type CanonicalVarInfos<'tcx> = &'tcx List>; -impl<'tcx> ty::TypeFoldable> for CanonicalVarInfos<'tcx> { - fn try_fold_with>>( - self, - folder: &mut F, - ) -> Result { - ty::util::fold_list(self, folder, |tcx, v| tcx.mk_canonical_var_infos(v)) - } -} - /// When we canonicalize a value to form a query, we wind up replacing /// various parts of it with canonical variables. This struct stores /// those replaced bits to remember for when we process the query diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index 1e6178144c92..8fe2cc7101ba 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -29,7 +29,6 @@ #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::potential_query_instability)] #![allow(rustc::untranslatable_diagnostic)] -#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(allocator_api)] diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 4dfb362f3a22..db19c858e7c1 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -1636,8 +1636,8 @@ pub fn find_self_call<'tcx>( &body[block].terminator && let Operand::Constant(box ConstOperand { const_, .. }) = func && let ty::FnDef(def_id, fn_args) = *const_.ty().kind() - && let Some(ty::AssocItem { fn_has_self_parameter: true, .. }) = - tcx.opt_associated_item(def_id) + && let Some(item) = tcx.opt_associated_item(def_id) + && item.is_method() && let [Spanned { node: Operand::Move(self_place) | Operand::Copy(self_place), .. }, ..] = **args { diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 5a038b27337c..d57019fee0f9 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -531,12 +531,12 @@ fn write_mir_intro<'tcx>( // construct a scope tree and write it out let mut scope_tree: FxHashMap> = Default::default(); - for (index, scope_data) in body.source_scopes.iter().enumerate() { + for (index, scope_data) in body.source_scopes.iter_enumerated() { if let Some(parent) = scope_data.parent_scope { - scope_tree.entry(parent).or_default().push(SourceScope::new(index)); + scope_tree.entry(parent).or_default().push(index); } else { // Only the argument scope has no parent, because it's the root. - assert_eq!(index, OUTERMOST_SOURCE_SCOPE.index()); + assert_eq!(index, OUTERMOST_SOURCE_SCOPE); } } @@ -859,7 +859,7 @@ impl Debug for Statement<'_> { BackwardIncompatibleDropHint { ref place, reason: _ } => { // For now, we don't record the reason because there is only one use case, // which is to report breaking change in drop order by Edition 2024 - write!(fmt, "backward incompatible drop({place:?})") + write!(fmt, "BackwardIncompatibleDropHint({place:?})") } } } diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index 5a9fe10938ae..3fc05f2caf2a 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -6,14 +6,13 @@ use rustc_abi::{FieldIdx, VariantIdx}; use rustc_data_structures::fx::FxIndexMap; use rustc_errors::ErrorGuaranteed; use rustc_hir::def_id::LocalDefId; +use rustc_index::IndexVec; use rustc_index::bit_set::BitMatrix; -use rustc_index::{Idx, IndexVec}; use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; use rustc_span::{Span, Symbol}; -use smallvec::SmallVec; use super::{ConstValue, SourceInfo}; -use crate::ty::{self, CoroutineArgsExt, OpaqueHiddenType, Ty, TyCtxt, fold_regions}; +use crate::ty::{self, CoroutineArgsExt, OpaqueHiddenType, Ty}; rustc_index::newtype_index! { #[derive(HashStable)] @@ -85,16 +84,11 @@ impl Debug for CoroutineLayout<'_> { } } -#[derive(Debug, TyEncodable, TyDecodable, HashStable)] -pub struct BorrowCheckResult<'tcx> { - /// All the opaque types that are restricted to concrete types - /// by this function. Unlike the value in `TypeckResults`, this has - /// unerased regions. - pub concrete_opaque_types: FxIndexMap>, - pub closure_requirements: Option>, - pub used_mut_upvars: SmallVec<[FieldIdx; 8]>, - pub tainted_by_errors: Option, -} +/// All the opaque types that are restricted to concrete types +/// by this function. Unlike the value in `TypeckResults`, this has +/// unerased regions. +#[derive(Default, Debug, TyEncodable, TyDecodable, HashStable)] +pub struct ConcreteOpaqueTypes<'tcx>(pub FxIndexMap>); /// The result of the `mir_const_qualif` query. /// @@ -108,84 +102,6 @@ pub struct ConstQualifs { pub needs_non_const_drop: bool, pub tainted_by_errors: Option, } - -/// After we borrow check a closure, we are left with various -/// requirements that we have inferred between the free regions that -/// appear in the closure's signature or on its field types. These -/// requirements are then verified and proved by the closure's -/// creating function. This struct encodes those requirements. -/// -/// The requirements are listed as being between various `RegionVid`. The 0th -/// region refers to `'static`; subsequent region vids refer to the free -/// regions that appear in the closure (or coroutine's) type, in order of -/// appearance. (This numbering is actually defined by the `UniversalRegions` -/// struct in the NLL region checker. See for example -/// `UniversalRegions::closure_mapping`.) Note the free regions in the -/// closure's signature and captures are erased. -/// -/// Example: If type check produces a closure with the closure args: -/// -/// ```text -/// ClosureArgs = [ -/// 'a, // From the parent. -/// 'b, -/// i8, // the "closure kind" -/// for<'x> fn(&' &'x u32) -> &'x u32, // the "closure signature" -/// &' String, // some upvar -/// ] -/// ``` -/// -/// We would "renumber" each free region to a unique vid, as follows: -/// -/// ```text -/// ClosureArgs = [ -/// '1, // From the parent. -/// '2, -/// i8, // the "closure kind" -/// for<'x> fn(&'3 &'x u32) -> &'x u32, // the "closure signature" -/// &'4 String, // some upvar -/// ] -/// ``` -/// -/// Now the code might impose a requirement like `'1: '2`. When an -/// instance of the closure is created, the corresponding free regions -/// can be extracted from its type and constrained to have the given -/// outlives relationship. -#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)] -pub struct ClosureRegionRequirements<'tcx> { - /// The number of external regions defined on the closure. In our - /// example above, it would be 3 -- one for `'static`, then `'1` - /// and `'2`. This is just used for a sanity check later on, to - /// make sure that the number of regions we see at the callsite - /// matches. - pub num_external_vids: usize, - - /// Requirements between the various free regions defined in - /// indices. - pub outlives_requirements: Vec>, -} - -/// Indicates an outlives-constraint between a type or between two -/// free regions declared on the closure. -#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)] -pub struct ClosureOutlivesRequirement<'tcx> { - // This region or type ... - pub subject: ClosureOutlivesSubject<'tcx>, - - // ... must outlive this one. - pub outlived_free_region: ty::RegionVid, - - // If not, report an error here ... - pub blame_span: Span, - - // ... due to this reason. - pub category: ConstraintCategory<'tcx>, -} - -// Make sure this enum doesn't unintentionally grow -#[cfg(target_pointer_width = "64")] -rustc_data_structures::static_assert_size!(ConstraintCategory<'_>, 16); - /// Outlives-constraints can be categorized to determine whether and why they /// are interesting (for error reporting). Order of variants indicates sort /// order of the category, thereby influencing diagnostic output. @@ -253,66 +169,6 @@ pub enum AnnotationSource { GenericArg, } -/// The subject of a `ClosureOutlivesRequirement` -- that is, the thing -/// that must outlive some region. -#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)] -pub enum ClosureOutlivesSubject<'tcx> { - /// Subject is a type, typically a type parameter, but could also - /// be a projection. Indicates a requirement like `T: 'a` being - /// passed to the caller, where the type here is `T`. - Ty(ClosureOutlivesSubjectTy<'tcx>), - - /// Subject is a free region from the closure. Indicates a requirement - /// like `'a: 'b` being passed to the caller; the region here is `'a`. - Region(ty::RegionVid), -} - -/// Represents a `ty::Ty` for use in [`ClosureOutlivesSubject`]. -/// -/// This abstraction is necessary because the type may include `ReVar` regions, -/// which is what we use internally within NLL code, and they can't be used in -/// a query response. -/// -/// DO NOT implement `TypeVisitable` or `TypeFoldable` traits, because this -/// type is not recognized as a binder for late-bound region. -#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)] -pub struct ClosureOutlivesSubjectTy<'tcx> { - inner: Ty<'tcx>, -} - -impl<'tcx> ClosureOutlivesSubjectTy<'tcx> { - /// All regions of `ty` must be of kind `ReVar` and must represent - /// universal regions *external* to the closure. - pub fn bind(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Self { - let inner = fold_regions(tcx, ty, |r, depth| match r.kind() { - ty::ReVar(vid) => { - let br = ty::BoundRegion { - var: ty::BoundVar::new(vid.index()), - kind: ty::BoundRegionKind::Anon, - }; - ty::Region::new_bound(tcx, depth, br) - } - _ => bug!("unexpected region in ClosureOutlivesSubjectTy: {r:?}"), - }); - - Self { inner } - } - - pub fn instantiate( - self, - tcx: TyCtxt<'tcx>, - mut map: impl FnMut(ty::RegionVid) -> ty::Region<'tcx>, - ) -> Ty<'tcx> { - fold_regions(tcx, self.inner, |r, depth| match r.kind() { - ty::ReBound(debruijn, br) => { - debug_assert_eq!(debruijn, depth); - map(ty::RegionVid::new(br.var.index())) - } - _ => bug!("unexpected region {r:?}"), - }) - } -} - /// The constituent parts of a mir constant of kind ADT or array. #[derive(Copy, Clone, Debug, HashStable)] pub struct DestructuredConstant<'tcx> { diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index 707c8d04d557..304b3caa6e19 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -652,6 +652,8 @@ pub enum CallSource { /// Other types of desugaring that did not come from the HIR, but we don't care about /// for diagnostics (yet). Misc, + /// Use of value, generating a clone function call + Use, /// Normal function call, no special source Normal, } @@ -929,6 +931,8 @@ pub enum TerminatorKind<'tcx> { asm_macro: InlineAsmMacro, /// The template for the inline assembly, with placeholders. + #[type_foldable(identity)] + #[type_visitable(ignore)] template: &'tcx [InlineAsmTemplatePiece], /// The operands for the inline assembly, as `Operand`s or `Place`s. @@ -939,6 +943,8 @@ pub enum TerminatorKind<'tcx> { /// 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. + #[type_foldable(identity)] + #[type_visitable(ignore)] line_spans: &'tcx [Span], /// Valid targets for the inline assembly. @@ -1236,6 +1242,8 @@ pub enum ProjectionElem { /// Like an explicit cast from an opaque type to a concrete type, but without /// requiring an intermediate variable. + /// + /// This is unused with `-Znext-solver`. OpaqueCast(T), /// A transmute from an unsafe binder to the type that it wraps. This is a projection diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs index b2c51ad88645..82e8422c52dc 100644 --- a/compiler/rustc_middle/src/mir/terminator.rs +++ b/compiler/rustc_middle/src/mir/terminator.rs @@ -454,7 +454,7 @@ mod helper { /// Like [`SwitchTargets::target_for_value`], but returning the same type as /// [`Terminator::successors`]. #[inline] - #[cfg_attr(not(bootstrap), define_opaque(Successors))] + #[define_opaque(Successors)] pub fn successors_for_value(&self, value: u128) -> Successors<'_> { let target = self.target_for_value(value); (&[]).into_iter().copied().chain(Some(target)) @@ -463,7 +463,7 @@ mod helper { impl<'tcx> TerminatorKind<'tcx> { #[inline] - #[cfg_attr(not(bootstrap), define_opaque(Successors))] + #[define_opaque(Successors)] pub fn successors(&self) -> Successors<'_> { use self::TerminatorKind::*; match *self { @@ -502,7 +502,7 @@ mod helper { } #[inline] - #[cfg_attr(not(bootstrap), define_opaque(SuccessorsMut))] + #[define_opaque(SuccessorsMut)] pub fn successors_mut(&mut self) -> SuccessorsMut<'_> { use self::TerminatorKind::*; match *self { diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 3c83d962900a..de4d5140e857 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -457,9 +457,15 @@ macro_rules! make_mir_visitor { } } } + StatementKind::BackwardIncompatibleDropHint { place, .. } => { + self.visit_place( + place, + PlaceContext::NonUse(NonUseContext::BackwardIncompatibleDropHint), + location + ); + } StatementKind::ConstEvalCounter => {} StatementKind::Nop => {} - StatementKind::BackwardIncompatibleDropHint { .. } => {} } } @@ -1348,6 +1354,8 @@ pub enum NonUseContext { AscribeUserTy(ty::Variance), /// The data of a user variable, for debug info. VarDebugInfo, + /// A `BackwardIncompatibleDropHint` statement, meant for edition 2024 lints. + BackwardIncompatibleDropHint, } #[derive(Copy, Clone, Debug, PartialEq, Eq)] @@ -1422,7 +1430,9 @@ impl PlaceContext { use NonUseContext::*; match self { PlaceContext::MutatingUse(_) => ty::Invariant, - PlaceContext::NonUse(StorageDead | StorageLive | VarDebugInfo) => ty::Invariant, + PlaceContext::NonUse( + StorageDead | StorageLive | VarDebugInfo | BackwardIncompatibleDropHint, + ) => ty::Invariant, PlaceContext::NonMutatingUse( Inspect | Copy | Move | PlaceMention | SharedBorrow | FakeBorrow | RawBorrow | Projection, diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index 6c6b9a5510c6..5bd111fa2f22 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -25,7 +25,7 @@ pub trait EraseType: Copy { pub type Erase = Erased; #[inline(always)] -#[cfg_attr(not(bootstrap), define_opaque(Erase))] +#[define_opaque(Erase)] pub fn erase(src: T) -> Erase { // Ensure the sizes match const { @@ -49,7 +49,7 @@ pub fn erase(src: T) -> Erase { /// Restores an erased value. #[inline(always)] -#[cfg_attr(not(bootstrap), define_opaque(Erase))] +#[define_opaque(Erase)] pub fn restore(value: Erase) -> T { let value: Erased<::Result> = value; // See comment in `erase` for why we use `transmute_unchecked`. diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 0d5fba3cc69b..e94f088304b1 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -161,11 +161,11 @@ rustc_queries! { /// Represents crate as a whole (as distinct from the top-level crate module). /// - /// If you call `hir_crate` (e.g., indirectly by calling `tcx.hir_crate()`), - /// we will have to assume that any change means that you need to be recompiled. - /// This is because the `hir_crate` query gives you access to all other items. - /// To avoid this fate, do not call `tcx.hir_crate()`; instead, - /// prefer wrappers like [`TyCtxt::hir_visit_all_item_likes_in_crate`]. + /// If you call `tcx.hir_crate(())` we will have to assume that any change + /// means that you need to be recompiled. This is because the `hir_crate` + /// query gives you access to all other items. To avoid this fate, do not + /// call `tcx.hir_crate(())`; instead, prefer wrappers like + /// [`TyCtxt::hir_visit_all_item_likes_in_crate`]. query hir_crate(key: ()) -> &'tcx Crate<'tcx> { arena_cache eval_always @@ -197,7 +197,7 @@ rustc_queries! { /// Gives access to the HIR node's parent for the HIR owner `key`. /// - /// This can be conveniently accessed by methods on `tcx.hir()`. + /// This can be conveniently accessed by `tcx.hir_*` methods. /// Avoid calling this query directly. query hir_owner_parent(key: hir::OwnerId) -> hir::HirId { desc { |tcx| "getting HIR parent of `{}`", tcx.def_path_str(key) } @@ -205,7 +205,7 @@ rustc_queries! { /// Gives access to the HIR nodes and bodies inside `key` if it's a HIR owner. /// - /// This can be conveniently accessed by methods on `tcx.hir()`. + /// This can be conveniently accessed by `tcx.hir_*` methods. /// Avoid calling this query directly. query opt_hir_owner_nodes(key: LocalDefId) -> Option<&'tcx hir::OwnerNodes<'tcx>> { desc { |tcx| "getting HIR owner items in `{}`", tcx.def_path_str(key) } @@ -214,7 +214,7 @@ rustc_queries! { /// Gives access to the HIR attributes inside the HIR owner `key`. /// - /// This can be conveniently accessed by methods on `tcx.hir()`. + /// This can be conveniently accessed by `tcx.hir_*` methods. /// Avoid calling this query directly. query hir_attr_map(key: hir::OwnerId) -> &'tcx hir::AttributeMap<'tcx> { desc { |tcx| "getting HIR owner attributes in `{}`", tcx.def_path_str(key) } @@ -484,7 +484,7 @@ rustc_queries! { desc { "computing `#[expect]`ed lints in this crate" } } - query lints_that_dont_need_to_run(_: ()) -> &'tcx FxIndexSet { + query lints_that_dont_need_to_run(_: ()) -> &'tcx UnordSet { arena_cache desc { "Computing all lints that are explicitly enabled or with a default level greater than Allow" } } @@ -1026,6 +1026,13 @@ rustc_queries! { separate_provide_extern } + /// Given an `impl_def_id`, return true if the self type is guaranteed to be unsized due + /// to either being one of the built-in unsized types (str/slice/dyn) or to be a struct + /// whose tail is one of those types. + query impl_self_is_guaranteed_unsized(impl_def_id: DefId) -> bool { + desc { |tcx| "computing whether `{}` has a guaranteed unsized self type", tcx.def_path_str(impl_def_id) } + } + /// Maps a `DefId` of a type to a list of its inherent impls. /// Contains implementations of methods that are inherent to a type. /// Methods in these implementations don't need to be exported. @@ -1153,11 +1160,10 @@ rustc_queries! { return_result_from_ensure_ok } - /// Borrow-checks the function body. If this is a closure, returns - /// additional requirements that the closure's creator must verify. - query mir_borrowck(key: LocalDefId) -> &'tcx mir::BorrowCheckResult<'tcx> { + /// Borrow-checks the given typeck root, e.g. functions, const/static items, + /// and its children, e.g. closures, inline consts. + query mir_borrowck(key: LocalDefId) -> Result<&'tcx mir::ConcreteOpaqueTypes<'tcx>, ErrorGuaranteed> { desc { |tcx| "borrow-checking `{}`", tcx.def_path_str(key) } - cache_on_disk_if(tcx) { tcx.is_typeck_child(key.to_def_id()) } } /// Gets a complete map from all types to their inherent impls. @@ -1436,8 +1442,8 @@ rustc_queries! { desc { |tcx| "computing target features for inline asm of `{}`", tcx.def_path_str(def_id) } } - query fn_arg_names(def_id: DefId) -> &'tcx [Option] { - desc { |tcx| "looking up function parameter names for `{}`", tcx.def_path_str(def_id) } + query fn_arg_idents(def_id: DefId) -> &'tcx [Option] { + desc { |tcx| "looking up function parameter identifiers for `{}`", tcx.def_path_str(def_id) } separate_provide_extern } @@ -1894,6 +1900,11 @@ rustc_queries! { // The macro which defines `rustc_metadata::provide_extern` depends on this query's name. // Changing the name should cause a compiler error, but in case that changes, be aware. + // + // The hash should not be calculated before the `analysis` pass is complete, specifically + // until `tcx.untracked().definitions.freeze()` has been called, otherwise if incremental + // compilation is enabled calculating this hash can freeze this structure too early in + // compilation and cause subsequent crashes when attempting to write to `definitions` query crate_hash(_: CrateNum) -> Svh { eval_always desc { "looking up the hash a crate" } diff --git a/compiler/rustc_middle/src/query/on_disk_cache.rs b/compiler/rustc_middle/src/query/on_disk_cache.rs index c6ecc679b7b3..5431097cb1d7 100644 --- a/compiler/rustc_middle/src/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/query/on_disk_cache.rs @@ -16,8 +16,7 @@ use rustc_serialize::opaque::{FileEncodeResult, FileEncoder, IntEncodedWithFixed use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use rustc_session::Session; use rustc_span::hygiene::{ - ExpnId, HygieneDecodeContext, HygieneEncodeContext, SyntaxContext, - SyntaxContextDataNonRecursive as SyntaxContextData, + ExpnId, HygieneDecodeContext, HygieneEncodeContext, SyntaxContext, SyntaxContextKey, }; use rustc_span::source_map::Spanned; use rustc_span::{ @@ -46,7 +45,7 @@ const TAG_EXPN_DATA: u8 = 1; // Tags for encoding Symbol's const SYMBOL_STR: u8 = 0; const SYMBOL_OFFSET: u8 = 1; -const SYMBOL_PREINTERNED: u8 = 2; +const SYMBOL_PREDEFINED: u8 = 2; /// Provides an interface to incremental compilation data cached from the /// previous compilation session. This data will eventually include the results @@ -567,7 +566,7 @@ impl<'a, 'tcx> SpanDecoder for CacheDecoder<'a, 'tcx> { // We look up the position of the associated `SyntaxData` and decode it. let pos = syntax_contexts.get(&id).unwrap(); this.with_position(pos.to_usize(), |decoder| { - let data: SyntaxContextData = decode_tagged(decoder, TAG_SYNTAX_CONTEXT); + let data: SyntaxContextKey = decode_tagged(decoder, TAG_SYNTAX_CONTEXT); data }) }) @@ -674,9 +673,9 @@ impl<'a, 'tcx> SpanDecoder for CacheDecoder<'a, 'tcx> { Symbol::intern(s) }) } - SYMBOL_PREINTERNED => { + SYMBOL_PREDEFINED => { let symbol_index = self.read_u32(); - Symbol::new_from_decoded(symbol_index) + Symbol::new(symbol_index) } _ => unreachable!(), } @@ -892,9 +891,9 @@ impl<'a, 'tcx> SpanEncoder for CacheEncoder<'a, 'tcx> { // copy&paste impl from rustc_metadata fn encode_symbol(&mut self, symbol: Symbol) { - // if symbol preinterned, emit tag and symbol index - if symbol.is_preinterned() { - self.encoder.emit_u8(SYMBOL_PREINTERNED); + // if symbol predefined, emit tag and symbol index + if symbol.is_predefined() { + self.encoder.emit_u8(SYMBOL_PREDEFINED); self.encoder.emit_u32(symbol.as_u32()); } else { // otherwise write it as string or as offset to it diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 8d373cb3b309..c168142fb1ec 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -747,6 +747,9 @@ pub struct Ascription<'tcx> { #[derive(Clone, Debug, HashStable, TypeVisitable)] pub enum PatKind<'tcx> { + /// A missing pattern, e.g. for an anonymous param in a bare fn like `fn f(u32)`. + Missing, + /// A wildcard pattern: `_`. Wild, @@ -812,23 +815,17 @@ pub enum PatKind<'tcx> { }, /// Pattern obtained by converting a constant (inline or named) to its pattern - /// representation using `const_to_pat`. + /// representation using `const_to_pat`. This is used for unsafety checking. ExpandedConstant { - /// [DefId] of the constant, we need this so that we have a - /// reference that can be used by unsafety checking to visit nested - /// unevaluated constants and for diagnostics. If the `DefId` doesn't - /// correspond to a local crate, it points at the `const` item. + /// [DefId] of the constant item. def_id: DefId, - /// If `false`, then `def_id` points at a `const` item, otherwise it - /// corresponds to a local inline const. - is_inline: bool, - /// If the inline constant is used in a range pattern, this subpattern - /// represents the range (if both ends are inline constants, there will - /// be multiple InlineConstant wrappers). + /// The pattern that the constant lowered to. /// - /// Otherwise, the actual pattern that the constant lowered to. As with - /// other constants, inline constants are matched structurally where - /// possible. + /// HACK: we need to keep the `DefId` of inline constants around for unsafety checking; + /// therefore when a range pattern contains inline constants, we re-wrap the range pattern + /// with the `ExpandedConstant` nodes that correspond to the range endpoints. Hence + /// `subpattern` may actually be a range pattern, and `def_id` be the constant for one of + /// its endpoints. subpattern: Box>, }, diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs index 7d62ab7970d0..f3da2a5cc8e4 100644 --- a/compiler/rustc_middle/src/thir/visit.rs +++ b/compiler/rustc_middle/src/thir/visit.rs @@ -250,7 +250,8 @@ pub(crate) fn for_each_immediate_subpat<'a, 'tcx>( mut callback: impl FnMut(&'a Pat<'tcx>), ) { match &pat.kind { - PatKind::Wild + PatKind::Missing + | PatKind::Wild | PatKind::Binding { subpattern: None, .. } | PatKind::Constant { value: _ } | PatKind::Range(_) diff --git a/compiler/rustc_middle/src/ty/adjustment.rs b/compiler/rustc_middle/src/ty/adjustment.rs index f8ab555305f0..a61a6c571a2c 100644 --- a/compiler/rustc_middle/src/ty/adjustment.rs +++ b/compiler/rustc_middle/src/ty/adjustment.rs @@ -5,7 +5,7 @@ use rustc_hir::lang_items::LangItem; use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; use rustc_span::Span; -use crate::ty::{self, Ty, TyCtxt}; +use crate::ty::{Ty, TyCtxt}; #[derive(Clone, Copy, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)] pub enum PointerCoercion { @@ -133,7 +133,7 @@ impl OverloadedDeref { }; tcx.associated_items(trait_def_id) .in_definition_order() - .find(|m| m.kind == ty::AssocKind::Fn) + .find(|item| item.is_fn()) .unwrap() .def_id } @@ -214,3 +214,25 @@ pub enum CustomCoerceUnsized { /// Records the index of the field being coerced. Struct(FieldIdx), } + +/// Represents an implicit coercion applied to the scrutinee of a match before testing a pattern +/// against it. Currently, this is used only for implicit dereferences. +#[derive(Clone, Copy, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] +pub struct PatAdjustment<'tcx> { + pub kind: PatAdjust, + /// The type of the scrutinee before the adjustment is applied, or the "adjusted type" of the + /// pattern. + pub source: Ty<'tcx>, +} + +/// Represents implicit coercions of patterns' types, rather than values' types. +#[derive(Clone, Copy, PartialEq, Debug, TyEncodable, TyDecodable, HashStable)] +#[derive(TypeFoldable, TypeVisitable)] +pub enum PatAdjust { + /// An implicit dereference before matching, such as when matching the pattern `0` against a + /// scrutinee of type `&u8` or `&mut u8`. + BuiltinDeref, + /// An implicit call to `Deref(Mut)::deref(_mut)` before matching, such as when matching the + /// pattern `[..]` against a scrutinee of type `Vec`. + OverloadedDeref, +} diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index 00fe5cb0c5d6..66517c97a687 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -53,6 +53,10 @@ bitflags::bitflags! { const IS_VARIANT_LIST_NON_EXHAUSTIVE = 1 << 8; /// Indicates whether the type is `UnsafeCell`. const IS_UNSAFE_CELL = 1 << 9; + /// Indicates whether the type is `UnsafePinned`. + const IS_UNSAFE_PINNED = 1 << 10; + /// Indicates whether the type is anonymous. + const IS_ANONYMOUS = 1 << 11; } } rustc_data_structures::external_bitflags_debug! { AdtFlags } @@ -302,6 +306,9 @@ impl AdtDefData { if tcx.is_lang_item(did, LangItem::UnsafeCell) { flags |= AdtFlags::IS_UNSAFE_CELL; } + if tcx.is_lang_item(did, LangItem::UnsafePinned) { + flags |= AdtFlags::IS_UNSAFE_PINNED; + } AdtDefData { did, variants, flags, repr } } @@ -405,6 +412,12 @@ impl<'tcx> AdtDef<'tcx> { self.flags().contains(AdtFlags::IS_UNSAFE_CELL) } + /// Returns `true` if this is `UnsafePinned`. + #[inline] + pub fn is_unsafe_pinned(self) -> bool { + self.flags().contains(AdtFlags::IS_UNSAFE_PINNED) + } + /// Returns `true` if this is `ManuallyDrop`. #[inline] pub fn is_manually_drop(self) -> bool { diff --git a/compiler/rustc_middle/src/ty/assoc.rs b/compiler/rustc_middle/src/ty/assoc.rs index ce4c08aa485e..0c44fd2758d5 100644 --- a/compiler/rustc_middle/src/ty/assoc.rs +++ b/compiler/rustc_middle/src/ty/assoc.rs @@ -18,27 +18,33 @@ pub enum AssocItemContainer { #[derive(Copy, Clone, Debug, PartialEq, HashStable, Eq, Hash, Encodable, Decodable)] pub struct AssocItem { pub def_id: DefId, - pub name: Symbol, pub kind: AssocKind, pub container: AssocItemContainer, /// If this is an item in an impl of a trait then this is the `DefId` of /// the associated item on the trait that this implements. pub trait_item_def_id: Option, - - /// Whether this is a method with an explicit self - /// as its first parameter, allowing method calls. - pub fn_has_self_parameter: bool, - - /// `Some` if the associated item (an associated type) comes from the - /// return-position `impl Trait` in trait desugaring. The `ImplTraitInTraitData` - /// provides additional information about its source. - pub opt_rpitit_info: Option, } impl AssocItem { + // Gets the identifier, if it has one. + pub fn opt_name(&self) -> Option { + match self.kind { + ty::AssocKind::Type { data: AssocTypeData::Normal(name) } => Some(name), + ty::AssocKind::Type { data: AssocTypeData::Rpitit(_) } => None, + ty::AssocKind::Const { name } => Some(name), + ty::AssocKind::Fn { name, .. } => Some(name), + } + } + + // Gets the identifier name. Aborts if it lacks one, i.e. is an RPITIT + // associated type. + pub fn name(&self) -> Symbol { + self.opt_name().expect("name of non-Rpitit assoc item") + } + pub fn ident(&self, tcx: TyCtxt<'_>) -> Ident { - Ident::new(self.name, tcx.def_ident_span(self.def_id).unwrap()) + Ident::new(self.name(), tcx.def_ident_span(self.def_id).unwrap()) } /// Gets the defaultness of the associated item. @@ -78,35 +84,65 @@ impl AssocItem { pub fn signature(&self, tcx: TyCtxt<'_>) -> String { match self.kind { - ty::AssocKind::Fn => { + ty::AssocKind::Fn { .. } => { // We skip the binder here because the binder would deanonymize all // late-bound regions, and we don't want method signatures to show up // `as for<'r> fn(&'r MyType)`. Pretty-printing handles late-bound // regions just fine, showing `fn(&MyType)`. tcx.fn_sig(self.def_id).instantiate_identity().skip_binder().to_string() } - ty::AssocKind::Type => format!("type {};", self.name), - ty::AssocKind::Const => { - format!( - "const {}: {:?};", - self.name, - tcx.type_of(self.def_id).instantiate_identity() - ) + ty::AssocKind::Type { .. } => format!("type {};", self.name()), + ty::AssocKind::Const { name } => { + format!("const {}: {:?};", name, tcx.type_of(self.def_id).instantiate_identity()) } } } pub fn descr(&self) -> &'static str { match self.kind { - ty::AssocKind::Const => "const", - ty::AssocKind::Fn if self.fn_has_self_parameter => "method", - ty::AssocKind::Fn => "associated function", - ty::AssocKind::Type => "type", + ty::AssocKind::Const { .. } => "associated const", + ty::AssocKind::Fn { has_self: true, .. } => "method", + ty::AssocKind::Fn { has_self: false, .. } => "associated function", + ty::AssocKind::Type { .. } => "associated type", + } + } + + pub fn namespace(&self) -> Namespace { + match self.kind { + ty::AssocKind::Type { .. } => Namespace::TypeNS, + ty::AssocKind::Const { .. } | ty::AssocKind::Fn { .. } => Namespace::ValueNS, + } + } + + pub fn as_def_kind(&self) -> DefKind { + match self.kind { + AssocKind::Const { .. } => DefKind::AssocConst, + AssocKind::Fn { .. } => DefKind::AssocFn, + AssocKind::Type { .. } => DefKind::AssocTy, + } + } + pub fn is_type(&self) -> bool { + matches!(self.kind, ty::AssocKind::Type { .. }) + } + + pub fn is_fn(&self) -> bool { + matches!(self.kind, ty::AssocKind::Fn { .. }) + } + + pub fn is_method(&self) -> bool { + matches!(self.kind, ty::AssocKind::Fn { has_self: true, .. }) + } + + pub fn as_tag(&self) -> AssocTag { + match self.kind { + AssocKind::Const { .. } => AssocTag::Const, + AssocKind::Fn { .. } => AssocTag::Fn, + AssocKind::Type { .. } => AssocTag::Type, } } pub fn is_impl_trait_in_trait(&self) -> bool { - self.opt_rpitit_info.is_some() + matches!(self.kind, AssocKind::Type { data: AssocTypeData::Rpitit(_) }) } /// Returns true if: @@ -114,7 +150,7 @@ impl AssocItem { /// - If it is in a trait impl, the item from the original trait has this attribute, or /// - It is an inherent assoc const. pub fn is_type_const_capable(&self, tcx: TyCtxt<'_>) -> bool { - if self.kind != ty::AssocKind::Const { + if !matches!(self.kind, ty::AssocKind::Const { .. }) { return false; } @@ -128,26 +164,35 @@ impl AssocItem { } } +#[derive(Copy, Clone, PartialEq, Debug, HashStable, Eq, Hash, Encodable, Decodable)] +pub enum AssocTypeData { + Normal(Symbol), + /// The associated type comes from an RPITIT. It has no name, and the + /// `ImplTraitInTraitData` provides additional information about its + /// source. + Rpitit(ty::ImplTraitInTraitData), +} + #[derive(Copy, Clone, PartialEq, Debug, HashStable, Eq, Hash, Encodable, Decodable)] pub enum AssocKind { - Const, - Fn, - Type, + Const { name: Symbol }, + Fn { name: Symbol, has_self: bool }, + Type { data: AssocTypeData }, } impl AssocKind { pub fn namespace(&self) -> Namespace { match *self { - ty::AssocKind::Type => Namespace::TypeNS, - ty::AssocKind::Const | ty::AssocKind::Fn => Namespace::ValueNS, + ty::AssocKind::Type { .. } => Namespace::TypeNS, + ty::AssocKind::Const { .. } | ty::AssocKind::Fn { .. } => Namespace::ValueNS, } } pub fn as_def_kind(&self) -> DefKind { match self { - AssocKind::Const => DefKind::AssocConst, - AssocKind::Fn => DefKind::AssocFn, - AssocKind::Type => DefKind::AssocTy, + AssocKind::Const { .. } => DefKind::AssocConst, + AssocKind::Fn { .. } => DefKind::AssocFn, + AssocKind::Type { .. } => DefKind::AssocTy, } } } @@ -155,13 +200,22 @@ impl AssocKind { impl std::fmt::Display for AssocKind { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - AssocKind::Fn => write!(f, "method"), - AssocKind::Const => write!(f, "associated const"), - AssocKind::Type => write!(f, "associated type"), + AssocKind::Fn { has_self: true, .. } => write!(f, "method"), + AssocKind::Fn { has_self: false, .. } => write!(f, "associated function"), + AssocKind::Const { .. } => write!(f, "associated const"), + AssocKind::Type { .. } => write!(f, "associated type"), } } } +// Like `AssocKind`, but just the tag, no fields. Used in various kinds of matching. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum AssocTag { + Const, + Fn, + Type, +} + /// A list of `ty::AssocItem`s in definition order that allows for efficient lookup by name. /// /// When doing lookup by name, we try to postpone hygienic comparison for as long as possible since @@ -169,17 +223,17 @@ impl std::fmt::Display for AssocKind { /// done only on items with the same name. #[derive(Debug, Clone, PartialEq, HashStable)] pub struct AssocItems { - items: SortedIndexMultiMap, + items: SortedIndexMultiMap, ty::AssocItem>, } impl AssocItems { /// Constructs an `AssociatedItems` map from a series of `ty::AssocItem`s in definition order. pub fn new(items_in_def_order: impl IntoIterator) -> Self { - let items = items_in_def_order.into_iter().map(|item| (item.name, item)).collect(); + let items = items_in_def_order.into_iter().map(|item| (item.opt_name(), item)).collect(); AssocItems { items } } - /// Returns a slice of associated items in the order they were defined. + /// Returns an iterator over associated items in the order they were defined. /// /// New code should avoid relying on definition order. If you need a particular associated item /// for a known trait, make that trait a lang item instead of indexing this array. @@ -196,36 +250,27 @@ impl AssocItems { &self, name: Symbol, ) -> impl '_ + Iterator { - self.items.get_by_key(name) + assert!(!name.is_empty()); + self.items.get_by_key(Some(name)) } - /// Returns the associated item with the given name and `AssocKind`, if one exists. - pub fn find_by_name_and_kind( + /// Returns the associated item with the given identifier and `AssocKind`, if one exists. + /// The identifier is matched hygienically. + pub fn find_by_ident_and_kind( &self, tcx: TyCtxt<'_>, ident: Ident, - kind: AssocKind, + assoc_tag: AssocTag, parent_def_id: DefId, ) -> Option<&ty::AssocItem> { self.filter_by_name_unhygienic(ident.name) - .filter(|item| item.kind == kind) + .filter(|item| item.as_tag() == assoc_tag) .find(|item| tcx.hygienic_eq(ident, item.ident(tcx), parent_def_id)) } - /// Returns the associated item with the given name and any of `AssocKind`, if one exists. - pub fn find_by_name_and_kinds( - &self, - tcx: TyCtxt<'_>, - ident: Ident, - // Sorted in order of what kinds to look at - kinds: &[AssocKind], - parent_def_id: DefId, - ) -> Option<&ty::AssocItem> { - kinds.iter().find_map(|kind| self.find_by_name_and_kind(tcx, ident, *kind, parent_def_id)) - } - - /// Returns the associated item with the given name in the given `Namespace`, if one exists. - pub fn find_by_name_and_namespace( + /// Returns the associated item with the given identifier in the given `Namespace`, if one + /// exists. The identifier is matched hygienically. + pub fn find_by_ident_and_namespace( &self, tcx: TyCtxt<'_>, ident: Ident, @@ -233,7 +278,7 @@ impl AssocItems { parent_def_id: DefId, ) -> Option<&ty::AssocItem> { self.filter_by_name_unhygienic(ident.name) - .filter(|item| item.kind.namespace() == ns) + .filter(|item| item.namespace() == ns) .find(|item| tcx.hygienic_eq(ident, item.ident(tcx), parent_def_id)) } } diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index 74b34afe616b..23927c112bcd 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -501,7 +501,7 @@ impl_decodable_via_ref! { &'tcx ty::List>, &'tcx traits::ImplSource<'tcx, ()>, &'tcx mir::Body<'tcx>, - &'tcx mir::BorrowCheckResult<'tcx>, + &'tcx mir::ConcreteOpaqueTypes<'tcx>, &'tcx ty::List, &'tcx ty::ListWithCachedTypeInfo>, &'tcx ty::List, diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index ae1c6c670cbc..dc5fe2d8f8b0 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -3,6 +3,7 @@ use std::borrow::Cow; use rustc_data_structures::intern::Interned; use rustc_error_messages::MultiSpan; use rustc_macros::HashStable; +use rustc_type_ir::walk::TypeWalker; use rustc_type_ir::{self as ir, TypeFlags, WithCachedTypeInfo}; use crate::ty::{self, Ty, TyCtxt}; @@ -243,4 +244,18 @@ impl<'tcx> Const<'tcx> { pub fn is_ct_infer(self) -> bool { matches!(self.kind(), ty::ConstKind::Infer(_)) } + + /// Iterator that walks `self` and any types reachable from + /// `self`, in depth-first order. Note that just walks the types + /// that appear in `self`, it does not descend into the fields of + /// structs or variants. For example: + /// + /// ```text + /// isize => { isize } + /// Foo> => { Foo>, Bar, isize } + /// [isize] => { [isize], isize } + /// ``` + pub fn walk(self) -> TypeWalker> { + TypeWalker::new(self.into()) + } } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 162ca1f4af85..fa2f1cf1a1c8 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -437,6 +437,10 @@ impl<'tcx> Interner for TyCtxt<'tcx> { ) } + fn impl_self_is_guaranteed_unsized(self, impl_def_id: DefId) -> bool { + self.impl_self_is_guaranteed_unsized(impl_def_id) + } + fn has_target_features(self, def_id: DefId) -> bool { !self.codegen_fn_attrs(def_id).target_features.is_empty() } @@ -460,7 +464,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> { fn associated_type_def_ids(self, def_id: DefId) -> impl IntoIterator { self.associated_items(def_id) .in_definition_order() - .filter(|assoc_item| matches!(assoc_item.kind, ty::AssocKind::Type)) + .filter(|assoc_item| assoc_item.is_type()) .map(|assoc_item| assoc_item.def_id) } @@ -866,7 +870,7 @@ impl<'tcx> CtxtInterners<'tcx> { Ty(Interned::new_unchecked( self.type_ .intern(kind, |kind| { - let flags = super::flags::FlagComputation::for_kind(&kind); + let flags = ty::FlagComputation::>::for_kind(&kind); let stable_hash = self.stable_hash(&flags, sess, untracked, &kind); InternedInSet(self.arena.alloc(WithCachedTypeInfo { @@ -892,7 +896,7 @@ impl<'tcx> CtxtInterners<'tcx> { Const(Interned::new_unchecked( self.const_ .intern(kind, |kind: ty::ConstKind<'_>| { - let flags = super::flags::FlagComputation::for_const_kind(&kind); + let flags = ty::FlagComputation::>::for_const_kind(&kind); let stable_hash = self.stable_hash(&flags, sess, untracked, &kind); InternedInSet(self.arena.alloc(WithCachedTypeInfo { @@ -908,7 +912,7 @@ impl<'tcx> CtxtInterners<'tcx> { fn stable_hash<'a, T: HashStable>>( &self, - flags: &ty::flags::FlagComputation, + flags: &ty::FlagComputation>, sess: &'a Session, untracked: &'a Untracked, val: &T, @@ -936,7 +940,7 @@ impl<'tcx> CtxtInterners<'tcx> { Predicate(Interned::new_unchecked( self.predicate .intern(kind, |kind| { - let flags = super::flags::FlagComputation::for_predicate(kind); + let flags = ty::FlagComputation::>::for_predicate(kind); let stable_hash = self.stable_hash(&flags, sess, untracked, &kind); @@ -957,7 +961,7 @@ impl<'tcx> CtxtInterners<'tcx> { } else { self.clauses .intern_ref(clauses, || { - let flags = super::flags::FlagComputation::for_clauses(clauses); + let flags = ty::FlagComputation::>::for_clauses(clauses); InternedInSet(ListWithCachedTypeInfo::from_arena( &*self.arena, @@ -2143,7 +2147,7 @@ impl<'tcx> TyCtxt<'tcx> { return vec![]; }; - let mut v = TraitObjectVisitor(vec![], self.hir()); + let mut v = TraitObjectVisitor(vec![]); v.visit_ty_unambig(hir_output); v.0 } @@ -2156,7 +2160,7 @@ impl<'tcx> TyCtxt<'tcx> { scope_def_id: LocalDefId, ) -> Option<(Vec<&'tcx hir::Ty<'tcx>>, Span, Option)> { let hir_id = self.local_def_id_to_hir_id(scope_def_id); - let mut v = TraitObjectVisitor(vec![], self.hir()); + let mut v = TraitObjectVisitor(vec![]); // when the return type is a type alias if let Some(hir::FnDecl { output: hir::FnRetTy::Return(hir_output), .. }) = self.hir_fn_decl_by_hir_id(hir_id) && let hir::TyKind::Path(hir::QPath::Resolved( diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index d3abb3d64b8c..fbb57b8df6bb 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -571,15 +571,15 @@ pub fn suggest_constraining_type_params<'a>( } /// Collect al types that have an implicit `'static` obligation that we could suggest `'_` for. -pub struct TraitObjectVisitor<'tcx>(pub Vec<&'tcx hir::Ty<'tcx>>, pub crate::hir::map::Map<'tcx>); +pub(crate) struct TraitObjectVisitor<'tcx>(pub(crate) Vec<&'tcx hir::Ty<'tcx>>); impl<'v> hir::intravisit::Visitor<'v> for TraitObjectVisitor<'v> { fn visit_ty(&mut self, ty: &'v hir::Ty<'v, AmbigArg>) { match ty.kind { hir::TyKind::TraitObject(_, tagged_ptr) if let hir::Lifetime { - res: - hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Static, + kind: + hir::LifetimeKind::ImplicitObjectLifetimeDefault | hir::LifetimeKind::Static, .. } = tagged_ptr.pointer() => { @@ -592,18 +592,6 @@ impl<'v> hir::intravisit::Visitor<'v> for TraitObjectVisitor<'v> { } } -/// Collect al types that have an implicit `'static` obligation that we could suggest `'_` for. -pub struct StaticLifetimeVisitor<'tcx>(pub Vec, pub crate::hir::map::Map<'tcx>); - -impl<'v> hir::intravisit::Visitor<'v> for StaticLifetimeVisitor<'v> { - fn visit_lifetime(&mut self, lt: &'v hir::Lifetime) { - if let hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Static = lt.res - { - self.0.push(lt.ident.span); - } - } -} - pub struct IsSuggestableVisitor<'tcx> { tcx: TyCtxt<'tcx>, infer_suggestable: bool, diff --git a/compiler/rustc_middle/src/ty/erase_regions.rs b/compiler/rustc_middle/src/ty/erase_regions.rs index 8bddb5c0fd77..45a0b1288db8 100644 --- a/compiler/rustc_middle/src/ty/erase_regions.rs +++ b/compiler/rustc_middle/src/ty/erase_regions.rs @@ -65,7 +65,7 @@ impl<'tcx> TypeFolder> for RegionEraserVisitor<'tcx> { // We must not erase bound regions. `for<'a> fn(&'a ())` and // `fn(&'free ())` are different types: they may implement different // traits and have a different `TypeId`. - match *r { + match r.kind() { ty::ReBound(..) => r, _ => self.tcx.lifetimes.re_erased, } diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index a0e67929c528..5ecf1174defe 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -279,7 +279,7 @@ impl<'tcx> TyCtxt<'tcx> { p.hash(&mut s); let hash = s.finish(); *path = Some(path.take().unwrap_or_else(|| { - self.output_filenames(()).temp_path_ext(&format!("long-type-{hash}.txt"), None) + self.output_filenames(()).temp_path_for_diagnostic(&format!("long-type-{hash}.txt")) })); let Ok(mut file) = File::options().create(true).read(true).append(true).open(&path.as_ref().unwrap()) diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs deleted file mode 100644 index b0c442d28f0a..000000000000 --- a/compiler/rustc_middle/src/ty/flags.rs +++ /dev/null @@ -1,359 +0,0 @@ -use std::slice; - -use crate::ty::{self, GenericArg, GenericArgKind, InferConst, Ty, TypeFlags}; - -#[derive(Debug)] -pub struct FlagComputation { - pub flags: TypeFlags, - - /// see `Ty::outer_exclusive_binder` for details - pub outer_exclusive_binder: ty::DebruijnIndex, -} - -impl FlagComputation { - fn new() -> FlagComputation { - FlagComputation { flags: TypeFlags::empty(), outer_exclusive_binder: ty::INNERMOST } - } - - #[allow(rustc::usage_of_ty_tykind)] - pub fn for_kind(kind: &ty::TyKind<'_>) -> FlagComputation { - let mut result = FlagComputation::new(); - result.add_kind(kind); - result - } - - pub fn for_predicate(binder: ty::Binder<'_, ty::PredicateKind<'_>>) -> FlagComputation { - let mut result = FlagComputation::new(); - result.add_predicate(binder); - result - } - - pub fn for_const_kind(kind: &ty::ConstKind<'_>) -> FlagComputation { - let mut result = FlagComputation::new(); - result.add_const_kind(kind); - result - } - - pub fn for_clauses(clauses: &[ty::Clause<'_>]) -> FlagComputation { - let mut result = FlagComputation::new(); - for c in clauses { - result.add_flags(c.as_predicate().flags()); - result.add_exclusive_binder(c.as_predicate().outer_exclusive_binder()); - } - result - } - - fn add_flags(&mut self, flags: TypeFlags) { - self.flags = self.flags | flags; - } - - /// indicates that `self` refers to something at binding level `binder` - fn add_bound_var(&mut self, binder: ty::DebruijnIndex) { - let exclusive_binder = binder.shifted_in(1); - self.add_exclusive_binder(exclusive_binder); - } - - /// indicates that `self` refers to something *inside* binding - /// level `binder` -- not bound by `binder`, but bound by the next - /// binder internal to it - fn add_exclusive_binder(&mut self, exclusive_binder: ty::DebruijnIndex) { - self.outer_exclusive_binder = self.outer_exclusive_binder.max(exclusive_binder); - } - - /// Adds the flags/depth from a set of types that appear within the current type, but within a - /// region binder. - fn bound_computation(&mut self, value: ty::Binder<'_, T>, f: F) - where - F: FnOnce(&mut Self, T), - { - let mut computation = FlagComputation::new(); - - if !value.bound_vars().is_empty() { - computation.add_flags(TypeFlags::HAS_BINDER_VARS); - } - - f(&mut computation, value.skip_binder()); - - self.add_flags(computation.flags); - - // The types that contributed to `computation` occurred within - // a region binder, so subtract one from the region depth - // within when adding the depth to `self`. - let outer_exclusive_binder = computation.outer_exclusive_binder; - if outer_exclusive_binder > ty::INNERMOST { - self.add_exclusive_binder(outer_exclusive_binder.shifted_out(1)); - } // otherwise, this binder captures nothing - } - - #[allow(rustc::usage_of_ty_tykind)] - fn add_kind(&mut self, kind: &ty::TyKind<'_>) { - match kind { - &ty::Bool - | &ty::Char - | &ty::Int(_) - | &ty::Float(_) - | &ty::Uint(_) - | &ty::Never - | &ty::Str - | &ty::Foreign(..) => {} - - &ty::Error(_) => self.add_flags(TypeFlags::HAS_ERROR), - - &ty::Param(_) => { - self.add_flags(TypeFlags::HAS_TY_PARAM); - } - - &ty::Closure(_, args) - | &ty::Coroutine(_, args) - | &ty::CoroutineClosure(_, args) - | &ty::CoroutineWitness(_, args) => { - self.add_args(args); - } - - &ty::Bound(debruijn, _) => { - self.add_bound_var(debruijn); - self.add_flags(TypeFlags::HAS_TY_BOUND); - } - - &ty::Placeholder(..) => { - self.add_flags(TypeFlags::HAS_TY_PLACEHOLDER); - } - - &ty::Infer(infer) => match infer { - ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_) => { - self.add_flags(TypeFlags::HAS_TY_FRESH) - } - - ty::TyVar(_) | ty::IntVar(_) | ty::FloatVar(_) => { - self.add_flags(TypeFlags::HAS_TY_INFER) - } - }, - - &ty::Adt(_, args) => { - self.add_args(args); - } - - &ty::Alias(kind, data) => { - self.add_flags(match kind { - ty::Projection => TypeFlags::HAS_TY_PROJECTION, - ty::Weak => TypeFlags::HAS_TY_WEAK, - ty::Opaque => TypeFlags::HAS_TY_OPAQUE, - ty::Inherent => TypeFlags::HAS_TY_INHERENT, - }); - - self.add_alias_ty(data); - } - - &ty::Dynamic(obj, r, _) => { - for predicate in obj.iter() { - self.bound_computation(predicate, |computation, predicate| match predicate { - ty::ExistentialPredicate::Trait(tr) => computation.add_args(tr.args), - ty::ExistentialPredicate::Projection(p) => { - computation.add_existential_projection(&p); - } - ty::ExistentialPredicate::AutoTrait(_) => {} - }); - } - - self.add_region(r); - } - - &ty::Array(tt, len) => { - self.add_ty(tt); - self.add_const(len); - } - - &ty::Pat(ty, pat) => { - self.add_ty(ty); - match *pat { - ty::PatternKind::Range { start, end } => { - self.add_const(start); - self.add_const(end); - } - } - } - - &ty::Slice(tt) => self.add_ty(tt), - - &ty::RawPtr(ty, _) => { - self.add_ty(ty); - } - - &ty::Ref(r, ty, _) => { - self.add_region(r); - self.add_ty(ty); - } - - &ty::Tuple(types) => { - self.add_tys(types); - } - - &ty::FnDef(_, args) => { - self.add_args(args); - } - - &ty::FnPtr(sig_tys, _) => self.bound_computation(sig_tys, |computation, sig_tys| { - computation.add_tys(sig_tys.inputs_and_output); - }), - - &ty::UnsafeBinder(bound_ty) => { - self.bound_computation(bound_ty.into(), |computation, ty| { - computation.add_ty(ty); - }) - } - } - } - - fn add_predicate(&mut self, binder: ty::Binder<'_, ty::PredicateKind<'_>>) { - self.bound_computation(binder, |computation, atom| computation.add_predicate_atom(atom)); - } - - fn add_predicate_atom(&mut self, atom: ty::PredicateKind<'_>) { - match atom { - ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) => { - self.add_args(trait_pred.trait_ref.args); - } - ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(ty::HostEffectPredicate { - trait_ref, - constness: _, - })) => { - self.add_args(trait_ref.args); - } - ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate( - a, - b, - ))) => { - self.add_region(a); - self.add_region(b); - } - ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate( - ty, - region, - ))) => { - self.add_ty(ty); - self.add_region(region); - } - ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => { - self.add_const(ct); - self.add_ty(ty); - } - ty::PredicateKind::Subtype(ty::SubtypePredicate { a_is_expected: _, a, b }) => { - self.add_ty(a); - self.add_ty(b); - } - ty::PredicateKind::Coerce(ty::CoercePredicate { a, b }) => { - self.add_ty(a); - self.add_ty(b); - } - ty::PredicateKind::Clause(ty::ClauseKind::Projection(ty::ProjectionPredicate { - projection_term, - term, - })) => { - self.add_alias_term(projection_term); - self.add_term(term); - } - ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => { - self.add_args(slice::from_ref(&arg)); - } - ty::PredicateKind::DynCompatible(_def_id) => {} - ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(uv)) => { - self.add_const(uv); - } - ty::PredicateKind::ConstEquate(expected, found) => { - self.add_const(expected); - self.add_const(found); - } - ty::PredicateKind::Ambiguous => {} - ty::PredicateKind::NormalizesTo(ty::NormalizesTo { alias, term }) => { - self.add_alias_term(alias); - self.add_term(term); - } - ty::PredicateKind::AliasRelate(t1, t2, _) => { - self.add_term(t1); - self.add_term(t2); - } - } - } - - fn add_ty(&mut self, ty: Ty<'_>) { - self.add_flags(ty.flags()); - self.add_exclusive_binder(ty.outer_exclusive_binder()); - } - - fn add_tys(&mut self, tys: &[Ty<'_>]) { - for &ty in tys { - self.add_ty(ty); - } - } - - fn add_region(&mut self, r: ty::Region<'_>) { - self.add_flags(r.type_flags()); - if let ty::ReBound(debruijn, _) = *r { - self.add_bound_var(debruijn); - } - } - - fn add_const(&mut self, c: ty::Const<'_>) { - self.add_flags(c.flags()); - self.add_exclusive_binder(c.outer_exclusive_binder()); - } - - fn add_const_kind(&mut self, c: &ty::ConstKind<'_>) { - match *c { - ty::ConstKind::Unevaluated(uv) => { - self.add_args(uv.args); - self.add_flags(TypeFlags::HAS_CT_PROJECTION); - } - ty::ConstKind::Infer(infer) => match infer { - InferConst::Fresh(_) => self.add_flags(TypeFlags::HAS_CT_FRESH), - InferConst::Var(_) => self.add_flags(TypeFlags::HAS_CT_INFER), - }, - ty::ConstKind::Bound(debruijn, _) => { - self.add_bound_var(debruijn); - self.add_flags(TypeFlags::HAS_CT_BOUND); - } - ty::ConstKind::Param(_) => { - self.add_flags(TypeFlags::HAS_CT_PARAM); - } - ty::ConstKind::Placeholder(_) => { - self.add_flags(TypeFlags::HAS_CT_PLACEHOLDER); - } - ty::ConstKind::Value(cv) => self.add_ty(cv.ty), - ty::ConstKind::Expr(e) => self.add_args(e.args()), - ty::ConstKind::Error(_) => self.add_flags(TypeFlags::HAS_ERROR), - } - } - - fn add_existential_projection(&mut self, projection: &ty::ExistentialProjection<'_>) { - self.add_args(projection.args); - match projection.term.unpack() { - ty::TermKind::Ty(ty) => self.add_ty(ty), - ty::TermKind::Const(ct) => self.add_const(ct), - } - } - - fn add_alias_ty(&mut self, alias_ty: ty::AliasTy<'_>) { - self.add_args(alias_ty.args); - } - - fn add_alias_term(&mut self, alias_term: ty::AliasTerm<'_>) { - self.add_args(alias_term.args); - } - - fn add_args(&mut self, args: &[GenericArg<'_>]) { - for kind in args { - match kind.unpack() { - GenericArgKind::Type(ty) => self.add_ty(ty), - GenericArgKind::Lifetime(lt) => self.add_region(lt), - GenericArgKind::Const(ct) => self.add_const(ct), - } - } - } - - fn add_term(&mut self, term: ty::Term<'_>) { - match term.unpack() { - ty::TermKind::Ty(ty) => self.add_ty(ty), - ty::TermKind::Const(ct) => self.add_const(ct), - } - } -} diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index dc2c9e3d9f11..8d6871d2f1fe 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -145,10 +145,10 @@ where } fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { - match *r { + match r.kind() { ty::ReBound(debruijn, br) if debruijn == self.current_index => { let region = self.delegate.replace_region(br); - if let ty::ReBound(debruijn1, br) = *region { + if let ty::ReBound(debruijn1, br) = region.kind() { // If the callback returns a bound region, // that region should always use the INNERMOST // debruijn index. Then we adjust it to the @@ -278,7 +278,7 @@ impl<'tcx> TyCtxt<'tcx> { where T: TypeFoldable>, { - let shift_bv = |bv: ty::BoundVar| ty::BoundVar::from_usize(bv.as_usize() + bound_vars); + let shift_bv = |bv: ty::BoundVar| bv + bound_vars; self.replace_escaping_bound_vars_uncached( value, FnMutDelegate { diff --git a/compiler/rustc_middle/src/ty/generic_args.rs b/compiler/rustc_middle/src/ty/generic_args.rs index 9c1ff134f0fd..8de64b3bfac6 100644 --- a/compiler/rustc_middle/src/ty/generic_args.rs +++ b/compiler/rustc_middle/src/ty/generic_args.rs @@ -11,12 +11,13 @@ use rustc_hir::def_id::DefId; use rustc_macros::{HashStable, TyDecodable, TyEncodable, extension}; use rustc_serialize::{Decodable, Encodable}; use rustc_type_ir::WithCachedTypeInfo; +use rustc_type_ir::walk::TypeWalker; use smallvec::SmallVec; use crate::ty::codec::{TyDecoder, TyEncoder}; use crate::ty::{ self, ClosureArgs, CoroutineArgs, CoroutineClosureArgs, FallibleTypeFolder, InlineConstArgs, - Lift, List, Ty, TyCtxt, TypeFoldable, TypeVisitable, TypeVisitor, VisitorResult, + Lift, List, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeVisitable, TypeVisitor, VisitorResult, walk_visitable_list, }; @@ -297,6 +298,20 @@ impl<'tcx> GenericArg<'tcx> { GenericArgKind::Const(ct) => ct.is_ct_infer(), } } + + /// Iterator that walks `self` and any types reachable from + /// `self`, in depth-first order. Note that just walks the types + /// that appear in `self`, it does not descend into the fields of + /// structs or variants. For example: + /// + /// ```text + /// isize => { isize } + /// Foo> => { Foo>, Bar, isize } + /// [isize] => { [isize], isize } + /// ``` + pub fn walk(self) -> TypeWalker> { + TypeWalker::new(self) + } } impl<'a, 'tcx> Lift> for GenericArg<'a> { @@ -322,6 +337,14 @@ impl<'tcx> TypeFoldable> for GenericArg<'tcx> { GenericArgKind::Const(ct) => ct.try_fold_with(folder).map(Into::into), } } + + fn fold_with>>(self, folder: &mut F) -> Self { + match self.unpack() { + GenericArgKind::Lifetime(lt) => lt.fold_with(folder).into(), + GenericArgKind::Type(ty) => ty.fold_with(folder).into(), + GenericArgKind::Const(ct) => ct.fold_with(folder).into(), + } + } } impl<'tcx> TypeVisitable> for GenericArg<'tcx> { @@ -591,6 +614,27 @@ impl<'tcx> TypeFoldable> for GenericArgsRef<'tcx> { } } 0 => Ok(self), + _ => ty::util::try_fold_list(self, folder, |tcx, v| tcx.mk_args(v)), + } + } + + fn fold_with>>(self, folder: &mut F) -> Self { + // See justification for this behavior in `try_fold_with`. + match self.len() { + 1 => { + let param0 = self[0].fold_with(folder); + if param0 == self[0] { self } else { folder.cx().mk_args(&[param0]) } + } + 2 => { + let param0 = self[0].fold_with(folder); + let param1 = self[1].fold_with(folder); + if param0 == self[0] && param1 == self[1] { + self + } else { + folder.cx().mk_args(&[param0, param1]) + } + } + 0 => self, _ => ty::util::fold_list(self, folder, |tcx, v| tcx.mk_args(v)), } } @@ -626,6 +670,22 @@ impl<'tcx> TypeFoldable> for &'tcx ty::List> { Ok(folder.cx().mk_type_list(&[param0, param1])) } } + _ => ty::util::try_fold_list(self, folder, |tcx, v| tcx.mk_type_list(v)), + } + } + + fn fold_with>>(self, folder: &mut F) -> Self { + // See comment justifying behavior in `try_fold_with`. + match self.len() { + 2 => { + let param0 = self[0].fold_with(folder); + let param1 = self[1].fold_with(folder); + if param0 == self[0] && param1 == self[1] { + self + } else { + folder.cx().mk_type_list(&[param0, param1]) + } + } _ => ty::util::fold_list(self, folder, |tcx, v| tcx.mk_type_list(v)), } } diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 55ebd15248c6..faad0a82acbf 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -71,7 +71,7 @@ pub enum InstanceKind<'tcx> { /// - coroutines Item(DefId), - /// An intrinsic `fn` item (with `"rust-intrinsic"` ABI). + /// An intrinsic `fn` item (with`#[rustc_instrinsic]`). /// /// Alongside `Virtual`, this is the only `InstanceKind` that does not have its own callable MIR. /// Instead, codegen and const eval "magically" evaluate calls to intrinsics purely in the @@ -746,7 +746,7 @@ impl<'tcx> Instance<'tcx> { let call_once = tcx .associated_items(fn_once) .in_definition_order() - .find(|it| it.kind == ty::AssocKind::Fn) + .find(|it| it.is_fn()) .unwrap() .def_id; let track_caller = diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index ebb6a8c08a54..7ebfebea44e5 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -1265,9 +1265,7 @@ pub fn fn_can_unwind(tcx: TyCtxt<'_>, fn_def_id: Option, abi: ExternAbi) | CCmseNonSecureCall | CCmseNonSecureEntry | Unadjusted => false, - Rust | RustCall | RustCold | RustIntrinsic => { - tcx.sess.panic_strategy() == PanicStrategy::Unwind - } + Rust | RustCall | RustCold => tcx.sess.panic_strategy() == PanicStrategy::Unwind, } } diff --git a/compiler/rustc_middle/src/ty/list.rs b/compiler/rustc_middle/src/ty/list.rs index 0fd370a56195..0cf5820959ee 100644 --- a/compiler/rustc_middle/src/ty/list.rs +++ b/compiler/rustc_middle/src/ty/list.rs @@ -7,9 +7,9 @@ use std::{fmt, iter, mem, ptr, slice}; use rustc_data_structures::aligned::{Aligned, align_of}; use rustc_data_structures::sync::DynSync; use rustc_serialize::{Encodable, Encoder}; +use rustc_type_ir::FlagComputation; -use super::flags::FlagComputation; -use super::{DebruijnIndex, TypeFlags}; +use super::{DebruijnIndex, TyCtxt, TypeFlags}; use crate::arena::Arena; /// `List` is a bit like `&[T]`, but with some critical differences. @@ -299,8 +299,8 @@ impl TypeInfo { } } -impl From for TypeInfo { - fn from(computation: FlagComputation) -> TypeInfo { +impl<'tcx> From>> for TypeInfo { + fn from(computation: FlagComputation>) -> TypeInfo { TypeInfo { flags: computation.flags, outer_exclusive_binder: computation.outer_exclusive_binder, diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 80f1bd7c6f46..3698cfb98709 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -117,7 +117,6 @@ pub mod cast; pub mod codec; pub mod error; pub mod fast_reject; -pub mod flags; pub mod inhabitedness; pub mod layout; pub mod normalize_erasing_regions; @@ -128,7 +127,6 @@ pub mod significant_drop_order; pub mod trait_def; pub mod util; pub mod vtable; -pub mod walk; mod adt; mod assoc; @@ -539,6 +537,13 @@ impl<'tcx> TypeFoldable> for Term<'tcx> { ty::TermKind::Const(ct) => ct.try_fold_with(folder).map(Into::into), } } + + fn fold_with>>(self, folder: &mut F) -> Self { + match self.unpack() { + ty::TermKind::Ty(ty) => ty.fold_with(folder).into(), + ty::TermKind::Const(ct) => ct.fold_with(folder).into(), + } + } } impl<'tcx> TypeVisitable> for Term<'tcx> { @@ -1464,7 +1469,7 @@ impl<'tcx> TyCtxt<'tcx> { pub fn provided_trait_methods(self, id: DefId) -> impl 'tcx + Iterator { self.associated_items(id) .in_definition_order() - .filter(move |item| item.kind == AssocKind::Fn && item.defaultness(self).has_value()) + .filter(move |item| item.is_fn() && item.defaultness(self).has_value()) } pub fn repr_options_of_def(self, did: LocalDefId) -> ReprOptions { @@ -1610,8 +1615,11 @@ impl<'tcx> TyCtxt<'tcx> { /// return-position `impl Trait` from a trait, then provide the source info /// about where that RPITIT came from. pub fn opt_rpitit_info(self, def_id: DefId) -> Option { - if let DefKind::AssocTy = self.def_kind(def_id) { - self.associated_item(def_id).opt_rpitit_info + if let DefKind::AssocTy = self.def_kind(def_id) + && let AssocKind::Type { data: AssocTypeData::Rpitit(rpitit_info) } = + self.associated_item(def_id).kind + { + Some(rpitit_info) } else { None } @@ -1939,15 +1947,15 @@ impl<'tcx> TyCtxt<'tcx> { /// Hygienically compares a use-site name (`use_name`) for a field or an associated item with /// its supposed definition name (`def_name`). The method also needs `DefId` of the supposed /// definition's parent/scope to perform comparison. - pub fn hygienic_eq(self, use_name: Ident, def_name: Ident, def_parent_def_id: DefId) -> bool { - // We could use `Ident::eq` here, but we deliberately don't. The name + pub fn hygienic_eq(self, use_ident: Ident, def_ident: Ident, def_parent_def_id: DefId) -> bool { + // We could use `Ident::eq` here, but we deliberately don't. The identifier // comparison fails frequently, and we want to avoid the expensive // `normalize_to_macros_2_0()` calls required for the span comparison whenever possible. - use_name.name == def_name.name - && use_name + use_ident.name == def_ident.name + && use_ident .span .ctxt() - .hygienic_eq(def_name.span.ctxt(), self.expn_that_defined(def_parent_def_id)) + .hygienic_eq(def_ident.span.ctxt(), self.expn_that_defined(def_parent_def_id)) } pub fn adjust_ident(self, mut ident: Ident, scope: DefId) -> Ident { diff --git a/compiler/rustc_middle/src/ty/opaque_types.rs b/compiler/rustc_middle/src/ty/opaque_types.rs index c72efde09949..9445a18ad76b 100644 --- a/compiler/rustc_middle/src/ty/opaque_types.rs +++ b/compiler/rustc_middle/src/ty/opaque_types.rs @@ -95,7 +95,7 @@ impl<'tcx> TypeFolder> for ReverseMapper<'tcx> { #[instrument(skip(self), level = "debug")] fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { - match *r { + match r.kind() { // Ignore bound regions and `'static` regions that appear in the // type, we only need to remap regions that reference lifetimes // from the function declaration. diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs index b56e08626920..ecd6132b3ef3 100644 --- a/compiler/rustc_middle/src/ty/parameterized.rs +++ b/compiler/rustc_middle/src/ty/parameterized.rs @@ -113,7 +113,7 @@ trivially_parameterized_over_tcx! { rustc_span::Span, rustc_span::Symbol, rustc_span::def_id::DefPathHash, - rustc_span::hygiene::SyntaxContextDataNonRecursive, + rustc_span::hygiene::SyntaxContextKey, rustc_span::Ident, rustc_type_ir::Variance, rustc_hir::Attribute, diff --git a/compiler/rustc_middle/src/ty/pattern.rs b/compiler/rustc_middle/src/ty/pattern.rs index 4cad1ab20991..758adc42e3eb 100644 --- a/compiler/rustc_middle/src/ty/pattern.rs +++ b/compiler/rustc_middle/src/ty/pattern.rs @@ -1,14 +1,40 @@ use std::fmt; use rustc_data_structures::intern::Interned; -use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; +use rustc_macros::HashStable; +use rustc_type_ir::ir_print::IrPrint; +use rustc_type_ir::{ + FlagComputation, Flags, {self as ir}, +}; +use super::TyCtxt; use crate::ty; +pub type PatternKind<'tcx> = ir::PatternKind>; + #[derive(Copy, Clone, PartialEq, Eq, Hash, HashStable)] #[rustc_pass_by_value] pub struct Pattern<'tcx>(pub Interned<'tcx, PatternKind<'tcx>>); +impl<'tcx> Flags for Pattern<'tcx> { + fn flags(&self) -> rustc_type_ir::TypeFlags { + match &**self { + ty::PatternKind::Range { start, end } => { + FlagComputation::for_const_kind(&start.kind()).flags + | FlagComputation::for_const_kind(&end.kind()).flags + } + } + } + + fn outer_exclusive_binder(&self) -> rustc_type_ir::DebruijnIndex { + match &**self { + ty::PatternKind::Range { start, end } => { + start.outer_exclusive_binder().max(end.outer_exclusive_binder()) + } + } + } +} + impl<'tcx> std::ops::Deref for Pattern<'tcx> { type Target = PatternKind<'tcx>; @@ -23,9 +49,9 @@ impl<'tcx> fmt::Debug for Pattern<'tcx> { } } -impl<'tcx> fmt::Debug for PatternKind<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match *self { +impl<'tcx> IrPrint> for TyCtxt<'tcx> { + fn print(t: &PatternKind<'tcx>, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *t { PatternKind::Range { start, end } => { write!(f, "{start}")?; @@ -53,10 +79,15 @@ impl<'tcx> fmt::Debug for PatternKind<'tcx> { } } } + + fn print_debug(t: &PatternKind<'tcx>, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + Self::print(t, fmt) + } } -#[derive(Clone, PartialEq, Eq, Hash)] -#[derive(HashStable, TyEncodable, TyDecodable, TypeVisitable, TypeFoldable)] -pub enum PatternKind<'tcx> { - Range { start: ty::Const<'tcx>, end: ty::Const<'tcx> }, +impl<'tcx> rustc_type_ir::inherent::IntoKind for Pattern<'tcx> { + type Kind = PatternKind<'tcx>; + fn kind(self) -> Self::Kind { + *self + } } diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs index 5904deaaaad8..9172c5d3ab75 100644 --- a/compiler/rustc_middle/src/ty/print/mod.rs +++ b/compiler/rustc_middle/src/ty/print/mod.rs @@ -382,7 +382,7 @@ pub fn shrunk_instance_name<'tcx>( return (s, None); } - let path = tcx.output_filenames(()).temp_path_ext("long-type.txt", None); + let path = tcx.output_filenames(()).temp_path_for_diagnostic("long-type.txt"); let written_to_path = std::fs::write(&path, s).ok().map(|_| path); (shrunk, written_to_path) diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 3281cb4135a0..d739218af5ee 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -63,6 +63,7 @@ thread_local! { static FORCE_TRIMMED_PATH: Cell = const { Cell::new(false) }; static REDUCED_QUERIES: Cell = const { Cell::new(false) }; static NO_VISIBLE_PATH: Cell = const { Cell::new(false) }; + static NO_VISIBLE_PATH_IF_DOC_HIDDEN: Cell = const { Cell::new(false) }; static RTN_MODE: Cell = const { Cell::new(RtnMode::ForDiagnostic) }; } @@ -134,6 +135,8 @@ define_helper!( /// Prevent selection of visible paths. `Display` impl of DefId will prefer /// visible (public) reexports of types as paths. fn with_no_visible_paths(NoVisibleGuard, NO_VISIBLE_PATH); + /// Prevent selection of visible paths if the paths are through a doc hidden path. + fn with_no_visible_paths_if_doc_hidden(NoVisibleIfDocHiddenGuard, NO_VISIBLE_PATH_IF_DOC_HIDDEN); ); #[must_use] @@ -569,6 +572,10 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { return Ok(false); }; + if self.tcx().is_doc_hidden(visible_parent) && with_no_visible_paths_if_doc_hidden() { + return Ok(false); + } + let actual_parent = self.tcx().opt_parent(def_id); debug!( "try_print_visible_def_path: visible_parent={:?} actual_parent={:?}", @@ -613,7 +620,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { // the children of the visible parent (as was done when computing // `visible_parent_map`), looking for the specific child we currently have and then // have access to the re-exported name. - DefPathData::TypeNs(Some(ref mut name)) if Some(visible_parent) != actual_parent => { + DefPathData::TypeNs(ref mut name) if Some(visible_parent) != actual_parent => { // Item might be re-exported several times, but filter for the one // that's public and whose identifier isn't `_`. let reexport = self @@ -634,7 +641,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { } // Re-exported `extern crate` (#43189). DefPathData::CrateRoot => { - data = DefPathData::TypeNs(Some(self.tcx().crate_name(def_id.krate))); + data = DefPathData::TypeNs(self.tcx().crate_name(def_id.krate)); } _ => {} } @@ -1207,7 +1214,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { && assoc .trait_container(tcx) .is_some_and(|def_id| tcx.is_lang_item(def_id, LangItem::Coroutine)) - && assoc.name == rustc_span::sym::Return + && assoc.opt_name() == Some(rustc_span::sym::Return) { if let ty::Coroutine(_, args) = args.type_at(0).kind() { let return_ty = args.as_coroutine().return_ty(); @@ -1230,7 +1237,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { p!(", "); } - p!(write("{} = ", tcx.associated_item(assoc_item_def_id).name)); + p!(write("{} = ", tcx.associated_item(assoc_item_def_id).name())); match term.unpack() { TermKind::Ty(ty) => p!(print(ty)), @@ -2520,7 +2527,7 @@ impl<'tcx> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx> { let identify_regions = self.tcx.sess.opts.unstable_opts.identify_regions; - match *region { + match region.kind() { ty::ReEarlyParam(ref data) => data.has_name(), ty::ReLateParam(ty::LateParamRegion { kind, .. }) => kind.is_named(), @@ -2590,7 +2597,7 @@ impl<'tcx> FmtPrinter<'_, 'tcx> { // the user might want to diagnose an error, but there is basically no way // to fit that into a short string. Hence the recommendation to use // `explain_region()` or `note_and_explain_region()`. - match *region { + match region.kind() { ty::ReEarlyParam(data) => { p!(write("{}", data.name)); return Ok(()); @@ -2680,7 +2687,7 @@ impl<'a, 'tcx> ty::TypeFolder> for RegionFolder<'a, 'tcx> { fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { let name = &mut self.name; - let region = match *r { + let region = match r.kind() { ty::ReBound(db, br) if db >= self.current_index => { *self.region_map.entry(br).or_insert_with(|| name(Some(db), self.current_index, br)) } @@ -2704,7 +2711,7 @@ impl<'a, 'tcx> ty::TypeFolder> for RegionFolder<'a, 'tcx> { } _ => return r, }; - if let ty::ReBound(debruijn1, br) = *region { + if let ty::ReBound(debruijn1, br) = region.kind() { assert_eq!(debruijn1, ty::INNERMOST); ty::Region::new_bound(self.tcx, self.current_index, br) } else { @@ -3284,7 +3291,7 @@ define_print! { } ty::ExistentialProjection<'tcx> { - let name = cx.tcx().associated_item(self.def_id).name; + let name = cx.tcx().associated_item(self.def_id).name(); // The args don't contain the self ty (as it has been erased) but the corresp. // generics do as the trait always has a self ty param. We need to offset. let args = &self.args[cx.tcx().generics_of(self.def_id).parent_count - 1..]; diff --git a/compiler/rustc_middle/src/ty/region.rs b/compiler/rustc_middle/src/ty/region.rs index c78306f2ca37..3e4f7a79d539 100644 --- a/compiler/rustc_middle/src/ty/region.rs +++ b/compiler/rustc_middle/src/ty/region.rs @@ -1,5 +1,3 @@ -use std::ops::Deref; - use rustc_data_structures::intern::Interned; use rustc_errors::MultiSpan; use rustc_hir::def_id::DefId; @@ -22,7 +20,7 @@ impl<'tcx> rustc_type_ir::inherent::IntoKind for Region<'tcx> { type Kind = RegionKind<'tcx>; fn kind(self) -> RegionKind<'tcx> { - *self + *self.0.0 } } @@ -32,7 +30,7 @@ impl<'tcx> rustc_type_ir::Flags for Region<'tcx> { } fn outer_exclusive_binder(&self) -> ty::DebruijnIndex { - match **self { + match self.kind() { ty::ReBound(debruijn, _) => debruijn.shifted_in(1), _ => ty::INNERMOST, } @@ -163,7 +161,7 @@ impl<'tcx> Region<'tcx> { pub fn get_name(self) -> Option { if self.has_name() { - match *self { + match self.kind() { ty::ReEarlyParam(ebr) => Some(ebr.name), ty::ReBound(_, br) => br.kind.get_name(), ty::ReLateParam(fr) => fr.kind.get_name(), @@ -185,7 +183,7 @@ impl<'tcx> Region<'tcx> { /// Is this region named by the user? pub fn has_name(self) -> bool { - match *self { + match self.kind() { ty::ReEarlyParam(ebr) => ebr.has_name(), ty::ReBound(_, br) => br.kind.is_named(), ty::ReLateParam(fr) => fr.kind.is_named(), @@ -199,32 +197,32 @@ impl<'tcx> Region<'tcx> { #[inline] pub fn is_error(self) -> bool { - matches!(*self, ty::ReError(_)) + matches!(self.kind(), ty::ReError(_)) } #[inline] pub fn is_static(self) -> bool { - matches!(*self, ty::ReStatic) + matches!(self.kind(), ty::ReStatic) } #[inline] pub fn is_erased(self) -> bool { - matches!(*self, ty::ReErased) + matches!(self.kind(), ty::ReErased) } #[inline] pub fn is_bound(self) -> bool { - matches!(*self, ty::ReBound(..)) + matches!(self.kind(), ty::ReBound(..)) } #[inline] pub fn is_placeholder(self) -> bool { - matches!(*self, ty::RePlaceholder(..)) + matches!(self.kind(), ty::RePlaceholder(..)) } #[inline] pub fn bound_at_or_above_binder(self, index: ty::DebruijnIndex) -> bool { - match *self { + match self.kind() { ty::ReBound(debruijn, _) => debruijn >= index, _ => false, } @@ -233,7 +231,7 @@ impl<'tcx> Region<'tcx> { pub fn type_flags(self) -> TypeFlags { let mut flags = TypeFlags::empty(); - match *self { + match self.kind() { ty::ReVar(..) => { flags = flags | TypeFlags::HAS_FREE_REGIONS; flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS; @@ -275,14 +273,14 @@ impl<'tcx> Region<'tcx> { /// True for free regions other than `'static`. pub fn is_param(self) -> bool { - matches!(*self, ty::ReEarlyParam(_) | ty::ReLateParam(_)) + matches!(self.kind(), ty::ReEarlyParam(_) | ty::ReLateParam(_)) } /// True for free region in the current context. /// /// This is the case for `'static` and param regions. pub fn is_free(self) -> bool { - match *self { + match self.kind() { ty::ReStatic | ty::ReEarlyParam(..) | ty::ReLateParam(..) => true, ty::ReVar(..) | ty::RePlaceholder(..) @@ -319,15 +317,6 @@ impl<'tcx> Region<'tcx> { } } -impl<'tcx> Deref for Region<'tcx> { - type Target = RegionKind<'tcx>; - - #[inline] - fn deref(&self) -> &RegionKind<'tcx> { - self.0.0 - } -} - #[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable)] #[derive(HashStable)] pub struct EarlyParamRegion { diff --git a/compiler/rustc_middle/src/ty/significant_drop_order.rs b/compiler/rustc_middle/src/ty/significant_drop_order.rs index 4881d611c128..561f84192b42 100644 --- a/compiler/rustc_middle/src/ty/significant_drop_order.rs +++ b/compiler/rustc_middle/src/ty/significant_drop_order.rs @@ -26,7 +26,7 @@ fn true_significant_drop_ty<'tcx>( name_rev.push(tcx.crate_name(did.krate)); } rustc_hir::definitions::DefPathData::TypeNs(symbol) => { - name_rev.push(symbol.unwrap()); + name_rev.push(symbol); } _ => return None, } @@ -143,25 +143,11 @@ pub fn ty_dtor_span<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option { | ty::UnsafeBinder(_) => None, ty::Adt(adt_def, _) => { - let did = adt_def.did(); - let try_local_did_span = |did: DefId| { - if let Some(local) = did.as_local() { - tcx.source_span(local) - } else { - tcx.def_span(did) - } - }; - let dtor = if let Some(dtor) = tcx.adt_destructor(did) { - dtor.did - } else if let Some(dtor) = tcx.adt_async_destructor(did) { - return Some(tcx.source_span(dtor.impl_did)); + if let Some(dtor) = tcx.adt_destructor(adt_def.did()) { + Some(tcx.def_span(tcx.parent(dtor.did))) } else { - return Some(try_local_did_span(did)); - }; - let def_key = tcx.def_key(dtor); - let Some(parent_index) = def_key.parent else { return Some(try_local_did_span(dtor)) }; - let parent_did = DefId { index: parent_index, krate: dtor.krate }; - Some(try_local_did_span(parent_did)) + Some(tcx.def_span(adt_def.did())) + } } ty::Coroutine(did, _) | ty::CoroutineWitness(did, _) diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 798ef352c408..26861666c1db 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -6,20 +6,19 @@ use std::fmt::{self, Debug}; use rustc_abi::TyAndLayout; -use rustc_ast::InlineAsmTemplatePiece; use rustc_hir::def::Namespace; use rustc_hir::def_id::LocalDefId; -use rustc_span::Span; use rustc_span::source_map::Spanned; -use rustc_type_ir::{ConstKind, VisitorResult, try_visit}; +use rustc_type_ir::{ConstKind, TypeFolder, VisitorResult, try_visit}; use super::print::PrettyPrinter; use super::{GenericArg, GenericArgKind, Pattern, Region}; +use crate::infer::canonical::CanonicalVarInfos; use crate::mir::PlaceElem; use crate::ty::print::{FmtPrinter, Printer, with_no_trimmed_paths}; use crate::ty::{ - self, FallibleTypeFolder, InferConst, Lift, Term, TermKind, Ty, TyCtxt, TypeFoldable, - TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitor, + self, FallibleTypeFolder, Lift, Term, TermKind, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, + TypeSuperVisitable, TypeVisitable, TypeVisitor, }; impl fmt::Debug for ty::TraitDef { @@ -61,6 +60,12 @@ impl<'tcx> fmt::Debug for ty::adjustment::Adjustment<'tcx> { } } +impl<'tcx> fmt::Debug for ty::adjustment::PatAdjustment<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{} -> {:?}", self.source, self.kind) + } +} + impl fmt::Debug for ty::BoundRegionKind { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { @@ -271,6 +276,7 @@ TrivialTypeTraversalImpls! { crate::ty::AssocKind, crate::ty::BoundRegion, crate::ty::BoundVar, + crate::ty::InferConst, crate::ty::Placeholder, crate::ty::Placeholder, crate::ty::Placeholder, @@ -337,24 +343,6 @@ impl<'tcx> TypeVisitable> for ty::AdtDef<'tcx> { } } -impl<'tcx> TypeFoldable> for &'tcx ty::List> { - fn try_fold_with>>( - self, - folder: &mut F, - ) -> Result { - ty::util::fold_list(self, folder, |tcx, v| tcx.mk_poly_existential_predicates(v)) - } -} - -impl<'tcx> TypeFoldable> for &'tcx ty::List> { - fn try_fold_with>>( - self, - folder: &mut F, - ) -> Result { - ty::util::fold_list(self, folder, |tcx, v| tcx.mk_const_list(v)) - } -} - impl<'tcx> TypeFoldable> for Pattern<'tcx> { fn try_fold_with>>( self, @@ -363,6 +351,11 @@ impl<'tcx> TypeFoldable> for Pattern<'tcx> { let pat = (*self).clone().try_fold_with(folder)?; Ok(if pat == *self { self } else { folder.cx().mk_pat(pat) }) } + + fn fold_with>>(self, folder: &mut F) -> Self { + let pat = (*self).clone().fold_with(folder); + if pat == *self { self } else { folder.cx().mk_pat(pat) } + } } impl<'tcx> TypeVisitable> for Pattern<'tcx> { @@ -378,6 +371,10 @@ impl<'tcx> TypeFoldable> for Ty<'tcx> { ) -> Result { folder.try_fold_ty(self) } + + fn fold_with>>(self, folder: &mut F) -> Self { + folder.fold_ty(self) + } } impl<'tcx> TypeVisitable> for Ty<'tcx> { @@ -436,6 +433,45 @@ impl<'tcx> TypeSuperFoldable> for Ty<'tcx> { Ok(if *self.kind() == kind { self } else { folder.cx().mk_ty_from_kind(kind) }) } + + fn super_fold_with>>(self, folder: &mut F) -> Self { + let kind = match *self.kind() { + ty::RawPtr(ty, mutbl) => ty::RawPtr(ty.fold_with(folder), mutbl), + ty::Array(typ, sz) => ty::Array(typ.fold_with(folder), sz.fold_with(folder)), + ty::Slice(typ) => ty::Slice(typ.fold_with(folder)), + ty::Adt(tid, args) => ty::Adt(tid, args.fold_with(folder)), + ty::Dynamic(trait_ty, region, representation) => { + ty::Dynamic(trait_ty.fold_with(folder), region.fold_with(folder), representation) + } + ty::Tuple(ts) => ty::Tuple(ts.fold_with(folder)), + ty::FnDef(def_id, args) => ty::FnDef(def_id, args.fold_with(folder)), + ty::FnPtr(sig_tys, hdr) => ty::FnPtr(sig_tys.fold_with(folder), hdr), + ty::UnsafeBinder(f) => ty::UnsafeBinder(f.fold_with(folder)), + ty::Ref(r, ty, mutbl) => ty::Ref(r.fold_with(folder), ty.fold_with(folder), mutbl), + ty::Coroutine(did, args) => ty::Coroutine(did, args.fold_with(folder)), + ty::CoroutineWitness(did, args) => ty::CoroutineWitness(did, args.fold_with(folder)), + ty::Closure(did, args) => ty::Closure(did, args.fold_with(folder)), + ty::CoroutineClosure(did, args) => ty::CoroutineClosure(did, args.fold_with(folder)), + ty::Alias(kind, data) => ty::Alias(kind, data.fold_with(folder)), + ty::Pat(ty, pat) => ty::Pat(ty.fold_with(folder), pat.fold_with(folder)), + + ty::Bool + | ty::Char + | ty::Str + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Error(_) + | ty::Infer(_) + | ty::Param(..) + | ty::Bound(..) + | ty::Placeholder(..) + | ty::Never + | ty::Foreign(..) => return self, + }; + + if *self.kind() == kind { self } else { folder.cx().mk_ty_from_kind(kind) } + } } impl<'tcx> TypeSuperVisitable> for Ty<'tcx> { @@ -496,6 +532,10 @@ impl<'tcx> TypeFoldable> for ty::Region<'tcx> { ) -> Result { folder.try_fold_region(self) } + + fn fold_with>>(self, folder: &mut F) -> Self { + folder.fold_region(self) + } } impl<'tcx> TypeVisitable> for ty::Region<'tcx> { @@ -511,6 +551,10 @@ impl<'tcx> TypeFoldable> for ty::Predicate<'tcx> { ) -> Result { folder.try_fold_predicate(self) } + + fn fold_with>>(self, folder: &mut F) -> Self { + folder.fold_predicate(self) + } } // FIXME(clause): This is wonky @@ -521,6 +565,10 @@ impl<'tcx> TypeFoldable> for ty::Clause<'tcx> { ) -> Result { Ok(folder.try_fold_predicate(self.as_predicate())?.expect_clause()) } + + fn fold_with>>(self, folder: &mut F) -> Self { + folder.fold_predicate(self.as_predicate()).expect_clause() + } } impl<'tcx> TypeVisitable> for ty::Predicate<'tcx> { @@ -543,6 +591,11 @@ impl<'tcx> TypeSuperFoldable> for ty::Predicate<'tcx> { let new = self.kind().try_fold_with(folder)?; Ok(folder.cx().reuse_or_mk_predicate(self, new)) } + + fn super_fold_with>>(self, folder: &mut F) -> Self { + let new = self.kind().fold_with(folder); + folder.cx().reuse_or_mk_predicate(self, new) + } } impl<'tcx> TypeSuperVisitable> for ty::Predicate<'tcx> { @@ -563,15 +616,6 @@ impl<'tcx> TypeSuperVisitable> for ty::Clauses<'tcx> { } } -impl<'tcx> TypeFoldable> for ty::Clauses<'tcx> { - fn try_fold_with>>( - self, - folder: &mut F, - ) -> Result { - ty::util::fold_list(self, folder, |tcx, v| tcx.mk_clauses(v)) - } -} - impl<'tcx> TypeFoldable> for ty::Const<'tcx> { fn try_fold_with>>( self, @@ -579,6 +623,10 @@ impl<'tcx> TypeFoldable> for ty::Const<'tcx> { ) -> Result { folder.try_fold_const(self) } + + fn fold_with>>(self, folder: &mut F) -> Self { + folder.fold_const(self) + } } impl<'tcx> TypeVisitable> for ty::Const<'tcx> { @@ -606,6 +654,20 @@ impl<'tcx> TypeSuperFoldable> for ty::Const<'tcx> { }; if kind != self.kind() { Ok(folder.cx().mk_ct_from_kind(kind)) } else { Ok(self) } } + + fn super_fold_with>>(self, folder: &mut F) -> Self { + let kind = match self.kind() { + ConstKind::Param(p) => ConstKind::Param(p.fold_with(folder)), + ConstKind::Infer(i) => ConstKind::Infer(i.fold_with(folder)), + ConstKind::Bound(d, b) => ConstKind::Bound(d.fold_with(folder), b.fold_with(folder)), + ConstKind::Placeholder(p) => ConstKind::Placeholder(p.fold_with(folder)), + ConstKind::Unevaluated(uv) => ConstKind::Unevaluated(uv.fold_with(folder)), + ConstKind::Value(v) => ConstKind::Value(v.fold_with(folder)), + ConstKind::Error(e) => ConstKind::Error(e.fold_with(folder)), + ConstKind::Expr(e) => ConstKind::Expr(e.fold_with(folder)), + }; + if kind != self.kind() { folder.cx().mk_ct_from_kind(kind) } else { self } + } } impl<'tcx> TypeSuperVisitable> for ty::Const<'tcx> { @@ -639,20 +701,9 @@ impl<'tcx> TypeFoldable> for rustc_span::ErrorGuaranteed { ) -> Result { Ok(self) } -} -impl<'tcx> TypeFoldable> for InferConst { - fn try_fold_with>>( - self, - _folder: &mut F, - ) -> Result { - Ok(self) - } -} - -impl<'tcx> TypeVisitable> for InferConst { - fn visit_with>>(&self, _visitor: &mut V) -> V::Result { - V::Result::output() + fn fold_with>>(self, _folder: &mut F) -> Self { + self } } @@ -683,23 +734,9 @@ impl<'tcx, T: TypeFoldable> + Debug + Clone> TypeFoldable TypeFoldable> for &'tcx [InlineAsmTemplatePiece] { - fn try_fold_with>>( - self, - _folder: &mut F, - ) -> Result { - Ok(self) - } -} - -impl<'tcx> TypeFoldable> for &'tcx [Span] { - fn try_fold_with>>( - self, - _folder: &mut F, - ) -> Result { - Ok(self) + fn fold_with>>(self, folder: &mut F) -> Self { + Spanned { node: self.node.fold_with(folder), span: self.span.fold_with(folder) } } } @@ -710,13 +747,37 @@ impl<'tcx> TypeFoldable> for &'tcx ty::List { ) -> Result { Ok(self) } -} -impl<'tcx> TypeFoldable> for &'tcx ty::List> { - fn try_fold_with>>( - self, - folder: &mut F, - ) -> Result { - ty::util::fold_list(self, folder, |tcx, v| tcx.mk_place_elems(v)) + fn fold_with>>(self, _folder: &mut F) -> Self { + self } } + +macro_rules! list_fold { + ($($ty:ty : $mk:ident),+ $(,)?) => { + $( + impl<'tcx> TypeFoldable> for $ty { + fn try_fold_with>>( + self, + folder: &mut F, + ) -> Result { + ty::util::try_fold_list(self, folder, |tcx, v| tcx.$mk(v)) + } + + fn fold_with>>( + self, + folder: &mut F, + ) -> Self { + ty::util::fold_list(self, folder, |tcx, v| tcx.$mk(v)) + } + } + )* + } +} + +list_fold! { + ty::Clauses<'tcx> : mk_clauses, + &'tcx ty::List> : mk_poly_existential_predicates, + &'tcx ty::List> : mk_place_elems, + CanonicalVarInfos<'tcx> : mk_canonical_var_infos, +} diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 27ee363f1c14..301ae6045743 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -16,6 +16,7 @@ use rustc_hir::def_id::DefId; use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, extension}; use rustc_span::{DUMMY_SP, Span, Symbol, sym}; use rustc_type_ir::TyKind::*; +use rustc_type_ir::walk::TypeWalker; use rustc_type_ir::{self as ir, BoundVar, CollectAndApply, DynKind, TypeVisitableExt, elaborate}; use tracing::instrument; use ty::util::{AsyncDropGlueMorphology, IntTypeExt}; @@ -734,7 +735,7 @@ impl<'tcx> Ty<'tcx> { .map(|principal| { tcx.associated_items(principal.def_id()) .in_definition_order() - .filter(|item| item.kind == ty::AssocKind::Type) + .filter(|item| item.is_type()) .filter(|item| !item.is_impl_trait_in_trait()) .filter(|item| !tcx.generics_require_sized_self(item.def_id)) .count() @@ -1872,14 +1873,14 @@ impl<'tcx> Ty<'tcx> { /// Fast path helper for testing if a type is `Sized`. /// - /// Returning true means the type is known to be sized. Returning - /// `false` means nothing -- could be sized, might not be. + /// Returning true means the type is known to implement `Sized`. Returning `false` means + /// nothing -- could be sized, might not be. /// - /// Note that we could never rely on the fact that a type such as `[_]` is - /// trivially `!Sized` because we could be in a type environment with a - /// bound such as `[_]: Copy`. A function with such a bound obviously never - /// can be called, but that doesn't mean it shouldn't typecheck. This is why - /// this method doesn't return `Option`. + /// Note that we could never rely on the fact that a type such as `[_]` is trivially `!Sized` + /// because we could be in a type environment with a bound such as `[_]: Copy`. A function with + /// such a bound obviously never can be called, but that doesn't mean it shouldn't typecheck. + /// This is why this method doesn't return `Option`. + #[instrument(skip(tcx), level = "debug")] pub fn is_trivially_sized(self, tcx: TyCtxt<'tcx>) -> bool { match self.kind() { ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) @@ -2029,6 +2030,20 @@ impl<'tcx> Ty<'tcx> { pub fn is_known_rigid(self) -> bool { self.kind().is_known_rigid() } + + /// Iterator that walks `self` and any types reachable from + /// `self`, in depth-first order. Note that just walks the types + /// that appear in `self`, it does not descend into the fields of + /// structs or variants. For example: + /// + /// ```text + /// isize => { isize } + /// Foo> => { Foo>, Bar, isize } + /// [isize] => { [isize], isize } + /// ``` + pub fn walk(self) -> TypeWalker> { + TypeWalker::new(self.into()) + } } impl<'tcx> rustc_type_ir::inherent::Tys> for &'tcx ty::List> { diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index 7c437abfe24c..4c5c669771fb 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -77,8 +77,8 @@ pub struct TypeckResults<'tcx> { /// to a form valid in all Editions, either as a lint diagnostic or hard error. rust_2024_migration_desugared_pats: ItemLocalMap, - /// Stores the types which were implicitly dereferenced in pattern binding modes - /// for later usage in THIR lowering. For example, + /// Stores the types which were implicitly dereferenced in pattern binding modes or deref + /// patterns for later usage in THIR lowering. For example, /// /// ``` /// match &&Some(5i32) { @@ -86,11 +86,20 @@ pub struct TypeckResults<'tcx> { /// _ => {}, /// } /// ``` - /// leads to a `vec![&&Option, &Option]`. Empty vectors are not stored. + /// leads to a `vec![&&Option, &Option]` and + /// + /// ``` + /// #![feature(deref_patterns)] + /// match &Box::new(Some(5i32)) { + /// Some(n) => {}, + /// _ => {}, + /// } + /// ``` + /// leads to a `vec![&Box>, Box>]`. Empty vectors are not stored. /// /// See: /// - pat_adjustments: ItemLocalMap>>, + pat_adjustments: ItemLocalMap>>, /// Set of reference patterns that match against a match-ergonomics inserted reference /// (as opposed to against a reference in the scrutinee type). @@ -403,11 +412,15 @@ impl<'tcx> TypeckResults<'tcx> { LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.pat_binding_modes } } - pub fn pat_adjustments(&self) -> LocalTableInContext<'_, Vec>> { + pub fn pat_adjustments( + &self, + ) -> LocalTableInContext<'_, Vec>> { LocalTableInContext { hir_owner: self.hir_owner, data: &self.pat_adjustments } } - pub fn pat_adjustments_mut(&mut self) -> LocalTableInContextMut<'_, Vec>> { + pub fn pat_adjustments_mut( + &mut self, + ) -> LocalTableInContextMut<'_, Vec>> { LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.pat_adjustments } } @@ -758,7 +771,7 @@ impl<'tcx> IsIdentity for CanonicalUserType<'tcx> { _ => false, }, - GenericArgKind::Lifetime(r) => match *r { + GenericArgKind::Lifetime(r) => match r.kind() { ty::ReBound(debruijn, br) => { // We only allow a `ty::INNERMOST` index in generic parameters. assert_eq!(debruijn, ty::INNERMOST); diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index e4863896fc8b..08cee1101d0a 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -2,7 +2,7 @@ use std::{fmt, iter}; -use rustc_abi::{ExternAbi, Float, Integer, IntegerType, Size}; +use rustc_abi::{Float, Integer, IntegerType, Size}; use rustc_apfloat::Float as _; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; @@ -819,7 +819,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Get an English description for the item's kind. pub fn def_kind_descr(self, def_kind: DefKind, def_id: DefId) -> &'static str { match def_kind { - DefKind::AssocFn if self.associated_item(def_id).fn_has_self_parameter => "method", + DefKind::AssocFn if self.associated_item(def_id).is_method() => "method", DefKind::Closure if let Some(coroutine_kind) = self.coroutine_kind(def_id) => { match coroutine_kind { hir::CoroutineKind::Desugared( @@ -873,7 +873,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Gets an English article for the [`TyCtxt::def_kind_descr`]. pub fn def_kind_descr_article(self, def_kind: DefKind, def_id: DefId) -> &'static str { match def_kind { - DefKind::AssocFn if self.associated_item(def_id).fn_has_self_parameter => "a", + DefKind::AssocFn if self.associated_item(def_id).is_method() => "a", DefKind::Closure if let Some(coroutine_kind) = self.coroutine_kind(def_id) => { match coroutine_kind { hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, ..) => "an", @@ -1647,6 +1647,42 @@ pub fn fold_list<'tcx, F, L, T>( list: L, folder: &mut F, intern: impl FnOnce(TyCtxt<'tcx>, &[T]) -> L, +) -> L +where + F: TypeFolder>, + L: AsRef<[T]>, + T: TypeFoldable> + PartialEq + Copy, +{ + let slice = list.as_ref(); + let mut iter = slice.iter().copied(); + // Look for the first element that changed + match iter.by_ref().enumerate().find_map(|(i, t)| { + let new_t = t.fold_with(folder); + if new_t != t { Some((i, new_t)) } else { None } + }) { + Some((i, new_t)) => { + // An element changed, prepare to intern the resulting list + let mut new_list = SmallVec::<[_; 8]>::with_capacity(slice.len()); + new_list.extend_from_slice(&slice[..i]); + new_list.push(new_t); + for t in iter { + new_list.push(t.fold_with(folder)) + } + intern(folder.cx(), &new_list) + } + None => list, + } +} + +/// Does the equivalent of +/// ```ignore (illustrative) +/// let v = self.iter().map(|p| p.try_fold_with(folder)).collect::>(); +/// folder.tcx().intern_*(&v) +/// ``` +pub fn try_fold_list<'tcx, F, L, T>( + list: L, + folder: &mut F, + intern: impl FnOnce(TyCtxt<'tcx>, &[T]) -> L, ) -> Result where F: FallibleTypeFolder>, @@ -1719,10 +1755,7 @@ pub fn is_doc_notable_trait(tcx: TyCtxt<'_>, def_id: DefId) -> bool { /// the compiler to make some assumptions about its shape; if the user doesn't use a feature gate, they may /// cause an ICE that we otherwise may want to prevent. pub fn intrinsic_raw(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option { - if tcx.features().intrinsics() - && (matches!(tcx.fn_sig(def_id).skip_binder().abi(), ExternAbi::RustIntrinsic) - || tcx.has_attr(def_id, sym::rustc_intrinsic)) - { + if tcx.features().intrinsics() && tcx.has_attr(def_id, sym::rustc_intrinsic) { let must_be_overridden = match tcx.hir_node_by_def_id(def_id) { hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn { has_body, .. }, .. }) => { !has_body diff --git a/compiler/rustc_middle/src/ty/visit.rs b/compiler/rustc_middle/src/ty/visit.rs index e3b7a258c395..44c7b6a7c9e8 100644 --- a/compiler/rustc_middle/src/ty/visit.rs +++ b/compiler/rustc_middle/src/ty/visit.rs @@ -77,7 +77,7 @@ impl<'tcx> TyCtxt<'tcx> { } fn visit_region(&mut self, r: ty::Region<'tcx>) -> Self::Result { - match *r { + match r.kind() { ty::ReBound(debruijn, _) if debruijn < self.outer_index => { ControlFlow::Continue(()) } @@ -205,7 +205,7 @@ impl<'tcx> TypeVisitor> for LateBoundRegionsCollector { } fn visit_region(&mut self, r: ty::Region<'tcx>) { - if let ty::ReBound(debruijn, br) = *r { + if let ty::ReBound(debruijn, br) = r.kind() { if debruijn == self.current_index { self.regions.insert(br.kind); } @@ -231,9 +231,7 @@ impl MaxUniverse { impl<'tcx> TypeVisitor> for MaxUniverse { fn visit_ty(&mut self, t: Ty<'tcx>) { if let ty::Placeholder(placeholder) = t.kind() { - self.max_universe = ty::UniverseIndex::from_u32( - self.max_universe.as_u32().max(placeholder.universe.as_u32()), - ); + self.max_universe = self.max_universe.max(placeholder.universe); } t.super_visit_with(self) @@ -241,19 +239,15 @@ impl<'tcx> TypeVisitor> for MaxUniverse { fn visit_const(&mut self, c: ty::consts::Const<'tcx>) { 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()), - ); + self.max_universe = self.max_universe.max(placeholder.universe); } c.super_visit_with(self) } fn visit_region(&mut self, r: ty::Region<'tcx>) { - if let ty::RePlaceholder(placeholder) = *r { - self.max_universe = ty::UniverseIndex::from_u32( - self.max_universe.as_u32().max(placeholder.universe.as_u32()), - ); + if let ty::RePlaceholder(placeholder) = r.kind() { + self.max_universe = self.max_universe.max(placeholder.universe); } } } diff --git a/compiler/rustc_mir_build/src/builder/custom/mod.rs b/compiler/rustc_mir_build/src/builder/custom/mod.rs index bfc16816e2e5..902a6e7f115b 100644 --- a/compiler/rustc_mir_build/src/builder/custom/mod.rs +++ b/compiler/rustc_mir_build/src/builder/custom/mod.rs @@ -103,8 +103,9 @@ fn parse_attribute(attr: &Attribute) -> MirPhase { let mut dialect: Option = None; let mut phase: Option = None; + // Not handling errors properly for this internal attribute; will just abort on errors. for nested in meta_items { - let name = nested.name_or_empty(); + let name = nested.name().unwrap(); let value = nested.value_str().unwrap().as_str().to_string(); match name.as_str() { "dialect" => { diff --git a/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs index 19669021eefb..5918498f2392 100644 --- a/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs +++ b/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs @@ -145,7 +145,7 @@ impl<'a, 'tcx> ParseCtxt<'a, 'tcx> { let arm = &self.thir[*arm]; let value = match arm.pattern.kind { PatKind::Constant { value } => value, - PatKind::ExpandedConstant { ref subpattern, def_id: _, is_inline: false } + PatKind::ExpandedConstant { ref subpattern, def_id: _ } if let PatKind::Constant { value } = subpattern.kind => { value diff --git a/compiler/rustc_mir_build/src/builder/expr/into.rs b/compiler/rustc_mir_build/src/builder/expr/into.rs index 333e69475c50..a9a07997410c 100644 --- a/compiler/rustc_mir_build/src/builder/expr/into.rs +++ b/compiler/rustc_mir_build/src/builder/expr/into.rs @@ -328,7 +328,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { destination, target: Some(success), unwind: UnwindAction::Unreachable, - call_source: CallSource::Misc, + call_source: CallSource::Use, fn_span: expr_span, }, ); diff --git a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs index 29d400a957b4..d66b38c5b005 100644 --- a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs +++ b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs @@ -101,24 +101,27 @@ impl<'tcx> MatchPairTree<'tcx> { place_builder = resolved; } - // Only add the OpaqueCast projection if the given place is an opaque type and the - // expected type from the pattern is not. - let may_need_cast = match place_builder.base() { - PlaceBase::Local(local) => { - let ty = - Place::ty_from(local, place_builder.projection(), &cx.local_decls, cx.tcx).ty; - ty != pattern.ty && ty.has_opaque_types() + if !cx.tcx.next_trait_solver_globally() { + // Only add the OpaqueCast projection if the given place is an opaque type and the + // expected type from the pattern is not. + let may_need_cast = match place_builder.base() { + PlaceBase::Local(local) => { + let ty = + Place::ty_from(local, place_builder.projection(), &cx.local_decls, cx.tcx) + .ty; + ty != pattern.ty && ty.has_opaque_types() + } + _ => true, + }; + if may_need_cast { + place_builder = place_builder.project(ProjectionElem::OpaqueCast(pattern.ty)); } - _ => true, - }; - if may_need_cast { - place_builder = place_builder.project(ProjectionElem::OpaqueCast(pattern.ty)); } let place = place_builder.try_to_place(cx); let mut subpairs = Vec::new(); let test_case = match pattern.kind { - PatKind::Wild | PatKind::Error(_) => None, + PatKind::Missing | PatKind::Wild | PatKind::Error(_) => None, PatKind::Or { ref pats } => Some(TestCase::Or { pats: pats.iter().map(|pat| FlatPat::new(place_builder.clone(), pat, cx)).collect(), @@ -201,39 +204,10 @@ impl<'tcx> MatchPairTree<'tcx> { None } - PatKind::ExpandedConstant { subpattern: ref pattern, def_id: _, is_inline: false } => { + PatKind::ExpandedConstant { subpattern: ref pattern, .. } => { MatchPairTree::for_pattern(place_builder, pattern, cx, &mut subpairs, extra_data); None } - PatKind::ExpandedConstant { subpattern: ref pattern, def_id, is_inline: true } => { - MatchPairTree::for_pattern(place_builder, pattern, cx, &mut subpairs, extra_data); - - // Apply a type ascription for the inline constant to the value at `match_pair.place` - if let Some(source) = place { - let span = pattern.span; - let parent_id = cx.tcx.typeck_root_def_id(cx.def_id.to_def_id()); - let args = ty::InlineConstArgs::new( - cx.tcx, - ty::InlineConstArgsParts { - parent_args: ty::GenericArgs::identity_for_item(cx.tcx, parent_id), - ty: cx.infcx.next_ty_var(span), - }, - ) - .args; - let user_ty = cx.infcx.canonicalize_user_type_annotation(ty::UserType::new( - ty::UserTypeKind::TypeOf(def_id, ty::UserArgs { args, user_self_ty: None }), - )); - let annotation = ty::CanonicalUserTypeAnnotation { - inferred_ty: pattern.ty, - span, - user_ty: Box::new(user_ty), - }; - let variance = ty::Contravariant; - extra_data.ascriptions.push(super::Ascription { annotation, source, variance }); - } - - None - } PatKind::Array { ref prefix, ref slice, ref suffix } => { cx.prefix_slice_suffix( diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs index 3acf2a6a2a61..977d4f3e931b 100644 --- a/compiler/rustc_mir_build/src/builder/matches/mod.rs +++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs @@ -920,6 +920,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { PatKind::Constant { .. } | PatKind::Range { .. } + | PatKind::Missing | PatKind::Wild | PatKind::Never | PatKind::Error(_) => {} diff --git a/compiler/rustc_mir_build/src/builder/matches/test.rs b/compiler/rustc_mir_build/src/builder/matches/test.rs index d1f9d4c34fe1..73cc3c86e22f 100644 --- a/compiler/rustc_mir_build/src/builder/matches/test.rs +++ b/compiler/rustc_mir_build/src/builder/matches/test.rs @@ -140,8 +140,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let success_block = target_block(TestBranch::Success); let fail_block = target_block(TestBranch::Failure); - let expect_ty = value.ty(); - let expect = self.literal_operand(test.span, value); + let mut expect_ty = value.ty(); + let mut expect = self.literal_operand(test.span, value); let mut place = place; let mut block = block; @@ -174,6 +174,31 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { place = ref_str; ty = ref_str_ty; } + &ty::Pat(base, _) => { + assert_eq!(ty, value.ty()); + assert!(base.is_trivially_pure_clone_copy()); + + let transmuted_place = self.temp(base, test.span); + self.cfg.push_assign( + block, + self.source_info(scrutinee_span), + transmuted_place, + Rvalue::Cast(CastKind::Transmute, Operand::Copy(place), base), + ); + + let transmuted_expect = self.temp(base, test.span); + self.cfg.push_assign( + block, + self.source_info(test.span), + transmuted_expect, + Rvalue::Cast(CastKind::Transmute, expect, base), + ); + + place = transmuted_place; + expect = Operand::Copy(transmuted_expect); + ty = base; + expect_ty = base; + } _ => {} } @@ -715,7 +740,7 @@ fn trait_method<'tcx>( let item = tcx .associated_items(trait_def_id) .filter_by_name_unhygienic(method_name) - .find(|item| item.kind == ty::AssocKind::Fn) + .find(|item| item.is_fn()) .expect("trait method not found"); let method_ty = Ty::new_fn_def(tcx, item.def_id, args); diff --git a/compiler/rustc_mir_build/src/builder/mod.rs b/compiler/rustc_mir_build/src/builder/mod.rs index 8ca9ab58e457..59a52ae67cb1 100644 --- a/compiler/rustc_mir_build/src/builder/mod.rs +++ b/compiler/rustc_mir_build/src/builder/mod.rs @@ -485,7 +485,7 @@ fn construct_fn<'tcx>( }; if let Some(custom_mir_attr) = - tcx.hir_attrs(fn_id).iter().find(|attr| attr.name_or_empty() == sym::custom_mir) + tcx.hir_attrs(fn_id).iter().find(|attr| attr.has_name(sym::custom_mir)) { return custom::build_custom_mir( tcx, diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index 6fb9974fc8e2..b6a856a6eb4d 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -315,6 +315,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { fn visit_pat(&mut self, pat: &'a Pat<'tcx>) { if self.in_union_destructure { match pat.kind { + PatKind::Missing => unreachable!(), // binding to a variable allows getting stuff out of variable PatKind::Binding { .. } // match is conditional on having this value @@ -403,9 +404,9 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { visit::walk_pat(self, pat); self.inside_adt = old_inside_adt; } - PatKind::ExpandedConstant { def_id, is_inline, .. } => { + PatKind::ExpandedConstant { def_id, .. } => { if let Some(def) = def_id.as_local() - && *is_inline + && matches!(self.tcx.def_kind(def_id), DefKind::InlineConst) { self.visit_inner_body(def); } diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index 0e16f871b16f..ae09db502352 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -2,7 +2,7 @@ use rustc_data_structures::fx::FxIndexMap; use rustc_errors::codes::*; use rustc_errors::{ Applicability, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, - MultiSpan, SubdiagMessageOp, Subdiagnostic, pluralize, + MultiSpan, Subdiagnostic, pluralize, }; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_middle::ty::{self, Ty}; @@ -546,11 +546,7 @@ pub(crate) struct UnsafeNotInheritedLintNote { } impl Subdiagnostic for UnsafeNotInheritedLintNote { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { diag.span_note(self.signature_span, fluent::mir_build_unsafe_fn_safe_body); let body_start = self.body_span.shrink_to_lo(); let body_end = self.body_span.shrink_to_hi(); @@ -1031,11 +1027,7 @@ pub(crate) struct Variant { } impl<'tcx> Subdiagnostic for AdtDefinedHere<'tcx> { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { diag.arg("ty", self.ty); let mut spans = MultiSpan::from(self.adt_def_span); @@ -1117,11 +1109,7 @@ pub(crate) struct Rust2024IncompatiblePatSugg { } impl Subdiagnostic for Rust2024IncompatiblePatSugg { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { // Format and emit explanatory notes about default binding modes. Reversing the spans' order // means if we have nested spans, the innermost ones will be visited first. for (span, def_br_mutbl) in self.default_mode_labels.into_iter().rev() { diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs index a25697ba086d..8e96d46dac27 100644 --- a/compiler/rustc_mir_build/src/lib.rs +++ b/compiler/rustc_mir_build/src/lib.rs @@ -3,7 +3,6 @@ // tidy-alphabetical-start #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] -#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![feature(assert_matches)] #![feature(box_patterns)] #![feature(if_let_guard)] diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 31e22e69111b..fde23413972b 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -191,7 +191,7 @@ impl<'tcx> ThirBuildCx<'tcx> { let pointer_target = ExprKind::Field { lhs: self.thir.exprs.push(expr), variant_index: FIRST_VARIANT, - name: FieldIdx::from(0u32), + name: FieldIdx::ZERO, }; let arg = Expr { temp_lifetime, ty: pin_ty, span, kind: pointer_target }; let arg = self.thir.exprs.push(arg); @@ -226,7 +226,7 @@ impl<'tcx> ThirBuildCx<'tcx> { adt_def: self.tcx.adt_def(pin_did), variant_index: FIRST_VARIANT, args, - fields: Box::new([FieldExpr { name: FieldIdx::from(0u32), expr }]), + fields: Box::new([FieldExpr { name: FieldIdx::ZERO, expr }]), user_ty: None, base: AdtExprBase::None, })); diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs index b3daed8a7e01..2f593b9a0a74 100644 --- a/compiler/rustc_mir_build/src/thir/cx/mod.rs +++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs @@ -113,7 +113,7 @@ impl<'tcx> ThirBuildCx<'tcx> { apply_adjustments: tcx .hir_attrs(hir_id) .iter() - .all(|attr| attr.name_or_empty() != rustc_span::sym::custom_mir), + .all(|attr| !attr.has_name(rustc_span::sym::custom_mir)), } } 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 9f5e2c06b229..78583a402fe9 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -676,7 +676,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> { unpeeled_pat = subpattern; } - if let PatKind::ExpandedConstant { def_id, is_inline: false, .. } = unpeeled_pat.kind + if let PatKind::ExpandedConstant { def_id, .. } = unpeeled_pat.kind && let DefKind::Const = self.tcx.def_kind(def_id) && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(pat.span) // We filter out paths with multiple path::segments. @@ -1296,7 +1296,8 @@ fn report_non_exhaustive_match<'p, 'tcx>( for &arm in arms { let arm = &thir.arms[arm]; - if let PatKind::ExpandedConstant { def_id, is_inline: false, .. } = arm.pattern.kind + if let PatKind::ExpandedConstant { def_id, .. } = arm.pattern.kind + && !matches!(cx.tcx.def_kind(def_id), DefKind::InlineConst) && let Ok(snippet) = cx.tcx.sess.source_map().span_to_snippet(arm.pattern.span) // We filter out paths with multiple path::segments. && snippet.chars().all(|c| c.is_alphanumeric() || c == '_') 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 372453688d24..a40001bf7455 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 @@ -182,7 +182,10 @@ impl<'tcx> ConstToPat<'tcx> { } } - inlined_const_as_pat + // Wrap the pattern in a marker node to indicate that it is the result of lowering a + // constant. This is used for diagnostics, and for unsafety checking of inline const blocks. + let kind = PatKind::ExpandedConstant { subpattern: inlined_const_as_pat, def_id: uv.def }; + Box::new(Pat { kind, ty, span: self.span }) } fn field_pats( diff --git a/compiler/rustc_mir_build/src/thir/pattern/migration.rs b/compiler/rustc_mir_build/src/thir/pattern/migration.rs index bd7787b643d5..12c457f13fc1 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/migration.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/migration.rs @@ -4,8 +4,7 @@ use rustc_data_structures::fx::FxIndexMap; use rustc_errors::MultiSpan; use rustc_hir::{BindingMode, ByRef, HirId, Mutability}; use rustc_lint as lint; -use rustc_middle::span_bug; -use rustc_middle::ty::{self, Rust2024IncompatiblePatInfo, Ty, TyCtxt}; +use rustc_middle::ty::{self, Rust2024IncompatiblePatInfo, TyCtxt}; use rustc_span::{Ident, Span}; use crate::errors::{Rust2024IncompatiblePat, Rust2024IncompatiblePatSugg}; @@ -87,19 +86,18 @@ impl<'a> PatMigration<'a> { } /// Tracks when we're lowering a pattern that implicitly dereferences the scrutinee. - /// This should only be called when the pattern type adjustments list `adjustments` is - /// non-empty. Returns the prior default binding mode; this should be followed by a call to - /// [`PatMigration::leave_ref`] to restore it when we leave the pattern. + /// This should only be called when the pattern type adjustments list `adjustments` contains an + /// implicit deref of a reference type. Returns the prior default binding mode; this should be + /// followed by a call to [`PatMigration::leave_ref`] to restore it when we leave the pattern. pub(super) fn visit_implicit_derefs<'tcx>( &mut self, pat_span: Span, - adjustments: &[Ty<'tcx>], + adjustments: &[ty::adjustment::PatAdjustment<'tcx>], ) -> Option<(Span, Mutability)> { - let implicit_deref_mutbls = adjustments.iter().map(|ref_ty| { - let &ty::Ref(_, _, mutbl) = ref_ty.kind() else { - span_bug!(pat_span, "pattern implicitly dereferences a non-ref type"); - }; - mutbl + // Implicitly dereferencing references changes the default binding mode, but implicit derefs + // of smart pointers do not. Thus, we only consider implicit derefs of reference types. + let implicit_deref_mutbls = adjustments.iter().filter_map(|adjust| { + if let &ty::Ref(_, _, mutbl) = adjust.source.kind() { Some(mutbl) } else { None } }); if !self.info.suggest_eliding_modes { diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index d20e051548bf..8f058efdfacd 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -13,14 +13,16 @@ use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::pat_util::EnumerateAndAdjustIterator; use rustc_hir::{self as hir, LangItem, RangeEnd}; use rustc_index::Idx; +use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::mir::interpret::LitToConstInput; use rustc_middle::thir::{ Ascription, FieldPat, LocalVarId, Pat, PatKind, PatRange, PatRangeBoundary, }; +use rustc_middle::ty::adjustment::{PatAdjust, PatAdjustment}; use rustc_middle::ty::layout::IntegerExt; -use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty, TyCtxt, TypeVisitableExt}; +use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty, TyCtxt, TypingMode}; use rustc_middle::{bug, span_bug}; -use rustc_span::def_id::LocalDefId; +use rustc_span::def_id::DefId; use rustc_span::{ErrorGuaranteed, Span}; use tracing::{debug, instrument}; @@ -62,13 +64,15 @@ pub(super) fn pat_from_hir<'a, 'tcx>( impl<'a, 'tcx> PatCtxt<'a, 'tcx> { fn lower_pattern(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Box> { - let adjustments: &[Ty<'tcx>] = + let adjustments: &[PatAdjustment<'tcx>] = self.typeck_results.pat_adjustments().get(pat.hir_id).map_or(&[], |v| &**v); // Track the default binding mode for the Rust 2024 migration suggestion. + // Implicitly dereferencing references changes the default binding mode, but implicit deref + // patterns do not. Only track binding mode changes if a ref type is in the adjustments. let mut opt_old_mode_span = None; if let Some(s) = &mut self.rust_2024_migration - && !adjustments.is_empty() + && adjustments.iter().any(|adjust| adjust.kind == PatAdjust::BuiltinDeref) { opt_old_mode_span = s.visit_implicit_derefs(pat.span, adjustments); } @@ -101,17 +105,23 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { _ => self.lower_pattern_unadjusted(pat), }; - let adjusted_pat = adjustments.iter().rev().fold(unadjusted_pat, |thir_pat, ref_ty| { - debug!("{:?}: wrapping pattern with type {:?}", thir_pat, ref_ty); - Box::new(Pat { - span: thir_pat.span, - ty: *ref_ty, - kind: PatKind::Deref { subpattern: thir_pat }, - }) + let adjusted_pat = adjustments.iter().rev().fold(unadjusted_pat, |thir_pat, adjust| { + debug!("{:?}: wrapping pattern with adjustment {:?}", thir_pat, adjust); + let span = thir_pat.span; + let kind = match adjust.kind { + PatAdjust::BuiltinDeref => PatKind::Deref { subpattern: thir_pat }, + PatAdjust::OverloadedDeref => { + let mutable = self.typeck_results.pat_has_ref_mut_binding(pat); + let mutability = + if mutable { hir::Mutability::Mut } else { hir::Mutability::Not }; + PatKind::DerefPattern { subpattern: thir_pat, mutability } + } + }; + Box::new(Pat { span, ty: adjust.source, kind }) }); if let Some(s) = &mut self.rust_2024_migration - && !adjustments.is_empty() + && adjustments.iter().any(|adjust| adjust.kind == PatAdjust::BuiltinDeref) { s.leave_ref(opt_old_mode_span); } @@ -124,7 +134,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { expr: Option<&'tcx hir::PatExpr<'tcx>>, // Out-parameters collecting extra data to be reapplied by the caller ascriptions: &mut Vec>, - inline_consts: &mut Vec, + expanded_consts: &mut Vec, ) -> Result>, ErrorGuaranteed> { let Some(expr) = expr else { return Ok(None) }; @@ -139,10 +149,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { ascriptions.push(ascription); kind = subpattern.kind; } - PatKind::ExpandedConstant { is_inline, def_id, subpattern } => { - if is_inline { - inline_consts.extend(def_id.as_local()); - } + PatKind::ExpandedConstant { def_id, subpattern } => { + expanded_consts.push(def_id); kind = subpattern.kind; } _ => break, @@ -221,10 +229,10 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { // Collect extra data while lowering the endpoints, to be reapplied later. let mut ascriptions = vec![]; - let mut inline_consts = vec![]; + let mut expanded_consts = vec![]; let mut lower_endpoint = - |expr| self.lower_pattern_range_endpoint(expr, &mut ascriptions, &mut inline_consts); + |expr| self.lower_pattern_range_endpoint(expr, &mut ascriptions, &mut expanded_consts); let lo = lower_endpoint(lo_expr)?.unwrap_or(PatRangeBoundary::NegInfinity); let hi = lower_endpoint(hi_expr)?.unwrap_or(PatRangeBoundary::PosInfinity); @@ -269,17 +277,12 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { // `Foo::<'a>::A..=Foo::B`), we need to put the ascriptions for the associated // constants somewhere. Have them on the range pattern. for ascription in ascriptions { - kind = PatKind::AscribeUserType { - ascription, - subpattern: Box::new(Pat { span, ty, kind }), - }; + let subpattern = Box::new(Pat { span, ty, kind }); + kind = PatKind::AscribeUserType { ascription, subpattern }; } - for def in inline_consts { - kind = PatKind::ExpandedConstant { - def_id: def.to_def_id(), - is_inline: true, - subpattern: Box::new(Pat { span, ty, kind }), - }; + for def_id in expanded_consts { + let subpattern = Box::new(Pat { span, ty, kind }); + kind = PatKind::ExpandedConstant { def_id, subpattern }; } Ok(kind) } @@ -290,6 +293,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { let mut span = pat.span; let kind = match pat.kind { + hir::PatKind::Missing => PatKind::Missing, + hir::PatKind::Wild => PatKind::Wild, hir::PatKind::Never => PatKind::Never, @@ -567,15 +572,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { // Lower the named constant to a THIR pattern. let args = self.typeck_results.node_args(id); let c = ty::Const::new_unevaluated(self.tcx, ty::UnevaluatedConst { def: def_id, args }); - let subpattern = self.const_to_pat(c, ty, id, span); - - // Wrap the pattern in a marker node to indicate that it is the result - // of lowering a named constant. This marker is used for improved - // diagnostics in some situations, but has no effect at runtime. - let mut pattern = { - let kind = PatKind::ExpandedConstant { subpattern, def_id, is_inline: false }; - Box::new(Pat { span, ty, kind }) - }; + let mut pattern = self.const_to_pat(c, ty, id, span); // If this is an associated constant with an explicit user-written // type, add an ascription node (e.g. ` as MyTrait>::CONST`). @@ -612,18 +609,37 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { let ty = tcx.typeck(def_id).node_type(block.hir_id); let typeck_root_def_id = tcx.typeck_root_def_id(def_id.to_def_id()); - let parent_args = - tcx.erase_regions(ty::GenericArgs::identity_for_item(tcx, typeck_root_def_id)); + let parent_args = ty::GenericArgs::identity_for_item(tcx, typeck_root_def_id); let args = ty::InlineConstArgs::new(tcx, ty::InlineConstArgsParts { parent_args, ty }).args; - debug_assert!(!args.has_free_regions()); - let ct = ty::UnevaluatedConst { def: def_id.to_def_id(), args }; - let subpattern = self.const_to_pat(ty::Const::new_unevaluated(self.tcx, ct), ty, id, span); + let c = ty::Const::new_unevaluated(self.tcx, ct); + let pattern = self.const_to_pat(c, ty, id, span); - // Wrap the pattern in a marker node to indicate that it is the result - // of lowering an inline const block. - PatKind::ExpandedConstant { subpattern, def_id: def_id.to_def_id(), is_inline: true } + // Apply a type ascription for the inline constant. + let annotation = { + let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); + let args = ty::InlineConstArgs::new( + tcx, + ty::InlineConstArgsParts { parent_args, ty: infcx.next_ty_var(span) }, + ) + .args; + infcx.canonicalize_user_type_annotation(ty::UserType::new(ty::UserTypeKind::TypeOf( + def_id.to_def_id(), + ty::UserArgs { args, user_self_ty: None }, + ))) + }; + let annotation = + CanonicalUserTypeAnnotation { user_ty: Box::new(annotation), span, inferred_ty: ty }; + PatKind::AscribeUserType { + subpattern: pattern, + ascription: Ascription { + annotation, + // Note that we use `Contravariant` here. See the `variance` field documentation + // for details. + variance: ty::Contravariant, + }, + } } /// Lowers the kinds of "expression" that can appear in a HIR pattern: @@ -635,43 +651,41 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { expr: &'tcx hir::PatExpr<'tcx>, pat_ty: Option>, ) -> PatKind<'tcx> { - let (lit, neg) = match &expr.kind { - hir::PatExprKind::Path(qpath) => { - return self.lower_path(qpath, expr.hir_id, expr.span).kind; - } + match &expr.kind { + hir::PatExprKind::Path(qpath) => self.lower_path(qpath, expr.hir_id, expr.span).kind, hir::PatExprKind::ConstBlock(anon_const) => { - return self.lower_inline_const(anon_const, expr.hir_id, expr.span); + self.lower_inline_const(anon_const, expr.hir_id, expr.span) } - hir::PatExprKind::Lit { lit, negated } => (lit, *negated), - }; - - // We handle byte string literal patterns by using the pattern's type instead of the - // literal's type in `const_to_pat`: if the literal `b"..."` matches on a slice reference, - // the pattern's type will be `&[u8]` whereas the literal's type is `&[u8; 3]`; using the - // pattern's type means we'll properly translate it to a slice reference pattern. This works - // because slices and arrays have the same valtree representation. - // HACK: As an exception, use the literal's type if `pat_ty` is `String`; this can happen if - // `string_deref_patterns` is enabled. There's a special case for that when lowering to MIR. - // FIXME(deref_patterns): This hack won't be necessary once `string_deref_patterns` is - // superseded by a more general implementation of deref patterns. - let ct_ty = match pat_ty { - Some(pat_ty) - if let ty::Adt(def, _) = *pat_ty.kind() - && self.tcx.is_lang_item(def.did(), LangItem::String) => - { - if !self.tcx.features().string_deref_patterns() { - span_bug!( - expr.span, - "matching on `String` went through without enabling string_deref_patterns" - ); - } - self.typeck_results.node_type(expr.hir_id) + hir::PatExprKind::Lit { lit, negated } => { + // We handle byte string literal patterns by using the pattern's type instead of the + // literal's type in `const_to_pat`: if the literal `b"..."` matches on a slice reference, + // the pattern's type will be `&[u8]` whereas the literal's type is `&[u8; 3]`; using the + // pattern's type means we'll properly translate it to a slice reference pattern. This works + // because slices and arrays have the same valtree representation. + // HACK: As an exception, use the literal's type if `pat_ty` is `String`; this can happen if + // `string_deref_patterns` is enabled. There's a special case for that when lowering to MIR. + // FIXME(deref_patterns): This hack won't be necessary once `string_deref_patterns` is + // superseded by a more general implementation of deref patterns. + let ct_ty = match pat_ty { + Some(pat_ty) + if let ty::Adt(def, _) = *pat_ty.kind() + && self.tcx.is_lang_item(def.did(), LangItem::String) => + { + if !self.tcx.features().string_deref_patterns() { + span_bug!( + expr.span, + "matching on `String` went through without enabling string_deref_patterns" + ); + } + self.typeck_results.node_type(expr.hir_id) + } + Some(pat_ty) => pat_ty, + None => self.typeck_results.node_type(expr.hir_id), + }; + let lit_input = LitToConstInput { lit: &lit.node, ty: ct_ty, neg: *negated }; + let constant = self.tcx.at(expr.span).lit_to_const(lit_input); + self.const_to_pat(constant, ct_ty, expr.hir_id, lit.span).kind } - Some(pat_ty) => pat_ty, - None => self.typeck_results.node_type(expr.hir_id), - }; - let lit_input = LitToConstInput { lit: &lit.node, ty: ct_ty, neg }; - let constant = self.tcx.at(expr.span).lit_to_const(lit_input); - self.const_to_pat(constant, ct_ty, expr.hir_id, lit.span).kind + } } } diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs index 16cef0ec3acb..37248941e2c4 100644 --- a/compiler/rustc_mir_build/src/thir/print.rs +++ b/compiler/rustc_mir_build/src/thir/print.rs @@ -664,6 +664,7 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { print_indented!(self, "kind: PatKind {", depth_lvl); match pat_kind { + PatKind::Missing => unreachable!(), PatKind::Wild => { print_indented!(self, "Wild", depth_lvl + 1); } @@ -740,10 +741,9 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { print_indented!(self, format!("value: {:?}", value), depth_lvl + 2); print_indented!(self, "}", depth_lvl + 1); } - PatKind::ExpandedConstant { def_id, is_inline, subpattern } => { + PatKind::ExpandedConstant { def_id, subpattern } => { print_indented!(self, "ExpandedConstant {", depth_lvl + 1); print_indented!(self, format!("def_id: {def_id:?}"), depth_lvl + 2); - print_indented!(self, format!("is_inline: {is_inline:?}"), depth_lvl + 2); print_indented!(self, "subpattern:", depth_lvl + 2); self.print_pat(subpattern, depth_lvl + 2); print_indented!(self, "}", depth_lvl + 1); diff --git a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs index 448fad2dc3ec..95f488a925b2 100644 --- a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs +++ b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs @@ -109,27 +109,29 @@ impl RustcMirAttrs { .flat_map(|attr| attr.meta_item_list().into_iter().flat_map(|v| v.into_iter())); for attr in rustc_mir_attrs { - let attr_result = if attr.has_name(sym::borrowck_graphviz_postflow) { - Self::set_field(&mut ret.basename_and_suffix, tcx, &attr, |s| { - let path = PathBuf::from(s.to_string()); - match path.file_name() { - Some(_) => Ok(path), - None => { - tcx.dcx().emit_err(PathMustEndInFilename { span: attr.span() }); + let attr_result = match attr.name() { + Some(name @ sym::borrowck_graphviz_postflow) => { + Self::set_field(&mut ret.basename_and_suffix, tcx, name, &attr, |s| { + let path = PathBuf::from(s.to_string()); + match path.file_name() { + Some(_) => Ok(path), + None => { + tcx.dcx().emit_err(PathMustEndInFilename { span: attr.span() }); + Err(()) + } + } + }) + } + Some(name @ sym::borrowck_graphviz_format) => { + Self::set_field(&mut ret.formatter, tcx, name, &attr, |s| match s { + sym::two_phase => Ok(s), + _ => { + tcx.dcx().emit_err(UnknownFormatter { span: attr.span() }); Err(()) } - } - }) - } else if attr.has_name(sym::borrowck_graphviz_format) { - Self::set_field(&mut ret.formatter, tcx, &attr, |s| match s { - sym::gen_kill | sym::two_phase => Ok(s), - _ => { - tcx.dcx().emit_err(UnknownFormatter { span: attr.span() }); - Err(()) - } - }) - } else { - Ok(()) + }) + } + _ => Ok(()), }; result = result.and(attr_result); @@ -141,12 +143,12 @@ impl RustcMirAttrs { fn set_field( field: &mut Option, tcx: TyCtxt<'_>, + name: Symbol, attr: &ast::MetaItemInner, mapper: impl FnOnce(Symbol) -> Result, ) -> Result<(), ()> { if field.is_some() { - tcx.dcx() - .emit_err(DuplicateValuesFor { span: attr.span(), name: attr.name_or_empty() }); + tcx.dcx().emit_err(DuplicateValuesFor { span: attr.span(), name }); return Err(()); } @@ -156,7 +158,7 @@ impl RustcMirAttrs { Ok(()) } else { tcx.dcx() - .emit_err(RequiresAnArgument { span: attr.span(), name: attr.name_or_empty() }); + .emit_err(RequiresAnArgument { span: attr.span(), name: attr.name().unwrap() }); Err(()) } } diff --git a/compiler/rustc_mir_dataflow/src/lib.rs b/compiler/rustc_mir_dataflow/src/lib.rs index 82c57ef5678d..a0efc623b8e7 100644 --- a/compiler/rustc_mir_dataflow/src/lib.rs +++ b/compiler/rustc_mir_dataflow/src/lib.rs @@ -1,5 +1,4 @@ // tidy-alphabetical-start -#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![feature(assert_matches)] #![feature(associated_type_defaults)] #![feature(box_patterns)] diff --git a/compiler/rustc_mir_transform/src/check_undefined_transmutes.rs b/compiler/rustc_mir_transform/src/check_undefined_transmutes.rs index ed3b1ae4f42f..daddb5dedbcf 100644 --- a/compiler/rustc_mir_transform/src/check_undefined_transmutes.rs +++ b/compiler/rustc_mir_transform/src/check_undefined_transmutes.rs @@ -42,7 +42,7 @@ impl<'a, 'tcx> UndefinedTransmutesChecker<'a, 'tcx> { if self.tcx.is_const_fn(def_id) || matches!( self.tcx.opt_associated_item(def_id), - Some(AssocItem { kind: AssocKind::Const, .. }) + Some(AssocItem { kind: AssocKind::Const { .. }, .. }) ) { let fn_sig = function.ty(self.body, self.tcx).fn_sig(self.tcx).skip_binder(); diff --git a/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs b/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs index cb8440198573..4be67b873f73 100644 --- a/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs +++ b/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs @@ -35,7 +35,8 @@ impl<'tcx> crate::MirPass<'tcx> for CleanupPostBorrowck { // MIR building, and are not needed after InstrumentCoverage. CoverageKind::BlockMarker { .. } | CoverageKind::SpanMarker { .. }, ) - | StatementKind::FakeRead(..) => statement.make_nop(), + | StatementKind::FakeRead(..) + | StatementKind::BackwardIncompatibleDropHint { .. } => statement.make_nop(), StatementKind::Assign(box ( _, Rvalue::Cast( diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index 04d96f117072..92d5e152f58e 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -203,7 +203,7 @@ struct TransformVisitor<'tcx> { impl<'tcx> TransformVisitor<'tcx> { fn insert_none_ret_block(&self, body: &mut Body<'tcx>) -> BasicBlock { - let block = BasicBlock::new(body.basic_blocks.len()); + let block = body.basic_blocks.next_index(); let source_info = SourceInfo::outermost(body.span); let none_value = match self.coroutine_kind { @@ -547,7 +547,7 @@ fn transform_async_context<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { let get_context_def_id = tcx.require_lang_item(LangItem::GetContext, None); - for bb in START_BLOCK..body.basic_blocks.next_index() { + for bb in body.basic_blocks.indices() { let bb_data = &body[bb]; if bb_data.is_cleanup { continue; @@ -556,11 +556,11 @@ fn transform_async_context<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { match &bb_data.terminator().kind { TerminatorKind::Call { func, .. } => { let func_ty = func.ty(body, tcx); - if let ty::FnDef(def_id, _) = *func_ty.kind() { - if def_id == get_context_def_id { - let local = eliminate_get_context_call(&mut body[bb]); - replace_resume_ty_local(tcx, body, local, context_mut_ref); - } + if let ty::FnDef(def_id, _) = *func_ty.kind() + && def_id == get_context_def_id + { + let local = eliminate_get_context_call(&mut body[bb]); + replace_resume_ty_local(tcx, body, local, context_mut_ref); } } TerminatorKind::Yield { resume_arg, .. } => { @@ -1057,7 +1057,7 @@ fn insert_switch<'tcx>( let blocks = body.basic_blocks_mut().iter_mut(); for target in blocks.flat_map(|b| b.terminator_mut().successors_mut()) { - *target = BasicBlock::new(target.index() + 1); + *target += 1; } } @@ -1169,6 +1169,13 @@ fn create_coroutine_drop_shim<'tcx>( dump_mir(tcx, false, "coroutine_drop", &0, &body, |_, _| Ok(())); body.source.instance = drop_instance; + // Creating a coroutine drop shim happens on `Analysis(PostCleanup) -> Runtime(Initial)` + // but the pass manager doesn't update the phase of the coroutine drop shim. Update the + // phase of the drop shim so that later on when we run the pass manager on the shim, in + // the `mir_shims` query, we don't ICE on the intra-pass validation before we've updated + // the phase of the body from analysis. + body.phase = MirPhase::Runtime(RuntimePhase::Initial); + body } @@ -1186,7 +1193,7 @@ fn insert_panic_block<'tcx>( body: &mut Body<'tcx>, message: AssertMessage<'tcx>, ) -> BasicBlock { - let assert_block = BasicBlock::new(body.basic_blocks.len()); + let assert_block = body.basic_blocks.next_index(); let kind = TerminatorKind::Assert { cond: Operand::Constant(Box::new(ConstOperand { span: body.span, @@ -1209,14 +1216,8 @@ fn can_return<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, typing_env: ty::Typing } // If there's a return terminator the function may return. - for block in body.basic_blocks.iter() { - if let TerminatorKind::Return = block.terminator().kind { - return true; - } - } - + body.basic_blocks.iter().any(|block| matches!(block.terminator().kind, TerminatorKind::Return)) // Otherwise the function can't return. - false } fn can_unwind<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) -> bool { @@ -1293,12 +1294,12 @@ fn create_coroutine_resume_function<'tcx>( kind: TerminatorKind::Goto { target: poison_block }, }; } - } else if !block.is_cleanup { + } else if !block.is_cleanup // Any terminators that *can* unwind but don't have an unwind target set are also // pointed at our poisoning block (unless they're part of the cleanup path). - if let Some(unwind @ UnwindAction::Continue) = block.terminator_mut().unwind_mut() { - *unwind = UnwindAction::Cleanup(poison_block); - } + && let Some(unwind @ UnwindAction::Continue) = block.terminator_mut().unwind_mut() + { + *unwind = UnwindAction::Cleanup(poison_block); } } } @@ -1340,12 +1341,14 @@ fn create_coroutine_resume_function<'tcx>( make_coroutine_state_argument_indirect(tcx, body); match transform.coroutine_kind { + CoroutineKind::Coroutine(_) + | CoroutineKind::Desugared(CoroutineDesugaring::Async | CoroutineDesugaring::AsyncGen, _) => + { + make_coroutine_state_argument_pinned(tcx, body); + } // Iterator::next doesn't accept a pinned argument, // unlike for all other coroutine kinds. CoroutineKind::Desugared(CoroutineDesugaring::Gen, _) => {} - _ => { - make_coroutine_state_argument_pinned(tcx, body); - } } // Make sure we remove dead blocks to remove @@ -1408,8 +1411,7 @@ fn create_cases<'tcx>( let mut statements = Vec::new(); // Create StorageLive instructions for locals with live storage - for i in 0..(body.local_decls.len()) { - let l = Local::new(i); + for l in body.local_decls.indices() { let needs_storage_live = point.storage_liveness.contains(l) && !transform.remap.contains(l) && !transform.always_live_locals.contains(l); @@ -1535,15 +1537,10 @@ impl<'tcx> crate::MirPass<'tcx> for StateTransform { let coroutine_kind = body.coroutine_kind().unwrap(); // Get the discriminant type and args which typeck computed - let (discr_ty, movable) = match *coroutine_ty.kind() { - ty::Coroutine(_, args) => { - let args = args.as_coroutine(); - (args.discr_ty(tcx), coroutine_kind.movability() == hir::Movability::Movable) - } - _ => { - tcx.dcx().span_bug(body.span, format!("unexpected coroutine type {coroutine_ty}")); - } + let ty::Coroutine(_, args) = coroutine_ty.kind() else { + tcx.dcx().span_bug(body.span, format!("unexpected coroutine type {coroutine_ty}")); }; + let discr_ty = args.as_coroutine().discr_ty(tcx); let new_ret_ty = match coroutine_kind { CoroutineKind::Desugared(CoroutineDesugaring::Async, _) => { @@ -1610,6 +1607,7 @@ impl<'tcx> crate::MirPass<'tcx> for StateTransform { let always_live_locals = always_storage_live_locals(body); + let movable = coroutine_kind.movability() == hir::Movability::Movable; let liveness_info = locals_live_across_suspend_points(tcx, body, &always_live_locals, movable); diff --git a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs index 57f7893be1b8..d49f5d9f9c38 100644 --- a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs +++ b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs @@ -103,9 +103,8 @@ impl<'tcx> crate::MirPass<'tcx> for EarlyOtherwiseBranch { let mut should_cleanup = false; // Also consider newly generated bbs in the same pass - for i in 0..body.basic_blocks.len() { + for parent in body.basic_blocks.indices() { let bbs = &*body.basic_blocks; - let parent = BasicBlock::from_usize(i); let Some(opt_data) = evaluate_candidate(tcx, body, parent) else { continue }; trace!("SUCCESS: found optimization possibility to apply: {opt_data:?}"); diff --git a/compiler/rustc_mir_transform/src/elaborate_drop.rs b/compiler/rustc_mir_transform/src/elaborate_drop.rs index 0d8cf524661c..e3057a2f648f 100644 --- a/compiler/rustc_mir_transform/src/elaborate_drop.rs +++ b/compiler/rustc_mir_transform/src/elaborate_drop.rs @@ -258,31 +258,27 @@ where ) -> Vec<(Place<'tcx>, Option)> { variant .fields - .iter() - .enumerate() - .map(|(i, f)| { - let field = FieldIdx::new(i); - let subpath = self.elaborator.field_subpath(variant_path, field); + .iter_enumerated() + .map(|(field_idx, field)| { + let subpath = self.elaborator.field_subpath(variant_path, field_idx); let tcx = self.tcx(); assert_eq!(self.elaborator.typing_env().typing_mode, ty::TypingMode::PostAnalysis); - // The type error for normalization may have been in dropck: see - // `compute_drop_data` in rustc_borrowck, in which case we wouldn't have - // deleted the MIR body and could have an error here as well. - let field_ty = match tcx - .try_normalize_erasing_regions(self.elaborator.typing_env(), f.ty(tcx, args)) - { + let field_ty = match tcx.try_normalize_erasing_regions( + self.elaborator.typing_env(), + field.ty(tcx, args), + ) { Ok(t) => t, Err(_) => Ty::new_error( self.tcx(), - self.elaborator - .body() - .tainted_by_errors - .expect("Error in drop elaboration not found by dropck."), + self.tcx().dcx().span_delayed_bug( + self.elaborator.body().span, + "Error normalizing in drop elaboration.", + ), ), }; - (tcx.mk_place_field(base_place, field, field_ty), subpath) + (tcx.mk_place_field(base_place, field_idx, field_ty), subpath) }) .collect() } diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 68bc0ffce6b5..8b8d1efbbd2e 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -980,27 +980,17 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } } - let tcx = self.tcx; - let mut projection = SmallVec::<[PlaceElem<'tcx>; 1]>::new(); - loop { - if let Some(local) = self.try_as_local(copy_from_local_value, location) { - projection.reverse(); - let place = Place { local, projection: tcx.mk_place_elems(projection.as_slice()) }; - if rvalue.ty(self.local_decls, tcx) == place.ty(self.local_decls, tcx).ty { - self.reused_locals.insert(local); - *rvalue = Rvalue::Use(Operand::Copy(place)); - return Some(copy_from_value); - } - return None; - } else if let Value::Projection(pointer, proj) = *self.get(copy_from_local_value) - && let Some(proj) = self.try_as_place_elem(proj, location) - { - projection.push(proj); - copy_from_local_value = pointer; - } else { - return None; + // Allow introducing places with non-constant offsets, as those are still better than + // reconstructing an aggregate. + if let Some(place) = self.try_as_place(copy_from_local_value, location, true) { + if rvalue.ty(self.local_decls, self.tcx) == place.ty(self.local_decls, self.tcx).ty { + self.reused_locals.insert(place.local); + *rvalue = Rvalue::Use(Operand::Copy(place)); + return Some(copy_from_local_value); } } + + None } fn simplify_aggregate( @@ -1672,14 +1662,14 @@ fn op_to_prop_const<'tcx>( } impl<'tcx> VnState<'_, 'tcx> { - /// If either [`Self::try_as_constant`] as [`Self::try_as_local`] succeeds, + /// If either [`Self::try_as_constant`] as [`Self::try_as_place`] succeeds, /// returns that result as an [`Operand`]. fn try_as_operand(&mut self, index: VnIndex, location: Location) -> Option> { if let Some(const_) = self.try_as_constant(index) { Some(Operand::Constant(Box::new(const_))) - } else if let Some(local) = self.try_as_local(index, location) { - self.reused_locals.insert(local); - Some(Operand::Copy(local.into())) + } else if let Some(place) = self.try_as_place(index, location, false) { + self.reused_locals.insert(place.local); + Some(Operand::Copy(place)) } else { None } @@ -1712,6 +1702,35 @@ impl<'tcx> VnState<'_, 'tcx> { Some(ConstOperand { span: DUMMY_SP, user_ty: None, const_ }) } + /// Construct a place which holds the same value as `index` and for which all locals strictly + /// dominate `loc`. If you used this place, add its base local to `reused_locals` to remove + /// storage statements. + #[instrument(level = "trace", skip(self), ret)] + fn try_as_place( + &mut self, + mut index: VnIndex, + loc: Location, + allow_complex_projection: bool, + ) -> Option> { + let mut projection = SmallVec::<[PlaceElem<'tcx>; 1]>::new(); + loop { + if let Some(local) = self.try_as_local(index, loc) { + projection.reverse(); + let place = + Place { local, projection: self.tcx.mk_place_elems(projection.as_slice()) }; + return Some(place); + } else if let Value::Projection(pointer, proj) = *self.get(index) + && (allow_complex_projection || proj.is_stable_offset()) + && let Some(proj) = self.try_as_place_elem(proj, loc) + { + projection.push(proj); + index = pointer; + } else { + return None; + } + } + } + /// If there is a local which is assigned `index`, and its assignment strictly dominates `loc`, /// return it. If you used this local, add it to `reused_locals` to remove storage statements. fn try_as_local(&mut self, index: VnIndex, loc: Location) -> Option { @@ -1762,11 +1781,12 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, 'tcx> { if let Some(value) = value { if let Some(const_) = self.try_as_constant(value) { *rvalue = Rvalue::Use(Operand::Constant(Box::new(const_))); - } else if let Some(local) = self.try_as_local(value, location) - && *rvalue != Rvalue::Use(Operand::Move(local.into())) + } else if let Some(place) = self.try_as_place(value, location, false) + && *rvalue != Rvalue::Use(Operand::Move(place)) + && *rvalue != Rvalue::Use(Operand::Copy(place)) { - *rvalue = Rvalue::Use(Operand::Copy(local.into())); - self.reused_locals.insert(local); + *rvalue = Rvalue::Use(Operand::Copy(place)); + self.reused_locals.insert(place.local); } } } diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index 0ab24e48d443..69e80ed54eae 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -903,9 +903,9 @@ fn inline_call<'tcx, I: Inliner<'tcx>>( let mut integrator = Integrator { args: &args, - new_locals: Local::new(caller_body.local_decls.len()).., - new_scopes: SourceScope::new(caller_body.source_scopes.len()).., - new_blocks: BasicBlock::new(caller_body.basic_blocks.len()).., + new_locals: caller_body.local_decls.next_index().., + new_scopes: caller_body.source_scopes.next_index().., + new_blocks: caller_body.basic_blocks.next_index().., destination: destination_local, callsite_scope: caller_body.source_scopes[callsite.source_info.scope].clone(), callsite, @@ -1169,7 +1169,7 @@ impl Integrator<'_, '_> { if idx < self.args.len() { self.args[idx] } else { - Local::new(self.new_locals.start.index() + (idx - self.args.len())) + self.new_locals.start + (idx - self.args.len()) } }; trace!("mapping local `{:?}` to `{:?}`", local, new); @@ -1177,13 +1177,13 @@ impl Integrator<'_, '_> { } fn map_scope(&self, scope: SourceScope) -> SourceScope { - let new = SourceScope::new(self.new_scopes.start.index() + scope.index()); + let new = self.new_scopes.start + scope.index(); trace!("mapping scope `{:?}` to `{:?}`", scope, new); new } fn map_block(&self, block: BasicBlock) -> BasicBlock { - let new = BasicBlock::new(self.new_blocks.start.index() + block.index()); + let new = self.new_blocks.start + block.index(); trace!("mapping block `{:?}` to `{:?}`", block, new); new } diff --git a/compiler/rustc_mir_transform/src/instsimplify.rs b/compiler/rustc_mir_transform/src/instsimplify.rs index 2eff6b31372f..5f0c55ddc092 100644 --- a/compiler/rustc_mir_transform/src/instsimplify.rs +++ b/compiler/rustc_mir_transform/src/instsimplify.rs @@ -10,7 +10,6 @@ use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, layout}; use rustc_span::{DUMMY_SP, Symbol, sym}; use crate::simplify::simplify_duplicate_switch_targets; -use crate::take_array; pub(super) enum InstSimplify { BeforeInline, @@ -39,26 +38,26 @@ impl<'tcx> crate::MirPass<'tcx> for InstSimplify { attr::contains_name(tcx.hir_krate_attrs(), sym::rustc_preserve_ub_checks); 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)) => { - if !preserve_ub_checks { - ctx.simplify_ub_check(rvalue); - } - ctx.simplify_bool_cmp(rvalue); - ctx.simplify_ref_deref(rvalue); - ctx.simplify_ptr_aggregate(rvalue); - ctx.simplify_cast(rvalue); - ctx.simplify_repeated_aggregate(rvalue); - ctx.simplify_repeat_once(rvalue); - } - _ => {} + let StatementKind::Assign(box (.., rvalue)) = &mut statement.kind else { + continue; + }; + + if !preserve_ub_checks { + ctx.simplify_ub_check(rvalue); } + ctx.simplify_bool_cmp(rvalue); + ctx.simplify_ref_deref(rvalue); + ctx.simplify_ptr_aggregate(rvalue); + ctx.simplify_cast(rvalue); + ctx.simplify_repeated_aggregate(rvalue); + ctx.simplify_repeat_once(rvalue); } - ctx.simplify_primitive_clone(block.terminator.as_mut().unwrap(), &mut block.statements); - ctx.simplify_intrinsic_assert(block.terminator.as_mut().unwrap()); - ctx.simplify_nounwind_call(block.terminator.as_mut().unwrap()); - simplify_duplicate_switch_targets(block.terminator.as_mut().unwrap()); + let terminator = block.terminator.as_mut().unwrap(); + ctx.simplify_primitive_clone(terminator, &mut block.statements); + ctx.simplify_intrinsic_assert(terminator); + ctx.simplify_nounwind_call(terminator); + simplify_duplicate_switch_targets(terminator); } } @@ -105,43 +104,34 @@ impl<'tcx> InstSimplifyContext<'_, 'tcx> { /// Transform boolean comparisons into logical operations. fn simplify_bool_cmp(&self, rvalue: &mut Rvalue<'tcx>) { - match rvalue { - Rvalue::BinaryOp(op @ (BinOp::Eq | BinOp::Ne), box (a, b)) => { - let new = match (op, self.try_eval_bool(a), self.try_eval_bool(b)) { - // Transform "Eq(a, true)" ==> "a" - (BinOp::Eq, _, Some(true)) => Some(Rvalue::Use(a.clone())), + let Rvalue::BinaryOp(op @ (BinOp::Eq | BinOp::Ne), box (a, b)) = &*rvalue else { return }; + *rvalue = match (op, self.try_eval_bool(a), self.try_eval_bool(b)) { + // Transform "Eq(a, true)" ==> "a" + (BinOp::Eq, _, Some(true)) => Rvalue::Use(a.clone()), - // Transform "Ne(a, false)" ==> "a" - (BinOp::Ne, _, Some(false)) => Some(Rvalue::Use(a.clone())), + // Transform "Ne(a, false)" ==> "a" + (BinOp::Ne, _, Some(false)) => Rvalue::Use(a.clone()), - // Transform "Eq(true, b)" ==> "b" - (BinOp::Eq, Some(true), _) => Some(Rvalue::Use(b.clone())), + // Transform "Eq(true, b)" ==> "b" + (BinOp::Eq, Some(true), _) => Rvalue::Use(b.clone()), - // Transform "Ne(false, b)" ==> "b" - (BinOp::Ne, Some(false), _) => Some(Rvalue::Use(b.clone())), + // Transform "Ne(false, b)" ==> "b" + (BinOp::Ne, Some(false), _) => Rvalue::Use(b.clone()), - // Transform "Eq(false, b)" ==> "Not(b)" - (BinOp::Eq, Some(false), _) => Some(Rvalue::UnaryOp(UnOp::Not, b.clone())), + // Transform "Eq(false, b)" ==> "Not(b)" + (BinOp::Eq, Some(false), _) => Rvalue::UnaryOp(UnOp::Not, b.clone()), - // Transform "Ne(true, b)" ==> "Not(b)" - (BinOp::Ne, Some(true), _) => Some(Rvalue::UnaryOp(UnOp::Not, b.clone())), + // Transform "Ne(true, b)" ==> "Not(b)" + (BinOp::Ne, Some(true), _) => Rvalue::UnaryOp(UnOp::Not, b.clone()), - // Transform "Eq(a, false)" ==> "Not(a)" - (BinOp::Eq, _, Some(false)) => Some(Rvalue::UnaryOp(UnOp::Not, a.clone())), + // Transform "Eq(a, false)" ==> "Not(a)" + (BinOp::Eq, _, Some(false)) => Rvalue::UnaryOp(UnOp::Not, a.clone()), - // Transform "Ne(a, true)" ==> "Not(a)" - (BinOp::Ne, _, Some(true)) => Some(Rvalue::UnaryOp(UnOp::Not, a.clone())), + // Transform "Ne(a, true)" ==> "Not(a)" + (BinOp::Ne, _, Some(true)) => Rvalue::UnaryOp(UnOp::Not, a.clone()), - _ => None, - }; - - if let Some(new) = new { - *rvalue = new; - } - } - - _ => {} - } + _ => return, + }; } fn try_eval_bool(&self, a: &Operand<'_>) -> Option { @@ -151,64 +141,58 @@ impl<'tcx> InstSimplifyContext<'_, 'tcx> { /// Transform `&(*a)` ==> `a`. fn simplify_ref_deref(&self, rvalue: &mut Rvalue<'tcx>) { - if let Rvalue::Ref(_, _, place) | Rvalue::RawPtr(_, place) = rvalue { - if let Some((base, ProjectionElem::Deref)) = place.as_ref().last_projection() { - if rvalue.ty(self.local_decls, self.tcx) != base.ty(self.local_decls, self.tcx).ty { - return; - } - - *rvalue = Rvalue::Use(Operand::Copy(Place { - local: base.local, - projection: self.tcx.mk_place_elems(base.projection), - })); - } + if let Rvalue::Ref(_, _, place) | Rvalue::RawPtr(_, place) = rvalue + && let Some((base, ProjectionElem::Deref)) = place.as_ref().last_projection() + && rvalue.ty(self.local_decls, self.tcx) == base.ty(self.local_decls, self.tcx).ty + { + *rvalue = Rvalue::Use(Operand::Copy(Place { + local: base.local, + projection: self.tcx.mk_place_elems(base.projection), + })); } } /// Transform `Aggregate(RawPtr, [p, ()])` ==> `Cast(PtrToPtr, p)`. fn simplify_ptr_aggregate(&self, rvalue: &mut Rvalue<'tcx>) { if let Rvalue::Aggregate(box AggregateKind::RawPtr(pointee_ty, mutability), fields) = rvalue + && let meta_ty = fields.raw[1].ty(self.local_decls, self.tcx) + && meta_ty.is_unit() { - let meta_ty = fields.raw[1].ty(self.local_decls, self.tcx); - if meta_ty.is_unit() { - // The mutable borrows we're holding prevent printing `rvalue` here - let mut fields = std::mem::take(fields); - let _meta = fields.pop().unwrap(); - let data = fields.pop().unwrap(); - let ptr_ty = Ty::new_ptr(self.tcx, *pointee_ty, *mutability); - *rvalue = Rvalue::Cast(CastKind::PtrToPtr, data, ptr_ty); - } + // The mutable borrows we're holding prevent printing `rvalue` here + let mut fields = std::mem::take(fields); + let _meta = fields.pop().unwrap(); + let data = fields.pop().unwrap(); + let ptr_ty = Ty::new_ptr(self.tcx, *pointee_ty, *mutability); + *rvalue = Rvalue::Cast(CastKind::PtrToPtr, data, ptr_ty); } } fn simplify_ub_check(&self, rvalue: &mut Rvalue<'tcx>) { - if let Rvalue::NullaryOp(NullOp::UbChecks, _) = *rvalue { - let const_ = Const::from_bool(self.tcx, self.tcx.sess.ub_checks()); - let constant = ConstOperand { span: DUMMY_SP, const_, user_ty: None }; - *rvalue = Rvalue::Use(Operand::Constant(Box::new(constant))); - } + let Rvalue::NullaryOp(NullOp::UbChecks, _) = *rvalue else { return }; + + let const_ = Const::from_bool(self.tcx, self.tcx.sess.ub_checks()); + let constant = ConstOperand { span: DUMMY_SP, const_, user_ty: None }; + *rvalue = Rvalue::Use(Operand::Constant(Box::new(constant))); } fn simplify_cast(&self, rvalue: &mut Rvalue<'tcx>) { - if let Rvalue::Cast(kind, operand, cast_ty) = rvalue { - let operand_ty = operand.ty(self.local_decls, self.tcx); - if operand_ty == *cast_ty { - *rvalue = Rvalue::Use(operand.clone()); - } else if *kind == CastKind::Transmute { - // Transmuting an integer to another integer is just a signedness cast - if let (ty::Int(int), ty::Uint(uint)) | (ty::Uint(uint), ty::Int(int)) = - (operand_ty.kind(), cast_ty.kind()) - && int.bit_width() == uint.bit_width() - { - // The width check isn't strictly necessary, as different widths - // are UB and thus we'd be allowed to turn it into a cast anyway. - // But let's keep the UB around for codegen to exploit later. - // (If `CastKind::Transmute` ever becomes *not* UB for mismatched sizes, - // then the width check is necessary for big-endian correctness.) - *kind = CastKind::IntToInt; - return; - } - } + let Rvalue::Cast(kind, operand, cast_ty) = rvalue else { return }; + + let operand_ty = operand.ty(self.local_decls, self.tcx); + if operand_ty == *cast_ty { + *rvalue = Rvalue::Use(operand.clone()); + } else if *kind == CastKind::Transmute + // Transmuting an integer to another integer is just a signedness cast + && let (ty::Int(int), ty::Uint(uint)) | (ty::Uint(uint), ty::Int(int)) = + (operand_ty.kind(), cast_ty.kind()) + && int.bit_width() == uint.bit_width() + { + // The width check isn't strictly necessary, as different widths + // are UB and thus we'd be allowed to turn it into a cast anyway. + // But let's keep the UB around for codegen to exploit later. + // (If `CastKind::Transmute` ever becomes *not* UB for mismatched sizes, + // then the width check is necessary for big-endian correctness.) + *kind = CastKind::IntToInt; } } @@ -229,7 +213,9 @@ impl<'tcx> InstSimplifyContext<'_, 'tcx> { terminator: &mut Terminator<'tcx>, statements: &mut Vec>, ) { - let TerminatorKind::Call { func, args, destination, target, .. } = &mut terminator.kind + let TerminatorKind::Call { + func, args, destination, target: Some(destination_block), .. + } = &terminator.kind else { return; }; @@ -237,15 +223,8 @@ impl<'tcx> InstSimplifyContext<'_, 'tcx> { // It's definitely not a clone if there are multiple arguments let [arg] = &args[..] else { return }; - let Some(destination_block) = *target else { return }; - // Only bother looking more if it's easy to know what we're calling - let Some((fn_def_id, fn_args)) = func.const_fn_def() else { return }; - - // Clone needs one arg, so we can cheaply rule out other stuff - if fn_args.len() != 1 { - return; - } + let Some((fn_def_id, ..)) = func.const_fn_def() else { return }; // These types are easily available from locals, so check that before // doing DefId lookups to figure out what we're actually calling. @@ -253,15 +232,12 @@ impl<'tcx> InstSimplifyContext<'_, 'tcx> { let ty::Ref(_region, inner_ty, Mutability::Not) = *arg_ty.kind() else { return }; - if !inner_ty.is_trivially_pure_clone_copy() { + if !self.tcx.is_lang_item(fn_def_id, LangItem::CloneFn) + || !inner_ty.is_trivially_pure_clone_copy() + { return; } - if !self.tcx.is_lang_item(fn_def_id, LangItem::CloneFn) { - return; - } - - let Ok([arg]) = take_array(args) else { return }; let Some(arg_place) = arg.node.place() else { return }; statements.push(Statement { @@ -273,11 +249,11 @@ impl<'tcx> InstSimplifyContext<'_, 'tcx> { )), ))), }); - terminator.kind = TerminatorKind::Goto { target: destination_block }; + terminator.kind = TerminatorKind::Goto { target: *destination_block }; } fn simplify_nounwind_call(&self, terminator: &mut Terminator<'tcx>) { - let TerminatorKind::Call { func, unwind, .. } = &mut terminator.kind else { + let TerminatorKind::Call { ref func, ref mut unwind, .. } = terminator.kind else { return; }; @@ -290,7 +266,7 @@ impl<'tcx> InstSimplifyContext<'_, 'tcx> { ty::FnDef(..) => body_ty.fn_sig(self.tcx).abi(), ty::Closure(..) => ExternAbi::RustCall, ty::Coroutine(..) => ExternAbi::Rust, - _ => bug!("unexpected body ty: {:?}", body_ty), + _ => bug!("unexpected body ty: {body_ty:?}"), }; if !layout::fn_can_unwind(self.tcx, Some(def_id), body_abi) { @@ -299,10 +275,9 @@ impl<'tcx> InstSimplifyContext<'_, 'tcx> { } fn simplify_intrinsic_assert(&self, terminator: &mut Terminator<'tcx>) { - let TerminatorKind::Call { func, target, .. } = &mut terminator.kind else { - return; - }; - let Some(target_block) = target else { + let TerminatorKind::Call { ref func, target: ref mut target @ Some(target_block), .. } = + terminator.kind + else { return; }; let func_ty = func.ty(self.local_decls, self.tcx); @@ -310,12 +285,10 @@ impl<'tcx> InstSimplifyContext<'_, 'tcx> { return; }; // The intrinsics we are interested in have one generic parameter - if args.is_empty() { - return; - } + let [arg, ..] = args[..] else { return }; let known_is_valid = - intrinsic_assert_panics(self.tcx, self.typing_env, args[0], intrinsic_name); + intrinsic_assert_panics(self.tcx, self.typing_env, arg, intrinsic_name); match known_is_valid { // We don't know the layout or it's not validity assertion at all, don't touch it None => {} @@ -325,7 +298,7 @@ impl<'tcx> InstSimplifyContext<'_, 'tcx> { } Some(false) => { // If we know the assert does not panic, turn the call into a Goto - terminator.kind = TerminatorKind::Goto { target: *target_block }; + terminator.kind = TerminatorKind::Goto { target: target_block }; } } } @@ -346,9 +319,7 @@ fn resolve_rust_intrinsic<'tcx>( tcx: TyCtxt<'tcx>, func_ty: Ty<'tcx>, ) -> Option<(Symbol, GenericArgsRef<'tcx>)> { - if let ty::FnDef(def_id, args) = *func_ty.kind() { - let intrinsic = tcx.intrinsic(def_id)?; - return Some((intrinsic.name, args)); - } - None + let ty::FnDef(def_id, args) = *func_ty.kind() else { return None }; + let intrinsic = tcx.intrinsic(def_id)?; + Some((intrinsic.name, args)) } diff --git a/compiler/rustc_mir_transform/src/jump_threading.rs b/compiler/rustc_mir_transform/src/jump_threading.rs index 0a72a9d669fe..8b4b214a3d45 100644 --- a/compiler/rustc_mir_transform/src/jump_threading.rs +++ b/compiler/rustc_mir_transform/src/jump_threading.rs @@ -90,7 +90,11 @@ impl<'tcx> crate::MirPass<'tcx> for JumpThreading { }; for bb in body.basic_blocks.indices() { - finder.start_from_switch(bb); + let old_len = finder.opportunities.len(); + // If we have any const-eval errors discard any opportunities found + if finder.start_from_switch(bb).is_none() { + finder.opportunities.truncate(old_len); + } } let opportunities = finder.opportunities; @@ -150,14 +154,6 @@ impl Condition { fn matches(&self, value: ScalarInt) -> bool { (self.value == value) == (self.polarity == Polarity::Eq) } - - fn inv(mut self) -> Self { - self.polarity = match self.polarity { - Polarity::Eq => Polarity::Ne, - Polarity::Ne => Polarity::Eq, - }; - self - } } #[derive(Copy, Clone, Debug)] @@ -180,8 +176,21 @@ impl<'a> ConditionSet<'a> { self.iter().filter(move |c| c.matches(value)) } - fn map(self, arena: &'a DroplessArena, f: impl Fn(Condition) -> Condition) -> ConditionSet<'a> { - ConditionSet(arena.alloc_from_iter(self.iter().map(f))) + fn map( + self, + arena: &'a DroplessArena, + f: impl Fn(Condition) -> Option, + ) -> Option> { + let mut all_ok = true; + let set = arena.alloc_from_iter(self.iter().map_while(|c| { + if let Some(c) = f(c) { + Some(c) + } else { + all_ok = false; + None + } + })); + all_ok.then_some(ConditionSet(set)) } } @@ -192,28 +201,28 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { /// Recursion entry point to find threading opportunities. #[instrument(level = "trace", skip(self))] - fn start_from_switch(&mut self, bb: BasicBlock) { + fn start_from_switch(&mut self, bb: BasicBlock) -> Option<()> { let bbdata = &self.body[bb]; if bbdata.is_cleanup || self.loop_headers.contains(bb) { - return; + return Some(()); } - let Some((discr, targets)) = bbdata.terminator().kind.as_switch() else { return }; - let Some(discr) = discr.place() else { return }; + let Some((discr, targets)) = bbdata.terminator().kind.as_switch() else { return Some(()) }; + let Some(discr) = discr.place() else { return Some(()) }; debug!(?discr, ?bb); let discr_ty = discr.ty(self.body, self.tcx).ty; let Ok(discr_layout) = self.ecx.layout_of(discr_ty) else { - return; + return Some(()); }; - let Some(discr) = self.map.find(discr.as_ref()) else { return }; + let Some(discr) = self.map.find(discr.as_ref()) else { return Some(()) }; debug!(?discr); let cost = CostChecker::new(self.tcx, self.typing_env, None, self.body); let mut state = State::new_reachable(); let conds = if let Some((value, then, else_)) = targets.as_static_if() { - let Some(value) = ScalarInt::try_from_uint(value, discr_layout.size) else { return }; + let value = ScalarInt::try_from_uint(value, discr_layout.size)?; self.arena.alloc_from_iter([ Condition { value, polarity: Polarity::Eq, target: then }, Condition { value, polarity: Polarity::Ne, target: else_ }, @@ -227,7 +236,7 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { let conds = ConditionSet(conds); state.insert_value_idx(discr, conds, &self.map); - self.find_opportunity(bb, state, cost, 0); + self.find_opportunity(bb, state, cost, 0) } /// Recursively walk statements backwards from this bb's terminator to find threading @@ -239,10 +248,10 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { mut state: State>, mut cost: CostChecker<'_, 'tcx>, depth: usize, - ) { + ) -> Option<()> { // Do not thread through loop headers. if self.loop_headers.contains(bb) { - return; + return Some(()); } debug!(cost = ?cost.cost()); @@ -250,16 +259,16 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { self.body.basic_blocks[bb].statements.iter().enumerate().rev() { if self.is_empty(&state) { - return; + return Some(()); } cost.visit_statement(stmt, Location { block: bb, statement_index }); if cost.cost() > MAX_COST { - return; + return Some(()); } // Attempt to turn the `current_condition` on `lhs` into a condition on another place. - self.process_statement(bb, stmt, &mut state); + self.process_statement(bb, stmt, &mut state)?; // When a statement mutates a place, assignments to that place that happen // above the mutation cannot fulfill a condition. @@ -271,7 +280,7 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { } if self.is_empty(&state) || depth >= MAX_BACKTRACK { - return; + return Some(()); } let last_non_rec = self.opportunities.len(); @@ -284,9 +293,9 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { match term.kind { TerminatorKind::SwitchInt { ref discr, ref targets } => { self.process_switch_int(discr, targets, bb, &mut state); - self.find_opportunity(pred, state, cost, depth + 1); + self.find_opportunity(pred, state, cost, depth + 1)?; } - _ => self.recurse_through_terminator(pred, || state, &cost, depth), + _ => self.recurse_through_terminator(pred, || state, &cost, depth)?, } } else if let &[ref predecessors @ .., last_pred] = &predecessors[..] { for &pred in predecessors { @@ -311,12 +320,13 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { let first = &mut new_tos[0]; *first = ThreadingOpportunity { chain: vec![bb], target: first.target }; self.opportunities.truncate(last_non_rec + 1); - return; + return Some(()); } for op in self.opportunities[last_non_rec..].iter_mut() { op.chain.push(bb); } + Some(()) } /// Extract the mutated place from a statement. @@ -430,23 +440,23 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { lhs: PlaceIndex, rhs: &Operand<'tcx>, state: &mut State>, - ) { + ) -> Option<()> { match rhs { // If we expect `lhs ?= A`, we have an opportunity if we assume `constant == A`. Operand::Constant(constant) => { - let Some(constant) = - self.ecx.eval_mir_constant(&constant.const_, constant.span, None).discard_err() - else { - return; - }; + let constant = self + .ecx + .eval_mir_constant(&constant.const_, constant.span, None) + .discard_err()?; self.process_constant(bb, lhs, constant, state); } // Transfer the conditions on the copied rhs. Operand::Move(rhs) | Operand::Copy(rhs) => { - let Some(rhs) = self.map.find(rhs.as_ref()) else { return }; + let Some(rhs) = self.map.find(rhs.as_ref()) else { return Some(()) }; state.insert_place_idx(rhs, lhs, &self.map); } } + Some(()) } #[instrument(level = "trace", skip(self))] @@ -456,14 +466,18 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { lhs_place: &Place<'tcx>, rhs: &Rvalue<'tcx>, state: &mut State>, - ) { - let Some(lhs) = self.map.find(lhs_place.as_ref()) else { return }; + ) -> Option<()> { + let Some(lhs) = self.map.find(lhs_place.as_ref()) else { + return Some(()); + }; match rhs { - Rvalue::Use(operand) => self.process_operand(bb, lhs, operand, state), + Rvalue::Use(operand) => self.process_operand(bb, lhs, operand, state)?, // Transfer the conditions on the copy rhs. - Rvalue::CopyForDeref(rhs) => self.process_operand(bb, lhs, &Operand::Copy(*rhs), state), + Rvalue::CopyForDeref(rhs) => { + self.process_operand(bb, lhs, &Operand::Copy(*rhs), state)? + } Rvalue::Discriminant(rhs) => { - let Some(rhs) = self.map.find_discr(rhs.as_ref()) else { return }; + let Some(rhs) = self.map.find_discr(rhs.as_ref()) else { return Some(()) }; state.insert_place_idx(rhs, lhs, &self.map); } // If we expect `lhs ?= A`, we have an opportunity if we assume `constant == A`. @@ -471,7 +485,7 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { let agg_ty = lhs_place.ty(self.body, self.tcx).ty; let lhs = match kind { // Do not support unions. - AggregateKind::Adt(.., Some(_)) => return, + AggregateKind::Adt(.., Some(_)) => return Some(()), AggregateKind::Adt(_, variant_index, ..) if agg_ty.is_enum() => { if let Some(discr_target) = self.map.apply(lhs, TrackElem::Discriminant) && let Some(discr_value) = self @@ -484,30 +498,31 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { if let Some(idx) = self.map.apply(lhs, TrackElem::Variant(*variant_index)) { idx } else { - return; + return Some(()); } } _ => lhs, }; for (field_index, operand) in operands.iter_enumerated() { if let Some(field) = self.map.apply(lhs, TrackElem::Field(field_index)) { - self.process_operand(bb, field, operand, state); + self.process_operand(bb, field, operand, state)?; } } } - // Transfer the conditions on the copy rhs, after inversing polarity. + // Transfer the conditions on the copy rhs, after inverting the value of the condition. Rvalue::UnaryOp(UnOp::Not, Operand::Move(place) | Operand::Copy(place)) => { - if !place.ty(self.body, self.tcx).ty.is_bool() { - // Constructing the conditions by inverting the polarity - // of equality is only correct for bools. That is to say, - // `!a == b` is not `a != b` for integers greater than 1 bit. - return; - } - let Some(conditions) = state.try_get_idx(lhs, &self.map) else { return }; - let Some(place) = self.map.find(place.as_ref()) else { return }; - // FIXME: I think This could be generalized to not bool if we - // actually perform a logical not on the condition's value. - let conds = conditions.map(self.arena, Condition::inv); + let layout = self.ecx.layout_of(place.ty(self.body, self.tcx).ty).unwrap(); + let Some(conditions) = state.try_get_idx(lhs, &self.map) else { return Some(()) }; + let Some(place) = self.map.find(place.as_ref()) else { return Some(()) }; + let conds = conditions.map(self.arena, |mut cond| { + cond.value = self + .ecx + .unary_op(UnOp::Not, &ImmTy::from_scalar_int(cond.value, layout)) + .discard_err()? + .to_scalar_int() + .discard_err()?; + Some(cond) + })?; state.insert_value_idx(place, conds, &self.map); } // We expect `lhs ?= A`. We found `lhs = Eq(rhs, B)`. @@ -517,34 +532,34 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { box (Operand::Move(place) | Operand::Copy(place), Operand::Constant(value)) | box (Operand::Constant(value), Operand::Move(place) | Operand::Copy(place)), ) => { - let Some(conditions) = state.try_get_idx(lhs, &self.map) else { return }; - let Some(place) = self.map.find(place.as_ref()) else { return }; + let Some(conditions) = state.try_get_idx(lhs, &self.map) else { return Some(()) }; + let Some(place) = self.map.find(place.as_ref()) else { return Some(()) }; let equals = match op { BinOp::Eq => ScalarInt::TRUE, BinOp::Ne => ScalarInt::FALSE, - _ => return, + _ => return Some(()), }; if value.const_.ty().is_floating_point() { // Floating point equality does not follow bit-patterns. // -0.0 and NaN both have special rules for equality, // and therefore we cannot use integer comparisons for them. // Avoid handling them, though this could be extended in the future. - return; + return Some(()); } - let Some(value) = value.const_.try_eval_scalar_int(self.tcx, self.typing_env) - else { - return; - }; - let conds = conditions.map(self.arena, |c| Condition { - value, - polarity: if c.matches(equals) { Polarity::Eq } else { Polarity::Ne }, - ..c - }); + let value = value.const_.try_eval_scalar_int(self.tcx, self.typing_env)?; + let conds = conditions.map(self.arena, |c| { + Some(Condition { + value, + polarity: if c.matches(equals) { Polarity::Eq } else { Polarity::Ne }, + ..c + }) + })?; state.insert_value_idx(place, conds, &self.map); } _ => {} } + Some(()) } #[instrument(level = "trace", skip(self))] @@ -553,7 +568,7 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { bb: BasicBlock, stmt: &Statement<'tcx>, state: &mut State>, - ) { + ) -> Option<()> { let register_opportunity = |c: Condition| { debug!(?bb, ?c.target, "register"); self.opportunities.push(ThreadingOpportunity { chain: vec![bb], target: c.target }) @@ -566,30 +581,32 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { // If we expect `discriminant(place) ?= A`, // we have an opportunity if `variant_index ?= A`. StatementKind::SetDiscriminant { box place, variant_index } => { - let Some(discr_target) = self.map.find_discr(place.as_ref()) else { return }; + let Some(discr_target) = self.map.find_discr(place.as_ref()) else { + return Some(()); + }; let enum_ty = place.ty(self.body, self.tcx).ty; // `SetDiscriminant` guarantees that the discriminant is now `variant_index`. // Even if the discriminant write does nothing due to niches, it is UB to set the // discriminant when the data does not encode the desired discriminant. - let Some(discr) = - self.ecx.discriminant_for_variant(enum_ty, *variant_index).discard_err() - else { - return; - }; + let discr = + self.ecx.discriminant_for_variant(enum_ty, *variant_index).discard_err()?; self.process_immediate(bb, discr_target, discr, state); } // If we expect `lhs ?= true`, we have an opportunity if we assume `lhs == true`. StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume( Operand::Copy(place) | Operand::Move(place), )) => { - let Some(conditions) = state.try_get(place.as_ref(), &self.map) else { return }; + let Some(conditions) = state.try_get(place.as_ref(), &self.map) else { + return Some(()); + }; conditions.iter_matches(ScalarInt::TRUE).for_each(register_opportunity); } StatementKind::Assign(box (lhs_place, rhs)) => { - self.process_assign(bb, lhs_place, rhs, state); + self.process_assign(bb, lhs_place, rhs, state)?; } _ => {} } + Some(()) } #[instrument(level = "trace", skip(self, state, cost))] @@ -600,7 +617,7 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { state: impl FnOnce() -> State>, cost: &CostChecker<'_, 'tcx>, depth: usize, - ) { + ) -> Option<()> { let term = self.body.basic_blocks[bb].terminator(); let place_to_flood = match term.kind { // We come from a target, so those are not possible. @@ -615,9 +632,9 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { | TerminatorKind::FalseUnwind { .. } | TerminatorKind::Yield { .. } => bug!("{term:?} invalid"), // Cannot reason about inline asm. - TerminatorKind::InlineAsm { .. } => return, + TerminatorKind::InlineAsm { .. } => return Some(()), // `SwitchInt` is handled specially. - TerminatorKind::SwitchInt { .. } => return, + TerminatorKind::SwitchInt { .. } => return Some(()), // We can recurse, no thing particular to do. TerminatorKind::Goto { .. } => None, // Flood the overwritten place, and progress through. @@ -632,7 +649,7 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { if let Some(place_to_flood) = place_to_flood { state.flood_with(place_to_flood.as_ref(), &self.map, ConditionSet::BOTTOM); } - self.find_opportunity(bb, state, cost.clone(), depth + 1); + self.find_opportunity(bb, state, cost.clone(), depth + 1) } #[instrument(level = "trace", skip(self))] diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 6429d3f67ec6..4d74ecddfb05 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -1,5 +1,4 @@ // tidy-alphabetical-start -#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![feature(array_windows)] #![feature(assert_matches)] #![feature(box_patterns)] @@ -498,8 +497,11 @@ fn mir_drops_elaborated_and_const_checked(tcx: TyCtxt<'_>, def: LocalDefId) -> & } // We only need to borrowck non-synthetic MIR. - let tainted_by_errors = - if !tcx.is_synthetic_mir(def) { tcx.mir_borrowck(def).tainted_by_errors } else { None }; + let tainted_by_errors = if !tcx.is_synthetic_mir(def) { + tcx.mir_borrowck(tcx.typeck_root_def_id(def.to_def_id()).expect_local()).err() + } else { + None + }; let is_fn_like = tcx.def_kind(def).is_fn_like(); if is_fn_like { @@ -795,7 +797,7 @@ fn promoted_mir(tcx: TyCtxt<'_>, def: LocalDefId) -> &IndexVec { /// A custom `Subdiagnostic` implementation so that the notes are delivered in a specific order impl Subdiagnostic for LocalLabel<'_> { - fn add_to_diag_with< - G: rustc_errors::EmissionGuarantee, - F: rustc_errors::SubdiagMessageOp, - >( - self, - diag: &mut rustc_errors::Diag<'_, G>, - f: &F, - ) { + fn add_to_diag(self, diag: &mut rustc_errors::Diag<'_, G>) { diag.arg("name", self.name); diag.arg("is_generated_name", self.is_generated_name); diag.arg("is_dropped_first_edition_2024", self.is_dropped_first_edition_2024); - let msg = f(diag, crate::fluent_generated::mir_transform_tail_expr_local.into()); + let msg = diag.eagerly_translate(crate::fluent_generated::mir_transform_tail_expr_local); diag.span_label(self.span, msg); for dtor in self.destructors { - dtor.add_to_diag_with(diag, f); + dtor.add_to_diag(diag); } - let msg = f(diag, crate::fluent_generated::mir_transform_label_local_epilogue); + let msg = + diag.eagerly_translate(crate::fluent_generated::mir_transform_label_local_epilogue); diag.span_label(self.span, msg); } } diff --git a/compiler/rustc_mir_transform/src/match_branches.rs b/compiler/rustc_mir_transform/src/match_branches.rs index 0d9d0368d372..5059837328e2 100644 --- a/compiler/rustc_mir_transform/src/match_branches.rs +++ b/compiler/rustc_mir_transform/src/match_branches.rs @@ -20,13 +20,11 @@ impl<'tcx> crate::MirPass<'tcx> for MatchBranchSimplification { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { let typing_env = body.typing_env(tcx); let mut should_cleanup = false; - for i in 0..body.basic_blocks.len() { - let bbs = &*body.basic_blocks; - let bb_idx = BasicBlock::from_usize(i); - match bbs[bb_idx].terminator().kind { + for bb_idx in body.basic_blocks.indices() { + match &body.basic_blocks[bb_idx].terminator().kind { TerminatorKind::SwitchInt { - discr: ref _discr @ (Operand::Copy(_) | Operand::Move(_)), - ref targets, + discr: Operand::Copy(_) | Operand::Move(_), + targets, .. // We require that the possible target blocks don't contain this block. } if !targets.all_targets().contains(&bb_idx) => {} @@ -66,9 +64,10 @@ trait SimplifyMatch<'tcx> { typing_env: ty::TypingEnv<'tcx>, ) -> Option<()> { let bbs = &body.basic_blocks; - let (discr, targets) = match bbs[switch_bb_idx].terminator().kind { - TerminatorKind::SwitchInt { ref discr, ref targets, .. } => (discr, targets), - _ => unreachable!(), + let TerminatorKind::SwitchInt { discr, targets, .. } = + &bbs[switch_bb_idx].terminator().kind + else { + unreachable!(); }; let discr_ty = discr.ty(body.local_decls(), tcx); diff --git a/compiler/rustc_mir_transform/src/multiple_return_terminators.rs b/compiler/rustc_mir_transform/src/multiple_return_terminators.rs index c63bfdcee855..f59b849e85c6 100644 --- a/compiler/rustc_mir_transform/src/multiple_return_terminators.rs +++ b/compiler/rustc_mir_transform/src/multiple_return_terminators.rs @@ -18,19 +18,17 @@ impl<'tcx> crate::MirPass<'tcx> for MultipleReturnTerminators { // find basic blocks with no statement and a return terminator let mut bbs_simple_returns = DenseBitSet::new_empty(body.basic_blocks.len()); let bbs = body.basic_blocks_mut(); - for idx in bbs.indices() { - if bbs[idx].statements.is_empty() - && bbs[idx].terminator().kind == TerminatorKind::Return - { + for (idx, bb) in bbs.iter_enumerated() { + if bb.statements.is_empty() && bb.terminator().kind == TerminatorKind::Return { bbs_simple_returns.insert(idx); } } for bb in bbs { - if let TerminatorKind::Goto { target } = bb.terminator().kind { - if bbs_simple_returns.contains(target) { - bb.terminator_mut().kind = TerminatorKind::Return; - } + if let TerminatorKind::Goto { target } = bb.terminator().kind + && bbs_simple_returns.contains(target) + { + bb.terminator_mut().kind = TerminatorKind::Return; } } diff --git a/compiler/rustc_mir_transform/src/patch.rs b/compiler/rustc_mir_transform/src/patch.rs index 6a177faeac81..12ace04c5e26 100644 --- a/compiler/rustc_mir_transform/src/patch.rs +++ b/compiler/rustc_mir_transform/src/patch.rs @@ -181,7 +181,7 @@ impl<'tcx> MirPatch<'tcx> { /// Queues the addition of a new basic block. pub(crate) fn new_block(&mut self, data: BasicBlockData<'tcx>) -> BasicBlock { - let block = BasicBlock::new(self.term_patch_map.len()); + let block = self.term_patch_map.next_index(); debug!("MirPatch: new_block: {:?}: {:?}", block, data); self.new_blocks.push(data); self.term_patch_map.push(None); diff --git a/compiler/rustc_mir_transform/src/post_analysis_normalize.rs b/compiler/rustc_mir_transform/src/post_analysis_normalize.rs index 76c2f082c0bf..5599dee4ccad 100644 --- a/compiler/rustc_mir_transform/src/post_analysis_normalize.rs +++ b/compiler/rustc_mir_transform/src/post_analysis_normalize.rs @@ -39,20 +39,22 @@ impl<'tcx> MutVisitor<'tcx> for PostAnalysisNormalizeVisitor<'tcx> { _context: PlaceContext, _location: Location, ) { - // Performance optimization: don't reintern if there is no `OpaqueCast` to remove. - if place.projection.iter().all(|elem| !matches!(elem, ProjectionElem::OpaqueCast(_))) { - return; + if !self.tcx.next_trait_solver_globally() { + // `OpaqueCast` projections are only needed if there are opaque types on which projections + // are performed. After the `PostAnalysisNormalize` pass, all opaque types are replaced with their + // hidden types, so we don't need these projections anymore. + // + // Performance optimization: don't reintern if there is no `OpaqueCast` to remove. + if place.projection.iter().any(|elem| matches!(elem, ProjectionElem::OpaqueCast(_))) { + place.projection = self.tcx.mk_place_elems( + &place + .projection + .into_iter() + .filter(|elem| !matches!(elem, ProjectionElem::OpaqueCast(_))) + .collect::>(), + ); + }; } - // `OpaqueCast` projections are only needed if there are opaque types on which projections - // are performed. After the `PostAnalysisNormalize` pass, all opaque types are replaced with their - // hidden types, so we don't need these projections anymore. - place.projection = self.tcx.mk_place_elems( - &place - .projection - .into_iter() - .filter(|elem| !matches!(elem, ProjectionElem::OpaqueCast(_))) - .collect::>(), - ); self.super_place(place, _context, _location); } diff --git a/compiler/rustc_mir_transform/src/promote_consts.rs b/compiler/rustc_mir_transform/src/promote_consts.rs index c8d8dc147e94..47d438309700 100644 --- a/compiler/rustc_mir_transform/src/promote_consts.rs +++ b/compiler/rustc_mir_transform/src/promote_consts.rs @@ -18,7 +18,7 @@ use either::{Left, Right}; use rustc_const_eval::check_consts::{ConstCx, qualifs}; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; -use rustc_index::{Idx, IndexSlice, IndexVec}; +use rustc_index::{IndexSlice, IndexVec}; use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; use rustc_middle::ty::{self, GenericArgs, List, Ty, TyCtxt, TypeVisitableExt}; @@ -864,17 +864,21 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { new_temp } - fn promote_candidate(mut self, candidate: Candidate, next_promoted_id: usize) -> Body<'tcx> { + fn promote_candidate( + mut self, + candidate: Candidate, + next_promoted_index: Promoted, + ) -> Body<'tcx> { let def = self.source.source.def_id(); let (mut rvalue, promoted_op) = { let promoted = &mut self.promoted; - let promoted_id = Promoted::new(next_promoted_id); let tcx = self.tcx; let mut promoted_operand = |ty, span| { promoted.span = span; promoted.local_decls[RETURN_PLACE] = LocalDecl::new(ty, span); let args = tcx.erase_regions(GenericArgs::identity_for_item(tcx, def)); - let uneval = mir::UnevaluatedConst { def, args, promoted: Some(promoted_id) }; + let uneval = + mir::UnevaluatedConst { def, args, promoted: Some(next_promoted_index) }; ConstOperand { span, user_ty: None, const_: Const::Unevaluated(uneval, ty) } }; @@ -1034,7 +1038,7 @@ fn promote_candidates<'tcx>( required_consts: Vec::new(), }; - let mut promoted = promoter.promote_candidate(candidate, promotions.len()); + let mut promoted = promoter.promote_candidate(candidate, promotions.next_index()); promoted.source.promoted = Some(promotions.next_index()); promotions.push(promoted); } diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index c9771467e499..c13ffae36498 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -66,7 +66,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceKind<'tcx>) -> Body< let call_mut = tcx .associated_items(fn_mut) .in_definition_order() - .find(|it| it.kind == ty::AssocKind::Fn) + .find(|it| it.is_fn()) .unwrap() .def_id; diff --git a/compiler/rustc_mir_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs index 84905f4a400f..5947637cded9 100644 --- a/compiler/rustc_mir_transform/src/simplify.rs +++ b/compiler/rustc_mir_transform/src/simplify.rs @@ -597,20 +597,6 @@ impl<'tcx> MutVisitor<'tcx> for LocalUpdater<'tcx> { self.tcx } - fn visit_statement(&mut self, statement: &mut Statement<'tcx>, location: Location) { - if let StatementKind::BackwardIncompatibleDropHint { place, reason: _ } = - &mut statement.kind - { - self.visit_local( - &mut place.local, - PlaceContext::MutatingUse(MutatingUseContext::Store), - location, - ); - } else { - self.super_statement(statement, location); - } - } - fn visit_local(&mut self, l: &mut Local, _: PlaceContext, _: Location) { *l = self.map[*l].unwrap(); } diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs index e7930f0a1e3f..66fe3ef4141f 100644 --- a/compiler/rustc_mir_transform/src/validate.rs +++ b/compiler/rustc_mir_transform/src/validate.rs @@ -221,12 +221,11 @@ impl<'a, 'tcx> CfgChecker<'a, 'tcx> { // Check for cycles let mut stack = FxHashSet::default(); - for i in 0..parent.len() { - let mut bb = BasicBlock::from_usize(i); + for (mut bb, parent) in parent.iter_enumerated_mut() { stack.clear(); stack.insert(bb); loop { - let Some(parent) = parent[bb].take() else { break }; + let Some(parent) = parent.take() else { break }; let no_cycle = stack.insert(parent); if !no_cycle { self.fail( diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 6e676ac6b8d5..d1d0f7cacaee 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -688,7 +688,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> { let target_ty = self.monomorphize(target_ty); let source_ty = self.monomorphize(source_ty); let (source_ty, target_ty) = - find_vtable_types_for_unsizing(self.tcx.at(span), source_ty, target_ty); + find_tails_for_unsizing(self.tcx.at(span), source_ty, target_ty); // This could also be a different Unsize instruction, like // from a fixed sized array to a slice. But we are only // interested in things that produce a vtable. @@ -1037,36 +1037,35 @@ fn should_codegen_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> /// /// Finally, there is also the case of custom unsizing coercions, e.g., for /// smart pointers such as `Rc` and `Arc`. -fn find_vtable_types_for_unsizing<'tcx>( +fn find_tails_for_unsizing<'tcx>( tcx: TyCtxtAt<'tcx>, source_ty: Ty<'tcx>, target_ty: Ty<'tcx>, ) -> (Ty<'tcx>, Ty<'tcx>) { - let ptr_vtable = |inner_source: Ty<'tcx>, inner_target: Ty<'tcx>| { - let typing_env = ty::TypingEnv::fully_monomorphized(); - if tcx.type_has_metadata(inner_source, typing_env) { - (inner_source, inner_target) - } else { - tcx.struct_lockstep_tails_for_codegen(inner_source, inner_target, typing_env) - } - }; + let typing_env = ty::TypingEnv::fully_monomorphized(); + debug_assert!(!source_ty.has_param(), "{source_ty} should be fully monomorphic"); + debug_assert!(!target_ty.has_param(), "{target_ty} should be fully monomorphic"); match (source_ty.kind(), target_ty.kind()) { - (&ty::Ref(_, a, _), &ty::Ref(_, b, _) | &ty::RawPtr(b, _)) - | (&ty::RawPtr(a, _), &ty::RawPtr(b, _)) => ptr_vtable(a, b), + ( + &ty::Ref(_, source_pointee, _), + &ty::Ref(_, target_pointee, _) | &ty::RawPtr(target_pointee, _), + ) + | (&ty::RawPtr(source_pointee, _), &ty::RawPtr(target_pointee, _)) => { + tcx.struct_lockstep_tails_for_codegen(source_pointee, target_pointee, typing_env) + } + + // `Box` could go through the ADT code below, b/c it'll unpeel to `Unique`, + // and eventually bottom out in a raw ref, but we can micro-optimize it here. (_, _) if let Some(source_boxed) = source_ty.boxed_ty() && let Some(target_boxed) = target_ty.boxed_ty() => { - ptr_vtable(source_boxed, target_boxed) + tcx.struct_lockstep_tails_for_codegen(source_boxed, target_boxed, typing_env) } - // T as dyn* Trait - (_, &ty::Dynamic(_, _, ty::DynStar)) => ptr_vtable(source_ty, target_ty), - (&ty::Adt(source_adt_def, source_args), &ty::Adt(target_adt_def, target_args)) => { assert_eq!(source_adt_def, target_adt_def); - let CustomCoerceUnsized::Struct(coerce_index) = match crate::custom_coerce_unsize_info(tcx, source_ty, target_ty) { Ok(ccu) => ccu, @@ -1075,21 +1074,23 @@ fn find_vtable_types_for_unsizing<'tcx>( return (e, e); } }; - - let source_fields = &source_adt_def.non_enum_variant().fields; - let target_fields = &target_adt_def.non_enum_variant().fields; - - assert!( - coerce_index.index() < source_fields.len() - && source_fields.len() == target_fields.len() - ); - - find_vtable_types_for_unsizing( - tcx, - source_fields[coerce_index].ty(*tcx, source_args), - target_fields[coerce_index].ty(*tcx, target_args), - ) + let coerce_field = &source_adt_def.non_enum_variant().fields[coerce_index]; + // We're getting a possibly unnormalized type, so normalize it. + let source_field = + tcx.normalize_erasing_regions(typing_env, coerce_field.ty(*tcx, source_args)); + let target_field = + tcx.normalize_erasing_regions(typing_env, coerce_field.ty(*tcx, target_args)); + find_tails_for_unsizing(tcx, source_field, target_field) } + + // `T` as `dyn* Trait` unsizes *directly*. + // + // FIXME(dyn_star): This case is a bit awkward, b/c we're not really computing + // a tail here. We probably should handle this separately in the *caller* of + // this function, rather than returning something that is semantically different + // than what we return above. + (_, &ty::Dynamic(_, _, ty::DynStar)) => (source_ty, target_ty), + _ => bug!( "find_vtable_types_for_unsizing: invalid coercion {:?} -> {:?}", source_ty, @@ -1308,7 +1309,7 @@ fn visit_mentioned_item<'tcx>( } MentionedItem::UnsizeCast { source_ty, target_ty } => { let (source_ty, target_ty) = - find_vtable_types_for_unsizing(tcx.at(span), source_ty, target_ty); + find_tails_for_unsizing(tcx.at(span), source_ty, target_ty); // This could also be a different Unsize instruction, like // from a fixed sized array to a slice. But we are only // interested in things that produce a vtable. @@ -1689,7 +1690,7 @@ pub(crate) fn collect_crate_mono_items<'tcx>( let mut recursion_depths = DefIdMap::default(); collect_items_rec( tcx, - dummy_spanned(root), + dummy_spanned(*root), &state, &mut recursion_depths, recursion_limit, diff --git a/compiler/rustc_monomorphize/src/lib.rs b/compiler/rustc_monomorphize/src/lib.rs index 5dbae50c499f..8f6914f3d724 100644 --- a/compiler/rustc_monomorphize/src/lib.rs +++ b/compiler/rustc_monomorphize/src/lib.rs @@ -1,5 +1,4 @@ // tidy-alphabetical-start -#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![feature(array_windows)] #![feature(file_buffered)] #![feature(if_let_guard)] diff --git a/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs b/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs index 0f5bdc8d7683..94ee34c8b7bf 100644 --- a/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs +++ b/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs @@ -111,6 +111,11 @@ fn wasm_abi_safe<'tcx>(tcx: TyCtxt<'tcx>, arg: &ArgAbi<'tcx, Ty<'tcx>>) -> bool } } + // Zero-sized types are dropped in both ABIs, so they're safe + if arg.layout.is_zst() { + return true; + } + false } diff --git a/compiler/rustc_monomorphize/src/mono_checks/move_check.rs b/compiler/rustc_monomorphize/src/mono_checks/move_check.rs index 838bfdab1ea5..7251ef478c6f 100644 --- a/compiler/rustc_monomorphize/src/mono_checks/move_check.rs +++ b/compiler/rustc_monomorphize/src/mono_checks/move_check.rs @@ -3,7 +3,7 @@ use rustc_data_structures::fx::FxIndexSet; use rustc_hir::def_id::DefId; use rustc_middle::mir::visit::Visitor as MirVisitor; use rustc_middle::mir::{self, Location, traversal}; -use rustc_middle::ty::{self, AssocKind, Instance, Ty, TyCtxt, TypeFoldable}; +use rustc_middle::ty::{self, AssocTag, Instance, Ty, TyCtxt, TypeFoldable}; use rustc_session::Limit; use rustc_session::lint::builtin::LARGE_ASSIGNMENTS; use rustc_span::source_map::Spanned; @@ -148,11 +148,7 @@ impl<'tcx> MoveCheckVisitor<'tcx> { span: Span, ) { let source_info = self.body.source_info(location); - for reported_span in &self.move_size_spans { - if reported_span.overlaps(span) { - return; - } - } + let lint_root = source_info.scope.lint_root(&self.body.source_scopes); let Some(lint_root) = lint_root else { // This happens when the issue is in a function from a foreign crate that @@ -162,22 +158,43 @@ impl<'tcx> MoveCheckVisitor<'tcx> { // but correct span? This would make the lint at least accept crate-level lint attributes. return; }; + + // If the source scope is inlined by the MIR inliner, report the lint on the call site. + let reported_span = self + .body + .source_scopes + .get(source_info.scope) + .and_then(|source_scope_data| source_scope_data.inlined) + .map(|(_, call_site)| call_site) + .unwrap_or(span); + + for previously_reported_span in &self.move_size_spans { + if previously_reported_span.overlaps(reported_span) { + return; + } + } + self.tcx.emit_node_span_lint( LARGE_ASSIGNMENTS, lint_root, - span, - LargeAssignmentsLint { span, size: too_large_size.bytes(), limit: limit as u64 }, + reported_span, + LargeAssignmentsLint { + span: reported_span, + size: too_large_size.bytes(), + limit: limit as u64, + }, ); - self.move_size_spans.push(span); + + self.move_size_spans.push(reported_span); } } fn assoc_fn_of_type<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, fn_ident: Ident) -> Option { for impl_def_id in tcx.inherent_impls(def_id) { - if let Some(new) = tcx.associated_items(impl_def_id).find_by_name_and_kind( + if let Some(new) = tcx.associated_items(impl_def_id).find_by_ident_and_kind( tcx, fn_ident, - AssocKind::Fn, + AssocTag::Fn, def_id, ) { return Some(new.def_id); diff --git a/compiler/rustc_monomorphize/src/partitioning/autodiff.rs b/compiler/rustc_monomorphize/src/partitioning/autodiff.rs index ebe0b258c1b6..22d593b80b89 100644 --- a/compiler/rustc_monomorphize/src/partitioning/autodiff.rs +++ b/compiler/rustc_monomorphize/src/partitioning/autodiff.rs @@ -2,7 +2,7 @@ use rustc_ast::expand::autodiff_attrs::{AutoDiffItem, DiffActivity}; use rustc_hir::def_id::LOCAL_CRATE; use rustc_middle::bug; use rustc_middle::mir::mono::MonoItem; -use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; +use rustc_middle::ty::{self, Instance, PseudoCanonicalInput, Ty, TyCtxt, TypingEnv}; use rustc_symbol_mangling::symbol_name_for_instance_in_crate; use tracing::{debug, trace}; @@ -22,23 +22,51 @@ fn adjust_activity_to_abi<'tcx>(tcx: TyCtxt<'tcx>, fn_ty: Ty<'tcx>, da: &mut Vec for (i, ty) in sig.inputs().iter().enumerate() { if let Some(inner_ty) = ty.builtin_deref(true) { if inner_ty.is_slice() { + // Now we need to figure out the size of each slice element in memory to allow + // safety checks and usability improvements in the backend. + let sty = match inner_ty.builtin_index() { + Some(sty) => sty, + None => { + panic!("slice element type unknown"); + } + }; + let pci = PseudoCanonicalInput { + typing_env: TypingEnv::fully_monomorphized(), + value: sty, + }; + + let layout = tcx.layout_of(pci); + let elem_size = match layout { + Ok(layout) => layout.size, + Err(_) => { + bug!("autodiff failed to compute slice element size"); + } + }; + let elem_size: u32 = elem_size.bytes() as u32; + // We know that the length will be passed as extra arg. if !da.is_empty() { // We are looking at a slice. The length of that slice will become an // extra integer on llvm level. Integers are always const. // However, if the slice get's duplicated, we want to know to later check the // size. So we mark the new size argument as FakeActivitySize. + // There is one FakeActivitySize per slice, so for convenience we store the + // slice element size in bytes in it. We will use the size in the backend. let activity = match da[i] { DiffActivity::DualOnly | DiffActivity::Dual + | DiffActivity::Dualv | DiffActivity::DuplicatedOnly - | DiffActivity::Duplicated => DiffActivity::FakeActivitySize, + | DiffActivity::Duplicated => { + DiffActivity::FakeActivitySize(Some(elem_size)) + } DiffActivity::Const => DiffActivity::Const, _ => bug!("unexpected activity for ptr/ref"), }; new_activities.push(activity); new_positions.push(i + 1); } + continue; } } diff --git a/compiler/rustc_next_trait_solver/src/lib.rs b/compiler/rustc_next_trait_solver/src/lib.rs index f575fe03019e..92cdc28a37b4 100644 --- a/compiler/rustc_next_trait_solver/src/lib.rs +++ b/compiler/rustc_next_trait_solver/src/lib.rs @@ -6,7 +6,7 @@ // tidy-alphabetical-start #![allow(rustc::usage_of_type_ir_inherent)] -#![cfg_attr(not(bootstrap), allow(rustc::usage_of_type_ir_traits))] +#![allow(rustc::usage_of_type_ir_traits)] // tidy-alphabetical-end pub mod canonicalizer; diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs index 384a304c4a9d..83b2465d05aa 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -92,16 +92,20 @@ where let ty::Dynamic(bounds, _, _) = goal.predicate.self_ty().kind() else { panic!("expected object type in `probe_and_consider_object_bound_candidate`"); }; - ecx.add_goals( - GoalSource::ImplWhereBound, - structural_traits::predicates_for_object_candidate( - ecx, - goal.param_env, - goal.predicate.trait_ref(cx), - bounds, - ), - ); - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + match structural_traits::predicates_for_object_candidate( + ecx, + goal.param_env, + goal.predicate.trait_ref(cx), + bounds, + ) { + Ok(requirements) => { + ecx.add_goals(GoalSource::ImplWhereBound, requirements); + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + } + Err(_) => { + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) + } + } }) } @@ -792,37 +796,46 @@ where }; match proven_via { - // Even when a trait bound has been proven using a where-bound, we - // still need to consider alias-bounds for normalization, see - // tests/ui/next-solver/alias-bound-shadowed-by-env.rs. - // - // FIXME(const_trait_impl): should this behavior also be used by - // constness checking. Doing so is *at least theoretically* breaking, - // see github.com/rust-lang/rust/issues/133044#issuecomment-2500709754 TraitGoalProvenVia::ParamEnv | TraitGoalProvenVia::AliasBound => { - let mut candidates_from_env_and_bounds: Vec<_> = candidates - .iter() - .filter(|c| { - matches!( - c.source, - CandidateSource::AliasBound | CandidateSource::ParamEnv(_) - ) - }) - .map(|c| c.result) - .collect(); + let mut considered_candidates = Vec::new(); + considered_candidates.extend( + candidates + .iter() + .filter(|c| matches!(c.source, CandidateSource::ParamEnv(_))) + .map(|c| c.result), + ); + + // Even when a trait bound has been proven using a where-bound, we + // still need to consider alias-bounds for normalization, see + // tests/ui/next-solver/alias-bound-shadowed-by-env.rs. + // + // We still need to prefer where-bounds over alias-bounds however. + // See tests/ui/winnowing/norm-where-bound-gt-alias-bound.rs. + // + // FIXME(const_trait_impl): should this behavior also be used by + // constness checking. Doing so is *at least theoretically* breaking, + // see github.com/rust-lang/rust/issues/133044#issuecomment-2500709754 + if considered_candidates.is_empty() { + considered_candidates.extend( + candidates + .iter() + .filter(|c| matches!(c.source, CandidateSource::AliasBound)) + .map(|c| c.result), + ); + } // If the trait goal has been proven by using the environment, we want to treat // aliases as rigid if there are no applicable projection bounds in the environment. - if candidates_from_env_and_bounds.is_empty() { + if considered_candidates.is_empty() { if let Ok(response) = inject_normalize_to_rigid_candidate(self) { - candidates_from_env_and_bounds.push(response); + considered_candidates.push(response); } } - if let Some(response) = self.try_merge_responses(&candidates_from_env_and_bounds) { + if let Some(response) = self.try_merge_responses(&considered_candidates) { Ok(response) } else { - self.flounder(&candidates_from_env_and_bounds) + self.flounder(&considered_candidates) } } TraitGoalProvenVia::Misc => { diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs index c2fb592c3f3a..1526049719ea 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs @@ -5,9 +5,10 @@ use derive_where::derive_where; use rustc_type_ir::data_structures::HashMap; use rustc_type_ir::inherent::*; use rustc_type_ir::lang_items::TraitSolverLangItem; +use rustc_type_ir::solve::inspect::ProbeKind; use rustc_type_ir::{ - self as ty, Interner, Movability, Mutability, TypeFoldable, TypeFolder, TypeSuperFoldable, - Upcast as _, elaborate, + self as ty, FallibleTypeFolder, Interner, Movability, Mutability, TypeFoldable, + TypeSuperFoldable, Upcast as _, elaborate, }; use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic}; use tracing::instrument; @@ -822,22 +823,16 @@ pub(in crate::solve) fn const_conditions_for_destruct( /// impl Baz for dyn Foo {} /// ``` /// -/// However, in order to make such impls well-formed, we need to do an +/// However, in order to make such impls non-cyclical, we need to do an /// additional step of eagerly folding the associated types in the where /// clauses of the impl. In this example, that means replacing /// `::Bar` with `Ty` in the first impl. -/// -// FIXME: This is only necessary as `::Assoc: ItemBound` -// bounds in impls are trivially proven using the item bound candidates. -// This is unsound in general and once that is fixed, we don't need to -// normalize eagerly here. See https://github.com/lcnr/solver-woes/issues/9 -// for more details. pub(in crate::solve) fn predicates_for_object_candidate( - ecx: &EvalCtxt<'_, D>, + ecx: &mut EvalCtxt<'_, D>, param_env: I::ParamEnv, trait_ref: ty::TraitRef, object_bounds: I::BoundExistentialPredicates, -) -> Vec> +) -> Result>, Ambiguous> where D: SolverDelegate, I: Interner, @@ -871,72 +866,130 @@ where .extend(cx.item_bounds(associated_type_def_id).iter_instantiated(cx, trait_ref.args)); } - let mut replace_projection_with = HashMap::default(); + let mut replace_projection_with: HashMap<_, Vec<_>> = HashMap::default(); for bound in object_bounds.iter() { if let ty::ExistentialPredicate::Projection(proj) = bound.skip_binder() { + // FIXME: We *probably* should replace this with a dummy placeholder, + // b/c don't want to replace literal instances of this dyn type that + // show up in the bounds, but just ones that come from substituting + // `Self` with the dyn type. let proj = proj.with_self_ty(cx, trait_ref.self_ty()); - let old_ty = replace_projection_with.insert(proj.def_id(), bound.rebind(proj)); - assert_eq!( - old_ty, - None, - "{:?} has two generic parameters: {:?} and {:?}", - proj.projection_term, - proj.term, - old_ty.unwrap() - ); + replace_projection_with.entry(proj.def_id()).or_default().push(bound.rebind(proj)); } } - let mut folder = - ReplaceProjectionWith { ecx, param_env, mapping: replace_projection_with, nested: vec![] }; - let folded_requirements = requirements.fold_with(&mut folder); + let mut folder = ReplaceProjectionWith { + ecx, + param_env, + self_ty: trait_ref.self_ty(), + mapping: &replace_projection_with, + nested: vec![], + }; - folder + let requirements = requirements.try_fold_with(&mut folder)?; + Ok(folder .nested .into_iter() - .chain(folded_requirements.into_iter().map(|clause| Goal::new(cx, param_env, clause))) - .collect() + .chain(requirements.into_iter().map(|clause| Goal::new(cx, param_env, clause))) + .collect()) } -struct ReplaceProjectionWith<'a, D: SolverDelegate, I: Interner> { - ecx: &'a EvalCtxt<'a, D>, +struct ReplaceProjectionWith<'a, 'b, I: Interner, D: SolverDelegate> { + ecx: &'a mut EvalCtxt<'b, D>, param_env: I::ParamEnv, - mapping: HashMap>>, + self_ty: I::Ty, + mapping: &'a HashMap>>>, nested: Vec>, } -impl, I: Interner> TypeFolder - for ReplaceProjectionWith<'_, D, I> +impl ReplaceProjectionWith<'_, '_, I, D> +where + D: SolverDelegate, + I: Interner, { + fn projection_may_match( + &mut self, + source_projection: ty::Binder>, + target_projection: ty::AliasTerm, + ) -> bool { + source_projection.item_def_id() == target_projection.def_id + && self + .ecx + .probe(|_| ProbeKind::ProjectionCompatibility) + .enter(|ecx| -> Result<_, NoSolution> { + let source_projection = ecx.instantiate_binder_with_infer(source_projection); + ecx.eq(self.param_env, source_projection.projection_term, target_projection)?; + ecx.try_evaluate_added_goals() + }) + .is_ok() + } + + /// Try to replace an alias with the term present in the projection bounds of the self type. + /// Returns `Ok` if this alias is not eligible to be replaced, or bail with + /// `Err(Ambiguous)` if it's uncertain which projection bound to replace the term with due + /// to multiple bounds applying. + fn try_eagerly_replace_alias( + &mut self, + alias_term: ty::AliasTerm, + ) -> Result, Ambiguous> { + if alias_term.self_ty() != self.self_ty { + return Ok(None); + } + + let Some(replacements) = self.mapping.get(&alias_term.def_id) else { + return Ok(None); + }; + + // This is quite similar to the `projection_may_match` we use in unsizing, + // but here we want to unify a projection predicate against an alias term + // so we can replace it with the the projection predicate's term. + let mut matching_projections = replacements + .iter() + .filter(|source_projection| self.projection_may_match(**source_projection, alias_term)); + let Some(replacement) = matching_projections.next() else { + // This shouldn't happen. + panic!("could not replace {alias_term:?} with term from from {:?}", self.self_ty); + }; + // FIXME: This *may* have issues with duplicated projections. + if matching_projections.next().is_some() { + // If there's more than one projection that we can unify here, then we + // need to stall until inference constrains things so that there's only + // one choice. + return Err(Ambiguous); + } + + let replacement = self.ecx.instantiate_binder_with_infer(*replacement); + self.nested.extend( + self.ecx + .eq_and_get_goals(self.param_env, alias_term, replacement.projection_term) + .expect("expected to be able to unify goal projection with dyn's projection"), + ); + + Ok(Some(replacement.term)) + } +} + +/// Marker for bailing with ambiguity. +pub(crate) struct Ambiguous; + +impl FallibleTypeFolder for ReplaceProjectionWith<'_, '_, I, D> +where + D: SolverDelegate, + I: Interner, +{ + type Error = Ambiguous; + fn cx(&self) -> I { self.ecx.cx() } - fn fold_ty(&mut self, ty: I::Ty) -> I::Ty { + fn try_fold_ty(&mut self, ty: I::Ty) -> Result { if let ty::Alias(ty::Projection, alias_ty) = ty.kind() { - if let Some(replacement) = self.mapping.get(&alias_ty.def_id) { - // We may have a case where our object type's projection bound is higher-ranked, - // but the where clauses we instantiated are not. We can solve this by instantiating - // the binder at the usage site. - let proj = self.ecx.instantiate_binder_with_infer(*replacement); - // FIXME: Technically this equate could be fallible... - self.nested.extend( - self.ecx - .eq_and_get_goals( - self.param_env, - alias_ty, - proj.projection_term.expect_ty(self.ecx.cx()), - ) - .expect( - "expected to be able to unify goal projection with dyn's projection", - ), - ); - proj.term.expect_ty() - } else { - ty.super_fold_with(self) + if let Some(term) = self.try_eagerly_replace_alias(alias_ty.into())? { + return Ok(term.expect_ty()); } - } else { - ty.super_fold_with(self) } + + ty.try_super_fold_with(self) } } diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs index 4edc293ad807..d56b0e5847e5 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs @@ -355,7 +355,7 @@ where // exist at all (see the FIXME at the start of this method), we have to deal with // them for now. delegate.instantiate_canonical_var_with_infer(info, span, |idx| { - ty::UniverseIndex::from(prev_universe.index() + idx.index()) + prev_universe + idx.index() }) } else if info.is_existential() { // As an optimization we sometimes avoid creating a new inference variable here. diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index 148ba02252d9..9994c85d0d0d 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -286,18 +286,23 @@ where // fixing it may cause inference breakage or introduce ambiguity. GoalSource::Misc => PathKind::Unknown, GoalSource::NormalizeGoal(path_kind) => path_kind, - GoalSource::ImplWhereBound => { + GoalSource::ImplWhereBound => match self.current_goal_kind { // We currently only consider a cycle coinductive if it steps // into a where-clause of a coinductive trait. + CurrentGoalKind::CoinductiveTrait => PathKind::Coinductive, + // While normalizing via an impl does step into a where-clause of + // an impl, accessing the associated item immediately steps out of + // it again. This means cycles/recursive calls are not guarded + // by impls used for normalization. // + // See tests/ui/traits/next-solver/cycles/normalizes-to-is-not-productive.rs + // for how this can go wrong. + CurrentGoalKind::NormalizesTo => PathKind::Inductive, // We probably want to make all traits coinductive in the future, - // so we treat cycles involving their where-clauses as ambiguous. - if let CurrentGoalKind::CoinductiveTrait = self.current_goal_kind { - PathKind::Coinductive - } else { - PathKind::Unknown - } - } + // so we treat cycles involving where-clauses of not-yet coinductive + // traits as ambiguous for now. + CurrentGoalKind::Misc => PathKind::Unknown, + }, // Relating types is always unproductive. If we were to map proof trees to // corecursive functions as explained in #136824, relating types never // introduces a constructor which could cause the recursion to be guarded. diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs index de6d21da0f59..fdeb276a58e6 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs @@ -45,7 +45,6 @@ where goal, goal.predicate.alias, ); - this.add_goal(GoalSource::AliasWellFormed, goal.with(cx, trait_ref)); this.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) }) }) @@ -134,7 +133,7 @@ where // Add GAT where clauses from the trait's definition // FIXME: We don't need these, since these are the type's own WF obligations. ecx.add_goals( - GoalSource::Misc, + GoalSource::AliasWellFormed, cx.own_predicates_of(goal.predicate.def_id()) .iter_instantiated(cx, goal.predicate.alias.args) .map(|pred| goal.with(cx, pred)), @@ -199,7 +198,7 @@ where // Add GAT where clauses from the trait's definition. // FIXME: We don't need these, since these are the type's own WF obligations. ecx.add_goals( - GoalSource::Misc, + GoalSource::AliasWellFormed, cx.own_predicates_of(goal.predicate.def_id()) .iter_instantiated(cx, goal.predicate.alias.args) .map(|pred| goal.with(cx, pred)), @@ -232,7 +231,33 @@ where }; if !cx.has_item_definition(target_item_def_id) { - return error_response(ecx, cx.delay_bug("missing item")); + // If the impl is missing an item, it's either because the user forgot to + // provide it, or the user is not *obligated* to provide it (because it + // has a trivially false `Sized` predicate). If it's the latter, we cannot + // delay a bug because we can have trivially false where clauses, so we + // treat it as rigid. + if cx.impl_self_is_guaranteed_unsized(impl_def_id) { + match ecx.typing_mode() { + ty::TypingMode::Coherence => { + return ecx.evaluate_added_goals_and_make_canonical_response( + Certainty::AMBIGUOUS, + ); + } + ty::TypingMode::Analysis { .. } + | ty::TypingMode::Borrowck { .. } + | ty::TypingMode::PostBorrowckAnalysis { .. } + | ty::TypingMode::PostAnalysis => { + ecx.structurally_instantiate_normalizes_to_term( + goal, + goal.predicate.alias, + ); + return ecx + .evaluate_added_goals_and_make_canonical_response(Certainty::Yes); + } + } + } else { + return error_response(ecx, cx.delay_bug("missing item")); + } } let target_container_def_id = cx.parent(target_item_def_id); diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index d42c9980f463..409af8568d7a 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -164,6 +164,7 @@ where ecx: &mut EvalCtxt<'_, D>, goal: Goal, ) -> Result, NoSolution> { + let cx = ecx.cx(); if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } @@ -174,20 +175,37 @@ where // Only consider auto impls of unsafe traits when there are no unsafe // fields. - if ecx.cx().trait_is_unsafe(goal.predicate.def_id()) + if cx.trait_is_unsafe(goal.predicate.def_id()) && goal.predicate.self_ty().has_unsafe_fields() { return Err(NoSolution); } - // We only look into opaque types during analysis for opaque types - // outside of their defining scope. Doing so for opaques in the - // defining scope may require calling `typeck` on the same item we're - // currently type checking, which will result in a fatal cycle that - // ideally we want to avoid, since we can make progress on this goal - // via an alias bound or a locally-inferred hidden type instead. + // We leak the implemented auto traits of opaques outside of their defining scope. + // This depends on `typeck` of the defining scope of that opaque, which may result in + // fatal query cycles. + // + // We only get to this point if we're outside of the defining scope as we'd otherwise + // be able to normalize the opaque type. We may also cycle in case `typeck` of a defining + // scope relies on the current context, e.g. either because it also leaks auto trait + // bounds of opaques defined in the current context or by evaluating the current item. + // + // To avoid this we don't try to leak auto trait bounds if they can also be proven via + // item bounds of the opaque. These bounds are always applicable as auto traits must not + // have any generic parameters. They would also get preferred over the impl candidate + // when merging candidates anyways. + // + // See tests/ui/impl-trait/auto-trait-leakage/avoid-query-cycle-via-item-bound.rs. if let ty::Alias(ty::Opaque, opaque_ty) = goal.predicate.self_ty().kind() { debug_assert!(ecx.opaque_type_is_rigid(opaque_ty.def_id)); + for item_bound in cx.item_self_bounds(opaque_ty.def_id).skip_binder() { + if item_bound + .as_trait_clause() + .is_some_and(|b| b.def_id() == goal.predicate.def_id()) + { + return Err(NoSolution); + } + } } ecx.probe_and_evaluate_goal_for_constituent_tys( @@ -926,7 +944,7 @@ where target_projection: ty::Binder>| { source_projection.item_def_id() == target_projection.item_def_id() && ecx - .probe(|_| ProbeKind::UpcastProjectionCompatibility) + .probe(|_| ProbeKind::ProjectionCompatibility) .enter(|ecx| -> Result<_, NoSolution> { ecx.enter_forall(target_projection, |ecx, target_projection| { let source_projection = @@ -1238,10 +1256,11 @@ where D: SolverDelegate, I: Interner, { + #[instrument(level = "debug", skip(self, goal), ret)] pub(super) fn merge_trait_candidates( &mut self, goal: Goal>, - candidates: Vec>, + mut candidates: Vec>, ) -> Result<(CanonicalResponse, Option), NoSolution> { if let TypingMode::Coherence = self.typing_mode() { let all_candidates: Vec<_> = candidates.into_iter().map(|c| c.result).collect(); @@ -1323,13 +1342,16 @@ where // If there are *only* global where bounds, then make sure to return that this // is still reported as being proven-via the param-env so that rigid projections - // operate correctly. + // operate correctly. Otherwise, drop all global where-bounds before merging the + // remaining candidates. let proven_via = if candidates.iter().all(|c| matches!(c.source, CandidateSource::ParamEnv(_))) { TraitGoalProvenVia::ParamEnv } else { + candidates.retain(|c| !matches!(c.source, CandidateSource::ParamEnv(_))); TraitGoalProvenVia::Misc }; + let all_candidates: Vec<_> = candidates.into_iter().map(|c| c.result).collect(); if let Some(response) = self.try_merge_responses(&all_candidates) { Ok((response, Some(proven_via))) diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 93fa89b68b97..e7f17bb6f996 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -543,7 +543,7 @@ parse_maybe_recover_from_bad_qpath_stage_2 = .suggestion = types that don't start with an identifier need to be surrounded with angle brackets in qualified paths parse_maybe_recover_from_bad_type_plus = - expected a path on the left-hand side of `+`, not `{$ty}` + expected a path on the left-hand side of `+` parse_maybe_report_ambiguous_plus = ambiguous `+` in a type @@ -642,7 +642,9 @@ parse_mut_on_nested_ident_pattern = `mut` must be attached to each individual bi .suggestion = add `mut` to each binding parse_mut_on_non_ident_pattern = `mut` must be followed by a named binding .suggestion = remove the `mut` prefix -parse_need_plus_after_trait_object_lifetime = lifetime in trait object type must be followed by `+` + +parse_need_plus_after_trait_object_lifetime = lifetimes must be followed by `+` to form a trait object type + .suggestion = consider adding a trait bound after the potential lifetime bound parse_nested_adt = `{$kw_str}` definition cannot be nested inside `{$keyword}` .suggestion = consider creating a new `{$kw_str}` definition instead of nesting @@ -806,9 +808,6 @@ parse_trait_alias_cannot_be_unsafe = trait aliases cannot be `unsafe` parse_transpose_dyn_or_impl = `for<...>` expected after `{$kw}`, not before .suggestion = move `{$kw}` before the `for<...>` -parse_type_ascription_removed = - if you meant to annotate an expression with a type, the type ascription syntax has been removed, see issue #101728 - parse_unclosed_unicode_escape = unterminated unicode escape .label = missing a closing `{"}"}` .terminate = terminate the unicode escape diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index dfdef018bc37..44b4e1a3e47a 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -7,8 +7,7 @@ use rustc_ast::util::parser::ExprPrecedence; use rustc_ast::{Path, Visibility}; use rustc_errors::codes::*; use rustc_errors::{ - Applicability, Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, SubdiagMessageOp, - Subdiagnostic, + Applicability, Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, Subdiagnostic, }; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_session::errors::ExprParenthesesNeeded; @@ -30,7 +29,6 @@ pub(crate) struct AmbiguousPlus { #[derive(Diagnostic)] #[diag(parse_maybe_recover_from_bad_type_plus, code = E0178)] pub(crate) struct BadTypePlus { - pub ty: String, #[primary_span] pub span: Span, #[subdiagnostic] @@ -1551,11 +1549,7 @@ pub(crate) struct FnTraitMissingParen { } impl Subdiagnostic for FnTraitMissingParen { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { diag.span_label(self.span, crate::fluent_generated::parse_fn_trait_missing_paren); diag.span_suggestion_short( self.span.shrink_to_hi(), @@ -1598,9 +1592,6 @@ pub(crate) struct PathSingleColon { #[suggestion(applicability = "machine-applicable", code = ":", style = "verbose")] pub suggestion: Span, - - #[note(parse_type_ascription_removed)] - pub type_ascription: bool, } #[derive(Diagnostic)] @@ -1617,9 +1608,6 @@ pub(crate) struct ColonAsSemi { #[primary_span] #[suggestion(applicability = "machine-applicable", code = ";", style = "verbose")] pub span: Span, - - #[note(parse_type_ascription_removed)] - pub type_ascription: bool, } #[derive(Diagnostic)] @@ -2806,6 +2794,8 @@ pub(crate) struct ReturnTypesUseThinArrow { pub(crate) struct NeedPlusAfterTraitObjectLifetime { #[primary_span] pub span: Span, + #[suggestion(code = " + /* Trait */", applicability = "has-placeholders")] + pub suggestion: Span, } #[derive(Diagnostic)] diff --git a/compiler/rustc_parse/src/lexer/unicode_chars.rs b/compiler/rustc_parse/src/lexer/unicode_chars.rs index ff03b42484b4..2bfa1ea4e058 100644 --- a/compiler/rustc_parse/src/lexer/unicode_chars.rs +++ b/compiler/rustc_parse/src/lexer/unicode_chars.rs @@ -376,7 +376,7 @@ pub(super) fn check_for_substitution( ascii_name, }) }; - (token.clone(), sugg) + (*token, sugg) } /// Extract string if found at current position with given delimiters diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index 79939aab7fc2..2edc8c83017d 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -4,7 +4,6 @@ #![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] -#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![feature(array_windows)] #![feature(assert_matches)] #![feature(box_patterns)] diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs index cff998fa1379..f1bd6a227309 100644 --- a/compiler/rustc_parse/src/parser/attr_wrapper.rs +++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs @@ -120,7 +120,7 @@ impl ToAttrTokenStream for LazyAttrTokenStreamImpl { // produce an empty `TokenStream` if no calls were made, and omit the // final token otherwise. let mut cursor_snapshot = self.cursor_snapshot.clone(); - let tokens = iter::once(FlatToken::Token(self.start_token.clone())) + let tokens = iter::once(FlatToken::Token(self.start_token)) .chain(iter::repeat_with(|| FlatToken::Token(cursor_snapshot.next()))) .take(self.num_calls as usize); @@ -186,7 +186,7 @@ impl ToAttrTokenStream for LazyAttrTokenStreamImpl { impl<'a> Parser<'a> { pub(super) fn collect_pos(&self) -> CollectPos { CollectPos { - start_token: (self.token.clone(), self.token_spacing), + start_token: (self.token, self.token_spacing), cursor_snapshot: self.token_cursor.clone(), start_pos: self.num_bump_calls, } diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index ef044fe9d638..7c8e0146c3d2 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -322,7 +322,7 @@ impl<'a> Parser<'a> { let mut recovered_ident = None; // we take this here so that the correct original token is retained in // the diagnostic, regardless of eager recovery. - let bad_token = self.token.clone(); + let bad_token = self.token; // suggest prepending a keyword in identifier position with `r#` let suggest_raw = if let Some((ident, IdentIsRaw::No)) = self.token.ident() @@ -382,7 +382,7 @@ impl<'a> Parser<'a> { // if the previous token is a valid keyword // that might use a generic, then suggest a correct // generic placement (later on) - let maybe_keyword = self.prev_token.clone(); + let maybe_keyword = self.prev_token; if valid_prev_keywords.into_iter().any(|x| maybe_keyword.is_keyword(x)) { // if we have a valid keyword, attempt to parse generics // also obtain the keywords symbol @@ -530,7 +530,7 @@ impl<'a> Parser<'a> { // let y = 42; let guar = self.dcx().emit_err(ExpectedSemi { span: self.token.span, - token: self.token.clone(), + token: self.token, unexpected_token_label: None, sugg: ExpectedSemiSugg::ChangeToSemi(self.token.span), }); @@ -555,7 +555,7 @@ impl<'a> Parser<'a> { let span = self.prev_token.span.shrink_to_hi(); let guar = self.dcx().emit_err(ExpectedSemi { span, - token: self.token.clone(), + token: self.token, unexpected_token_label: Some(self.token.span), sugg: ExpectedSemiSugg::AddSemi(span), }); @@ -609,6 +609,8 @@ impl<'a> Parser<'a> { // FIXME: translation requires list formatting (for `expect`) let mut err = self.dcx().struct_span_err(self.token.span, msg_exp); + self.label_expected_raw_ref(&mut err); + // Look for usages of '=>' where '>=' was probably intended if self.token == token::FatArrow && expected.iter().any(|tok| matches!(tok, TokenType::Operator | TokenType::Le)) @@ -750,6 +752,25 @@ impl<'a> Parser<'a> { Err(err) } + /// Adds a label when `&raw EXPR` was written instead of `&raw const EXPR`/`&raw mut EXPR`. + /// + /// Given that not all parser diagnostics flow through `expected_one_of_not_found`, this + /// label may need added to other diagnostics emission paths as needed. + pub(super) fn label_expected_raw_ref(&mut self, err: &mut Diag<'_>) { + if self.prev_token.is_keyword(kw::Raw) + && self.expected_token_types.contains(TokenType::KwMut) + && self.expected_token_types.contains(TokenType::KwConst) + && self.token.can_begin_expr() + { + err.span_suggestions( + self.prev_token.span.shrink_to_hi(), + "`&raw` must be followed by `const` or `mut` to be a raw reference expression", + [" const".to_string(), " mut".to_string()], + Applicability::MaybeIncorrect, + ); + } + } + /// Checks if the current token or the previous token are misspelled keywords /// and adds a helpful suggestion. fn check_for_misspelled_kw(&self, err: &mut Diag<'_>, expected: &[TokenType]) { @@ -801,7 +822,7 @@ impl<'a> Parser<'a> { let span = self.prev_token.span.shrink_to_hi(); let mut err = self.dcx().create_err(ExpectedSemi { span, - token: self.token.clone(), + token: self.token, unexpected_token_label: Some(self.token.span), sugg: ExpectedSemiSugg::AddSemi(span), }); @@ -1636,19 +1657,19 @@ impl<'a> Parser<'a> { self.bump(); // `+` let _bounds = self.parse_generic_bounds()?; - let sum_span = ty.span.to(self.prev_token.span); - let sub = match &ty.kind { TyKind::Ref(_lifetime, mut_ty) => { let lo = mut_ty.ty.span.shrink_to_lo(); let hi = self.prev_token.span.shrink_to_hi(); BadTypePlusSub::AddParen { suggestion: AddParen { lo, hi } } } - TyKind::Ptr(..) | TyKind::BareFn(..) => BadTypePlusSub::ForgotParen { span: sum_span }, - _ => BadTypePlusSub::ExpectPath { span: sum_span }, + TyKind::Ptr(..) | TyKind::BareFn(..) => { + BadTypePlusSub::ForgotParen { span: ty.span.to(self.prev_token.span) } + } + _ => BadTypePlusSub::ExpectPath { span: ty.span }, }; - self.dcx().emit_err(BadTypePlus { ty: pprust::ty_to_string(ty), span: sum_span, sub }); + self.dcx().emit_err(BadTypePlus { span: ty.span, sub }); Ok(()) } @@ -1922,10 +1943,7 @@ impl<'a> Parser<'a> { && self.token == token::Colon && self.look_ahead(1, |next| line_idx(self.token.span) < line_idx(next.span)) { - self.dcx().emit_err(ColonAsSemi { - span: self.token.span, - type_ascription: self.psess.unstable_features.is_nightly_build(), - }); + self.dcx().emit_err(ColonAsSemi { span: self.token.span }); self.bump(); return true; } diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 9c457f150a32..df44b3cc23c8 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -344,7 +344,7 @@ impl<'a> Parser<'a> { fn error_found_expr_would_be_stmt(&self, lhs: &Expr) { self.dcx().emit_err(errors::FoundExprWouldBeStmt { span: self.token.span, - token: self.token.clone(), + token: self.token, suggestion: ExprParenthesesNeeded::surrounding(lhs.span), }); } @@ -417,7 +417,7 @@ impl<'a> Parser<'a> { cur_op_span: Span, ) -> PResult<'a, P> { let rhs = if self.is_at_start_of_range_notation_rhs() { - let maybe_lt = self.token.clone(); + let maybe_lt = self.token; let attrs = self.parse_outer_attributes()?; Some( self.parse_expr_assoc_with(Bound::Excluded(prec), attrs) @@ -611,7 +611,7 @@ impl<'a> Parser<'a> { /// Recover on `not expr` in favor of `!expr`. fn recover_not_expr(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> { - let negated_token = self.look_ahead(1, |t| t.clone()); + let negated_token = self.look_ahead(1, |t| *t); let sub_diag = if negated_token.is_numeric_lit() { errors::NotAsNegationOperatorSub::SuggestNotBitwise @@ -637,9 +637,7 @@ impl<'a> Parser<'a> { /// Returns the span of expr if it was not interpolated, or the span of the interpolated token. fn interpolated_or_expr_span(&self, expr: &Expr) -> Span { match self.prev_token.kind { - TokenKind::NtIdent(..) | TokenKind::NtLifetime(..) | TokenKind::Interpolated(..) => { - self.prev_token.span - } + TokenKind::NtIdent(..) | TokenKind::NtLifetime(..) => self.prev_token.span, TokenKind::CloseDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(_))) => { // `expr.span` is the interpolated span, because invisible open // and close delims both get marked with the same span, one @@ -829,6 +827,18 @@ impl<'a> Parser<'a> { if let Some(lt) = lifetime { self.error_remove_borrow_lifetime(span, lt.ident.span.until(expr.span)); } + + // Add expected tokens if we parsed `&raw` as an expression. + // This will make sure we see "expected `const`, `mut`", and + // guides recovery in case we write `&raw expr`. + if borrow_kind == ast::BorrowKind::Ref + && mutbl == ast::Mutability::Not + && matches!(&expr.kind, ExprKind::Path(None, p) if p.is_ident(kw::Raw)) + { + self.expected_token_types.insert(TokenType::KwMut); + self.expected_token_types.insert(TokenType::KwConst); + } + Ok((span, ExprKind::AddrOf(borrow_kind, mutbl, expr))) } @@ -1386,15 +1396,7 @@ impl<'a> Parser<'a> { maybe_recover_from_interpolated_ty_qpath!(self, true); let span = self.token.span; - if let token::Interpolated(nt) = &self.token.kind { - match &**nt { - token::NtBlock(block) => { - let block = block.clone(); - self.bump(); - return Ok(self.mk_expr(self.prev_token.span, ExprKind::Block(block, None))); - } - }; - } else if let Some(expr) = self.eat_metavar_seq_with_matcher( + if let Some(expr) = self.eat_metavar_seq_with_matcher( |mv_kind| matches!(mv_kind, MetaVarKind::Expr { .. }), |this| { // Force collection (as opposed to just `parse_expr`) is required to avoid the @@ -1415,9 +1417,13 @@ impl<'a> Parser<'a> { self.eat_metavar_seq(MetaVarKind::Literal, |this| this.parse_literal_maybe_minus()) { return Ok(lit); - } else if let Some(path) = self.eat_metavar_seq(MetaVarKind::Path, |this| { - this.collect_tokens_no_attrs(|this| this.parse_path(PathStyle::Type)) - }) { + } else if let Some(block) = + self.eat_metavar_seq(MetaVarKind::Block, |this| this.parse_block()) + { + return Ok(self.mk_expr(span, ExprKind::Block(block, None))); + } else if let Some(path) = + self.eat_metavar_seq(MetaVarKind::Path, |this| this.parse_path(PathStyle::Type)) + { return Ok(self.mk_expr(span, ExprKind::Path(None, path))); } @@ -1612,7 +1618,7 @@ impl<'a> Parser<'a> { } fn parse_expr_path_start(&mut self) -> PResult<'a, P> { - let maybe_eq_tok = self.prev_token.clone(); + let maybe_eq_tok = self.prev_token; let (qself, path) = if self.eat_lt() { let lt_span = self.prev_token.span; let (qself, path) = self.parse_qpath(PathStyle::Expr).map_err(|mut err| { @@ -1671,7 +1677,7 @@ impl<'a> Parser<'a> { } else if self.eat_keyword(exp!(Loop)) { self.parse_expr_loop(label, lo) } else if self.check_noexpect(&token::OpenDelim(Delimiter::Brace)) - || self.token.is_whole_block() + || self.token.is_metavar_block() { self.parse_expr_block(label, lo, BlockCheckMode::Default) } else if !ate_colon @@ -2073,7 +2079,7 @@ impl<'a> Parser<'a> { &mut self, mk_lit_char: impl FnOnce(Symbol, Span) -> L, ) -> PResult<'a, L> { - let token = self.token.clone(); + let token = self.token; let err = |self_: &Self| { let msg = format!("unexpected token: {}", super::token_descr(&token)); self_.dcx().struct_span_err(token.span, msg) @@ -2166,10 +2172,15 @@ impl<'a> Parser<'a> { let expr = self .eat_metavar_seq(mv_kind, |this| this.parse_expr()) .expect("metavar seq expr"); - let ast::ExprKind::Lit(token_lit) = expr.kind else { - panic!("didn't reparse an expr"); - }; - Some(token_lit) + if let ast::ExprKind::Lit(token_lit) = expr.kind { + Some(token_lit) + } else if let ast::ExprKind::Unary(UnOp::Neg, inner) = &expr.kind + && let ast::Expr { kind: ast::ExprKind::Lit(_), .. } = **inner + { + None + } else { + panic!("unexpected reparsed expr: {:?}", expr.kind); + } } _ => None, } @@ -2349,7 +2360,7 @@ impl<'a> Parser<'a> { } } - if self.token.is_whole_block() { + if self.token.is_metavar_block() { self.dcx().emit_err(errors::InvalidBlockMacroSegment { span: self.token.span, context: lo.to(self.token.span), @@ -2374,7 +2385,7 @@ impl<'a> Parser<'a> { fn parse_expr_closure(&mut self) -> PResult<'a, P> { let lo = self.token.span; - let before = self.prev_token.clone(); + let before = self.prev_token; let binder = if self.check_keyword(exp!(For)) { let lo = self.token.span; let (lifetime_defs, _) = self.parse_late_bound_lifetime_defs()?; @@ -2406,8 +2417,8 @@ impl<'a> Parser<'a> { FnRetTy::Default(_) => { let restrictions = self.restrictions - Restrictions::STMT_EXPR - Restrictions::ALLOW_LET; - let prev = self.prev_token.clone(); - let token = self.token.clone(); + let prev = self.prev_token; + let token = self.token; let attrs = self.parse_outer_attributes()?; match self.parse_expr_res(restrictions, attrs) { Ok((expr, _)) => expr, @@ -2472,7 +2483,7 @@ impl<'a> Parser<'a> { if self.may_recover() && self.token.can_begin_expr() && !matches!(self.token.kind, TokenKind::OpenDelim(Delimiter::Brace)) - && !self.token.is_whole_block() + && !self.token.is_metavar_block() { let snapshot = self.create_snapshot_for_diagnostic(); let restrictions = @@ -2654,7 +2665,7 @@ impl<'a> Parser<'a> { } } else { let attrs = self.parse_outer_attributes()?; // For recovery. - let maybe_fatarrow = self.token.clone(); + let maybe_fatarrow = self.token; let block = if self.check(exp!(OpenBrace)) { self.parse_block()? } else if let Some(block) = recover_block_from_condition(self) { @@ -3519,7 +3530,7 @@ impl<'a> Parser<'a> { self.token.is_keyword(kw::Do) && self.is_keyword_ahead(1, &[kw::Catch]) && self - .look_ahead(2, |t| *t == token::OpenDelim(Delimiter::Brace) || t.is_whole_block()) + .look_ahead(2, |t| *t == token::OpenDelim(Delimiter::Brace) || t.is_metavar_block()) && !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL) } @@ -3530,7 +3541,7 @@ impl<'a> Parser<'a> { fn is_try_block(&self) -> bool { self.token.is_keyword(kw::Try) && self - .look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Brace) || t.is_whole_block()) + .look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Brace) || t.is_metavar_block()) && self.token_uninterpolated_span().at_least_rust_2018() } @@ -3564,12 +3575,12 @@ impl<'a> Parser<'a> { // `async move {` self.is_keyword_ahead(lookahead + 1, &[kw::Move, kw::Use]) && self.look_ahead(lookahead + 2, |t| { - *t == token::OpenDelim(Delimiter::Brace) || t.is_whole_block() + *t == token::OpenDelim(Delimiter::Brace) || t.is_metavar_block() }) ) || ( // `async {` self.look_ahead(lookahead + 1, |t| { - *t == token::OpenDelim(Delimiter::Brace) || t.is_whole_block() + *t == token::OpenDelim(Delimiter::Brace) || t.is_metavar_block() }) )) } @@ -3862,7 +3873,7 @@ impl<'a> Parser<'a> { return Err(this.dcx().create_err(errors::ExpectedStructField { span: this.look_ahead(1, |t| t.span), ident_span: this.token.span, - token: this.look_ahead(1, |t| t.clone()), + token: this.look_ahead(1, |t| *t), })); } let (ident, expr) = if is_shorthand { diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 9405b58ab3b4..39a0291cb1ef 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -602,21 +602,13 @@ impl<'a> Parser<'a> { let polarity = self.parse_polarity(); // Parse both types and traits as a type, then reinterpret if necessary. - let err_path = |span| ast::Path::from_ident(Ident::new(kw::Empty, span)); let ty_first = if self.token.is_keyword(kw::For) && self.look_ahead(1, |t| t != &token::Lt) { let span = self.prev_token.span.between(self.token.span); - self.dcx().emit_err(errors::MissingTraitInTraitImpl { + return Err(self.dcx().create_err(errors::MissingTraitInTraitImpl { span, for_span: span.to(self.token.span), - }); - - P(Ty { - kind: TyKind::Path(None, err_path(span)), - span, - id: DUMMY_NODE_ID, - tokens: None, - }) + })); } else { self.parse_ty_with_generics_recovery(&generics)? }; @@ -657,6 +649,7 @@ impl<'a> Parser<'a> { other => { if let TyKind::ImplTrait(_, bounds) = other && let [bound] = bounds.as_slice() + && let GenericBound::Trait(poly_trait_ref) = bound { // Suggest removing extra `impl` keyword: // `impl impl Default for Wrapper` @@ -666,12 +659,12 @@ impl<'a> Parser<'a> { extra_impl_kw, impl_trait_span: ty_first.span, }); + poly_trait_ref.trait_ref.path.clone() } else { - self.dcx().emit_err(errors::ExpectedTraitInTraitImplFoundType { - span: ty_first.span, - }); + return Err(self.dcx().create_err( + errors::ExpectedTraitInTraitImplFoundType { span: ty_first.span }, + )); } - err_path(ty_first.span) } }; let trait_ref = TraitRef { path, ref_id: ty_first.id }; @@ -1739,8 +1732,7 @@ impl<'a> Parser<'a> { self.expect_semi()?; body } else { - let err = - errors::UnexpectedTokenAfterStructName::new(self.token.span, self.token.clone()); + let err = errors::UnexpectedTokenAfterStructName::new(self.token.span, self.token); return Err(self.dcx().create_err(err)); }; @@ -2310,7 +2302,7 @@ impl<'a> Parser<'a> { || self.token.is_keyword(kw::Union)) && self.look_ahead(1, |t| t.is_ident()) { - let kw_token = self.token.clone(); + let kw_token = self.token; let kw_str = pprust::token_to_string(&kw_token); let item = self.parse_item(ForceCollect::No)?; let mut item = item.unwrap().span; @@ -2543,7 +2535,7 @@ impl<'a> Parser<'a> { self.expect_semi()?; *sig_hi = self.prev_token.span; (AttrVec::new(), None) - } else if self.check(exp!(OpenBrace)) || self.token.is_whole_block() { + } else if self.check(exp!(OpenBrace)) || self.token.is_metavar_block() { self.parse_block_common(self.token.span, BlockCheckMode::Default, None) .map(|(attrs, body)| (attrs, Some(body)))? } else if self.token == token::Eq { @@ -2987,9 +2979,7 @@ impl<'a> Parser<'a> { } match ty { Ok(ty) => { - let ident = Ident::new(kw::Empty, this.prev_token.span); - let bm = BindingMode::NONE; - let pat = this.mk_pat_ident(ty.span, bm, ident); + let pat = this.mk_pat(ty.span, PatKind::Missing); (pat, ty) } // If this is a C-variadic argument and we hit an error, return the error. diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 3b0861a9942a..2221a261b4c5 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -13,7 +13,6 @@ mod ty; use std::assert_matches::debug_assert_matches; use std::ops::Range; -use std::sync::Arc; use std::{fmt, mem, slice}; use attr_wrapper::{AttrWrapper, UsePreAttrPos}; @@ -24,8 +23,8 @@ pub use pat::{CommaRecoveryMode, RecoverColon, RecoverComma}; use path::PathStyle; use rustc_ast::ptr::P; use rustc_ast::token::{ - self, Delimiter, IdentIsRaw, InvisibleOrigin, MetaVarKind, Nonterminal, NtExprKind, NtPatKind, - Token, TokenKind, + self, Delimiter, IdentIsRaw, InvisibleOrigin, MetaVarKind, NtExprKind, NtPatKind, Token, + TokenKind, }; use rustc_ast::tokenstream::{AttrsTarget, Spacing, TokenStream, TokenTree}; use rustc_ast::util::case::Case; @@ -98,21 +97,6 @@ pub enum ForceCollect { No, } -#[macro_export] -macro_rules! maybe_whole { - ($p:expr, $constructor:ident, |$x:ident| $e:expr) => { - #[allow(irrefutable_let_patterns)] // FIXME: temporary - if let token::Interpolated(nt) = &$p.token.kind - && let token::$constructor(x) = &**nt - { - #[allow(unused_mut)] - let mut $x = x.clone(); - $p.bump(); - return Ok($e); - } - }; -} - /// If the next tokens are ill-formed `$ty::` recover them as `<$ty>::`. #[macro_export] macro_rules! maybe_recover_from_interpolated_ty_qpath { @@ -342,12 +326,12 @@ impl TokenCursor { // below can be removed. if let Some(tree) = self.curr.curr() { match tree { - &TokenTree::Token(ref token, spacing) => { + &TokenTree::Token(token, spacing) => { debug_assert!(!matches!( token.kind, token::OpenDelim(_) | token::CloseDelim(_) )); - let res = (token.clone(), spacing); + let res = (token, spacing); self.curr.bump(); return res; } @@ -459,7 +443,6 @@ pub fn token_descr(token: &Token) -> String { (Some(TokenDescription::MetaVar(kind)), _) => format!("`{kind}` metavariable"), (None, TokenKind::NtIdent(..)) => format!("identifier `{s}`"), (None, TokenKind::NtLifetime(..)) => format!("lifetime `{s}`"), - (None, TokenKind::Interpolated(node)) => format!("{} `{s}`", node.descr()), (None, _) => format!("`{s}`"), } } @@ -782,9 +765,16 @@ impl<'a> Parser<'a> { // Recovery is disabled when parsing macro arguments, so it must // also be disabled when reparsing pasted macro arguments, // otherwise we get inconsistent results (e.g. #137874). - let res = self.with_recovery(Recovery::Forbidden, |this| { - f(this).expect("failed to reparse {mv_kind:?}") - }); + let res = self.with_recovery(Recovery::Forbidden, |this| f(this)); + + let res = match res { + Ok(res) => res, + Err(err) => { + // This can occur in unusual error cases, e.g. #139445. + err.delay_as_bug(); + return None; + } + }; if let token::CloseDelim(delim) = self.token.kind && let Delimiter::Invisible(InvisibleOrigin::MetaVar(mv_kind)) = delim @@ -793,7 +783,12 @@ impl<'a> Parser<'a> { self.bump(); Some(res) } else { - panic!("no close delim when reparsing {mv_kind:?}"); + // This can occur when invalid syntax is passed to a decl macro. E.g. see #139248, + // where the reparse attempt of an invalid expr consumed the trailing invisible + // delimiter. + self.dcx() + .span_delayed_bug(self.token.span, "no close delim with reparsing {mv_kind:?}"); + None } } else { None @@ -843,8 +838,10 @@ impl<'a> Parser<'a> { fn check_inline_const(&self, dist: usize) -> bool { self.is_keyword_ahead(dist, &[kw::Const]) && self.look_ahead(dist + 1, |t| match &t.kind { - token::Interpolated(nt) => matches!(&**nt, token::NtBlock(..)), token::OpenDelim(Delimiter::Brace) => true, + token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar( + MetaVarKind::Block, + ))) => true, _ => false, }) } @@ -1390,7 +1387,7 @@ impl<'a> Parser<'a> { // Avoid const blocks and const closures to be parsed as const items if (self.check_const_closure() == is_closure) && !self - .look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Brace) || t.is_whole_block()) + .look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Brace) || t.is_metavar_block()) && self.eat_keyword_case(exp!(Const), case) { Const::Yes(self.prev_token_uninterpolated_span()) @@ -1520,7 +1517,7 @@ impl<'a> Parser<'a> { _ => { let prev_spacing = self.token_spacing; self.bump(); - TokenTree::Token(self.prev_token.clone(), prev_spacing) + TokenTree::Token(self.prev_token, prev_spacing) } } } @@ -1706,7 +1703,7 @@ impl<'a> Parser<'a> { dbg_fmt.field("prev_token", &self.prev_token); let mut tokens = vec![]; for i in 0..lookahead { - let tok = self.look_ahead(i, |tok| tok.kind.clone()); + let tok = self.look_ahead(i, |tok| tok.kind); let is_eof = tok == TokenKind::Eof; tokens.push(tok); if is_eof { @@ -1747,7 +1744,6 @@ impl<'a> Parser<'a> { pub fn token_uninterpolated_span(&self) -> Span { match &self.token.kind { token::NtIdent(ident, _) | token::NtLifetime(ident, _) => ident.span, - token::Interpolated(nt) => nt.use_span(), token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(_))) => { self.look_ahead(1, |t| t.span) } @@ -1759,7 +1755,6 @@ impl<'a> Parser<'a> { pub fn prev_token_uninterpolated_span(&self) -> Span { match &self.prev_token.kind { token::NtIdent(ident, _) | token::NtLifetime(ident, _) => ident.span, - token::Interpolated(nt) => nt.use_span(), token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(_))) => { self.look_ahead(0, |t| t.span) } @@ -1816,6 +1811,7 @@ pub enum ParseNtResult { Ident(Ident, IdentIsRaw), Lifetime(Ident, IdentIsRaw), Item(P), + Block(P), Stmt(P), Pat(P, NtPatKind), Expr(P, NtExprKind), @@ -1824,7 +1820,4 @@ pub enum ParseNtResult { Meta(P), Path(P), Vis(P), - - /// This variant will eventually be removed, along with `Token::Interpolate`. - Nt(Arc), } diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs index b4e540d670d1..b6e89cd7fa46 100644 --- a/compiler/rustc_parse/src/parser/nonterminal.rs +++ b/compiler/rustc_parse/src/parser/nonterminal.rs @@ -1,14 +1,7 @@ -use std::sync::Arc; - -use rustc_ast::HasTokens; use rustc_ast::ptr::P; -use rustc_ast::token::Nonterminal::*; use rustc_ast::token::NtExprKind::*; use rustc_ast::token::NtPatKind::*; -use rustc_ast::token::{ - self, Delimiter, InvisibleOrigin, MetaVarKind, Nonterminal, NonterminalKind, Token, -}; -use rustc_ast_pretty::pprust; +use rustc_ast::token::{self, Delimiter, InvisibleOrigin, MetaVarKind, NonterminalKind, Token}; use rustc_errors::PResult; use rustc_span::{Ident, kw}; @@ -45,13 +38,6 @@ impl<'a> Parser<'a> { } } - /// Old variant of `may_be_ident`. Being phased out. - fn nt_may_be_ident(nt: &Nonterminal) -> bool { - match nt { - NtBlock(_) => false, - } - } - match kind { // `expr_2021` and earlier NonterminalKind::Expr(Expr2021 { .. }) => { @@ -83,16 +69,12 @@ impl<'a> Parser<'a> { | token::Ident(..) | token::NtIdent(..) | token::NtLifetime(..) - | token::Interpolated(_) | token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(_))) => true, _ => token.can_begin_type(), }, NonterminalKind::Block => match &token.kind { token::OpenDelim(Delimiter::Brace) => true, token::NtLifetime(..) => true, - token::Interpolated(nt) => match &**nt { - NtBlock(_) => true, - }, token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(k))) => match k { MetaVarKind::Block | MetaVarKind::Stmt @@ -112,7 +94,6 @@ impl<'a> Parser<'a> { }, NonterminalKind::Path | NonterminalKind::Meta => match &token.kind { token::PathSep | token::Ident(..) | token::NtIdent(..) => true, - token::Interpolated(nt) => nt_may_be_ident(nt), token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(kind))) => { may_be_ident(*kind) } @@ -136,110 +117,85 @@ impl<'a> Parser<'a> { // A `macro_rules!` invocation may pass a captured item/expr to a proc-macro, // which requires having captured tokens available. Since we cannot determine // in advance whether or not a proc-macro will be (transitively) invoked, - // we always capture tokens for any `Nonterminal` which needs them. - let mut nt = match kind { + // we always capture tokens for any nonterminal that needs them. + match kind { // Note that TT is treated differently to all the others. - NonterminalKind::TT => return Ok(ParseNtResult::Tt(self.parse_token_tree())), + NonterminalKind::TT => Ok(ParseNtResult::Tt(self.parse_token_tree())), NonterminalKind::Item => match self.parse_item(ForceCollect::Yes)? { - Some(item) => return Ok(ParseNtResult::Item(item)), - None => { - return Err(self - .dcx() - .create_err(UnexpectedNonterminal::Item(self.token.span))); - } + Some(item) => Ok(ParseNtResult::Item(item)), + None => Err(self.dcx().create_err(UnexpectedNonterminal::Item(self.token.span))), }, NonterminalKind::Block => { // While a block *expression* may have attributes (e.g. `#[my_attr] { ... }`), // the ':block' matcher does not support them - NtBlock(self.collect_tokens_no_attrs(|this| this.parse_block())?) + Ok(ParseNtResult::Block(self.collect_tokens_no_attrs(|this| this.parse_block())?)) } NonterminalKind::Stmt => match self.parse_stmt(ForceCollect::Yes)? { - Some(stmt) => return Ok(ParseNtResult::Stmt(P(stmt))), + Some(stmt) => Ok(ParseNtResult::Stmt(P(stmt))), None => { - return Err(self - .dcx() - .create_err(UnexpectedNonterminal::Statement(self.token.span))); + Err(self.dcx().create_err(UnexpectedNonterminal::Statement(self.token.span))) } }, - NonterminalKind::Pat(pat_kind) => { - return Ok(ParseNtResult::Pat( - self.collect_tokens_no_attrs(|this| match pat_kind { - PatParam { .. } => this.parse_pat_no_top_alt(None, None), - PatWithOr => this.parse_pat_no_top_guard( - None, - RecoverComma::No, - RecoverColon::No, - CommaRecoveryMode::EitherTupleOrPipe, - ), - })?, - pat_kind, - )); - } + NonterminalKind::Pat(pat_kind) => Ok(ParseNtResult::Pat( + self.collect_tokens_no_attrs(|this| match pat_kind { + PatParam { .. } => this.parse_pat_no_top_alt(None, None), + PatWithOr => this.parse_pat_no_top_guard( + None, + RecoverComma::No, + RecoverColon::No, + CommaRecoveryMode::EitherTupleOrPipe, + ), + })?, + pat_kind, + )), NonterminalKind::Expr(expr_kind) => { - return Ok(ParseNtResult::Expr(self.parse_expr_force_collect()?, expr_kind)); + Ok(ParseNtResult::Expr(self.parse_expr_force_collect()?, expr_kind)) } NonterminalKind::Literal => { // The `:literal` matcher does not support attributes. - return Ok(ParseNtResult::Literal( + Ok(ParseNtResult::Literal( self.collect_tokens_no_attrs(|this| this.parse_literal_maybe_minus())?, - )); + )) } - NonterminalKind::Ty => { - return Ok(ParseNtResult::Ty( - self.collect_tokens_no_attrs(|this| this.parse_ty_no_question_mark_recover())?, - )); - } - // this could be handled like a token, since it is one + NonterminalKind::Ty => Ok(ParseNtResult::Ty( + self.collect_tokens_no_attrs(|this| this.parse_ty_no_question_mark_recover())?, + )), + // This could be handled like a token, since it is one. NonterminalKind::Ident => { - return if let Some((ident, is_raw)) = get_macro_ident(&self.token) { + if let Some((ident, is_raw)) = get_macro_ident(&self.token) { self.bump(); Ok(ParseNtResult::Ident(ident, is_raw)) } else { Err(self.dcx().create_err(UnexpectedNonterminal::Ident { span: self.token.span, - token: self.token.clone(), + token: self.token, })) - }; - } - NonterminalKind::Path => { - return Ok(ParseNtResult::Path(P( - self.collect_tokens_no_attrs(|this| this.parse_path(PathStyle::Type))? - ))); + } } + NonterminalKind::Path => Ok(ParseNtResult::Path(P( + self.collect_tokens_no_attrs(|this| this.parse_path(PathStyle::Type))? + ))), NonterminalKind::Meta => { - return Ok(ParseNtResult::Meta(P(self.parse_attr_item(ForceCollect::Yes)?))); + Ok(ParseNtResult::Meta(P(self.parse_attr_item(ForceCollect::Yes)?))) } NonterminalKind::Vis => { - return Ok(ParseNtResult::Vis(P(self.collect_tokens_no_attrs(|this| { - this.parse_visibility(FollowedByType::Yes) - })?))); + Ok(ParseNtResult::Vis(P(self + .collect_tokens_no_attrs(|this| this.parse_visibility(FollowedByType::Yes))?))) } NonterminalKind::Lifetime => { // We want to keep `'keyword` parsing, just like `keyword` is still // an ident for nonterminal purposes. - return if let Some((ident, is_raw)) = self.token.lifetime() { + if let Some((ident, is_raw)) = self.token.lifetime() { self.bump(); Ok(ParseNtResult::Lifetime(ident, is_raw)) } else { Err(self.dcx().create_err(UnexpectedNonterminal::Lifetime { span: self.token.span, - token: self.token.clone(), + token: self.token, })) - }; + } } - }; - - // If tokens are supported at all, they should be collected. - if matches!(nt.tokens_mut(), Some(None)) { - panic!( - "Missing tokens for nt {:?} at {:?}: {:?}", - nt, - nt.use_span(), - pprust::nonterminal_to_string(&nt) - ); } - - Ok(ParseNtResult::Nt(Arc::new(nt))) } } diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 9612f71b2af9..d5f469f9aa9e 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -363,7 +363,7 @@ impl<'a> Parser<'a> { self.dcx().emit_err(TrailingVertNotAllowed { span: self.token.span, start: lo, - token: self.token.clone(), + token: self.token, note_double_vert: matches!(self.token.kind, token::OrOr), }); self.bump(); @@ -1519,8 +1519,8 @@ impl<'a> Parser<'a> { etc = PatFieldsRest::Rest; let mut etc_sp = self.token.span; if first_etc_and_maybe_comma_span.is_none() { - if let Some(comma_tok) = self - .look_ahead(1, |t| if *t == token::Comma { Some(t.clone()) } else { None }) + if let Some(comma_tok) = + self.look_ahead(1, |&t| if t == token::Comma { Some(t) } else { None }) { let nw_span = self .psess diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 9c6830c36727..028836556623 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -273,7 +273,6 @@ impl<'a> Parser<'a> { self.dcx().emit_err(PathSingleColon { span: self.prev_token.span, suggestion: self.prev_token.span.shrink_to_hi(), - type_ascription: self.psess.unstable_features.is_nightly_build(), }); } continue; @@ -348,7 +347,6 @@ impl<'a> Parser<'a> { err = self.dcx().create_err(PathSingleColon { span: self.token.span, suggestion: self.prev_token.span.shrink_to_hi(), - type_ascription: self.psess.unstable_features.is_nightly_build(), }); } // Attempt to find places where a missing `>` might belong. @@ -393,8 +391,8 @@ impl<'a> Parser<'a> { } else { // `(T, U) -> R` - let prev_token_before_parsing = self.prev_token.clone(); - let token_before_parsing = self.token.clone(); + let prev_token_before_parsing = self.prev_token; + let token_before_parsing = self.token; let mut snapshot = None; if self.may_recover() && prev_token_before_parsing == token::PathSep diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 2cd09aa8959c..0cc8b6050186 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -23,8 +23,8 @@ use super::{ AttrWrapper, BlockMode, FnParseMode, ForceCollect, Parser, Restrictions, SemiColonMode, Trailing, UsePreAttrPos, }; -use crate::errors::MalformedLoopLabel; -use crate::{errors, exp, maybe_whole}; +use crate::errors::{self, MalformedLoopLabel}; +use crate::exp; impl<'a> Parser<'a> { /// Parses a statement. This stops just before trailing semicolons on everything but items. @@ -75,10 +75,11 @@ impl<'a> Parser<'a> { let stmt = if self.token.is_keyword(kw::Super) && self.is_keyword_ahead(1, &[kw::Let]) { self.collect_tokens(None, attrs, force_collect, |this, attrs| { + let super_span = this.token.span; this.expect_keyword(exp!(Super))?; - this.psess.gated_spans.gate(sym::super_let, this.prev_token.span); this.expect_keyword(exp!(Let))?; - let local = this.parse_local(attrs)?; // FIXME(mara): implement super let + this.psess.gated_spans.gate(sym::super_let, super_span); + let local = this.parse_local(Some(super_span), attrs)?; let trailing = Trailing::from(capture_semi && this.token == token::Semi); Ok(( this.mk_stmt(lo.to(this.prev_token.span), StmtKind::Let(local)), @@ -89,7 +90,7 @@ impl<'a> Parser<'a> { } else if self.token.is_keyword(kw::Let) { self.collect_tokens(None, attrs, force_collect, |this, attrs| { this.expect_keyword(exp!(Let))?; - let local = this.parse_local(attrs)?; + let local = this.parse_local(None, attrs)?; let trailing = Trailing::from(capture_semi && this.token == token::Semi); Ok(( this.mk_stmt(lo.to(this.prev_token.span), StmtKind::Let(local)), @@ -294,7 +295,7 @@ impl<'a> Parser<'a> { force_collect: ForceCollect, ) -> PResult<'a, Stmt> { let stmt = self.collect_tokens(None, attrs, force_collect, |this, attrs| { - let local = this.parse_local(attrs)?; + let local = this.parse_local(None, attrs)?; // FIXME - maybe capture semicolon in recovery? Ok(( this.mk_stmt(lo.to(this.prev_token.span), StmtKind::Let(local)), @@ -308,8 +309,8 @@ impl<'a> Parser<'a> { } /// Parses a local variable declaration. - fn parse_local(&mut self, attrs: AttrVec) -> PResult<'a, P> { - let lo = self.prev_token.span; + fn parse_local(&mut self, super_: Option, attrs: AttrVec) -> PResult<'a, P> { + let lo = super_.unwrap_or(self.prev_token.span); if self.token.is_keyword(kw::Const) && self.look_ahead(1, |t| t.is_ident()) { self.dcx().emit_err(errors::ConstLetMutuallyExclusive { span: lo.to(self.token.span) }); @@ -411,6 +412,7 @@ impl<'a> Parser<'a> { }; let hi = if self.token == token::Semi { self.token.span } else { self.prev_token.span }; Ok(P(ast::Local { + super_, ty, pat, kind, @@ -516,7 +518,11 @@ impl<'a> Parser<'a> { let prev = self.prev_token.span; let sp = self.token.span; let mut e = self.dcx().struct_span_err(sp, msg); - let do_not_suggest_help = self.token.is_keyword(kw::In) || self.token == token::Colon; + self.label_expected_raw_ref(&mut e); + + let do_not_suggest_help = self.token.is_keyword(kw::In) + || self.token == token::Colon + || self.prev_token.is_keyword(kw::Raw); // Check to see if the user has written something like // @@ -694,9 +700,11 @@ impl<'a> Parser<'a> { blk_mode: BlockCheckMode, loop_header: Option, ) -> PResult<'a, (AttrVec, P)> { - maybe_whole!(self, NtBlock, |block| (AttrVec::new(), block)); + if let Some(block) = self.eat_metavar_seq(MetaVarKind::Block, |this| this.parse_block()) { + return Ok((AttrVec::new(), block)); + } - let maybe_ident = self.prev_token.clone(); + let maybe_ident = self.prev_token; self.maybe_recover_unexpected_block_label(loop_header); if !self.eat(exp!(OpenBrace)) { return self.error_block_no_opening_brace(); @@ -763,10 +771,6 @@ impl<'a> Parser<'a> { Applicability::MaybeIncorrect, ); } - if self.psess.unstable_features.is_nightly_build() { - // FIXME(Nilstrieb): Remove this again after a few months. - err.note("type ascription syntax has been removed, see issue #101728 "); - } } } @@ -909,7 +913,7 @@ impl<'a> Parser<'a> { { if self.token == token::Colon && self.look_ahead(1, |token| { - token.is_whole_block() + token.is_metavar_block() || matches!( token.kind, token::Ident( diff --git a/compiler/rustc_parse/src/parser/tests.rs b/compiler/rustc_parse/src/parser/tests.rs index 49ae6cb9b726..2f958f4d4927 100644 --- a/compiler/rustc_parse/src/parser/tests.rs +++ b/compiler/rustc_parse/src/parser/tests.rs @@ -2554,7 +2554,7 @@ fn look(p: &Parser<'_>, dist: usize, kind: rustc_ast::token::TokenKind) { // Do the `assert_eq` outside the closure so that `track_caller` works. // (`#![feature(closure_track_caller)]` + `#[track_caller]` on the closure // doesn't give the line number in the test below if the assertion fails.) - let tok = p.look_ahead(dist, |tok| tok.clone()); + let tok = p.look_ahead(dist, |tok| *tok); assert_eq!(kind, tok.kind); } diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 93705da22c45..42ebf26784df 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -7,7 +7,7 @@ use rustc_ast::{ Pinnedness, PolyTraitRef, PreciseCapturingArg, TraitBoundModifiers, TraitObjectSyntax, Ty, TyKind, UnsafeBinderTy, }; -use rustc_errors::{Applicability, PResult}; +use rustc_errors::{Applicability, Diag, PResult}; use rustc_span::{ErrorGuaranteed, Ident, Span, kw, sym}; use thin_vec::{ThinVec, thin_vec}; @@ -411,6 +411,9 @@ impl<'a> Parser<'a> { TyKind::Path(None, path) if maybe_bounds => { self.parse_remaining_bounds_path(ThinVec::new(), path, lo, true) } + // For `('a) + …`, we know that `'a` in type position already lead to an error being + // emitted. To reduce output, let's indirectly suppress E0178 (bad `+` in type) and + // other irrelevant consequential errors. TyKind::TraitObject(bounds, TraitObjectSyntax::None) if maybe_bounds && bounds.len() == 1 && !trailing_plus => { @@ -425,12 +428,60 @@ impl<'a> Parser<'a> { } fn parse_bare_trait_object(&mut self, lo: Span, allow_plus: AllowPlus) -> PResult<'a, TyKind> { - let lt_no_plus = self.check_lifetime() && !self.look_ahead(1, |t| t.is_like_plus()); - let bounds = self.parse_generic_bounds_common(allow_plus)?; - if lt_no_plus { - self.dcx().emit_err(NeedPlusAfterTraitObjectLifetime { span: lo }); + // A lifetime only begins a bare trait object type if it is followed by `+`! + if self.token.is_lifetime() && !self.look_ahead(1, |t| t.is_like_plus()) { + // In Rust 2021 and beyond, we assume that the user didn't intend to write a bare trait + // object type with a leading lifetime bound since that seems very unlikely given the + // fact that `dyn`-less trait objects are *semantically* invalid. + if self.psess.edition.at_least_rust_2021() { + let lt = self.expect_lifetime(); + let mut err = self.dcx().struct_span_err(lo, "expected type, found lifetime"); + err.span_label(lo, "expected type"); + return Ok(match self.maybe_recover_ref_ty_no_leading_ampersand(lt, lo, err) { + Ok(ref_ty) => ref_ty, + Err(err) => TyKind::Err(err.emit()), + }); + } + + self.dcx().emit_err(NeedPlusAfterTraitObjectLifetime { + span: lo, + suggestion: lo.shrink_to_hi(), + }); + } + Ok(TyKind::TraitObject( + self.parse_generic_bounds_common(allow_plus)?, + TraitObjectSyntax::None, + )) + } + + fn maybe_recover_ref_ty_no_leading_ampersand<'cx>( + &mut self, + lt: Lifetime, + lo: Span, + mut err: Diag<'cx>, + ) -> Result> { + if !self.may_recover() { + return Err(err); + } + let snapshot = self.create_snapshot_for_diagnostic(); + let mutbl = self.parse_mutability(); + match self.parse_ty_no_plus() { + Ok(ty) => { + err.span_suggestion_verbose( + lo.shrink_to_lo(), + "you might have meant to write a reference type here", + "&", + Applicability::MaybeIncorrect, + ); + err.emit(); + Ok(TyKind::Ref(Some(lt), MutTy { ty, mutbl })) + } + Err(diag) => { + diag.cancel(); + self.restore_snapshot(snapshot); + Err(err) + } } - Ok(TyKind::TraitObject(bounds, TraitObjectSyntax::None)) } fn parse_remaining_bounds_path( @@ -547,7 +598,7 @@ impl<'a> Parser<'a> { // Recovery mutbl = Mutability::Mut; - let (dyn_tok, dyn_tok_sp) = (self.token.clone(), self.token_spacing); + let (dyn_tok, dyn_tok_sp) = (self.token, self.token_spacing); self.bump(); self.bump_with((dyn_tok, dyn_tok_sp)); } @@ -886,7 +937,7 @@ impl<'a> Parser<'a> { /// ``` fn parse_generic_bound(&mut self) -> PResult<'a, GenericBound> { let lo = self.token.span; - let leading_token = self.prev_token.clone(); + let leading_token = self.prev_token; let has_parens = self.eat(exp!(OpenParen)); let bound = if self.token.is_lifetime() { diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs index 6bbd650dcdfe..b518fca7a658 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_parse/src/validate_attr.rs @@ -157,7 +157,7 @@ fn is_attr_template_compatible(template: &AttributeTemplate, meta: &ast::MetaIte pub fn check_attribute_safety(psess: &ParseSess, safety: AttributeSafety, attr: &Attribute) { let attr_item = attr.get_normal_item(); - if safety == AttributeSafety::Unsafe { + if let AttributeSafety::Unsafe { unsafe_since } = safety { if let ast::Safety::Default = attr_item.unsafety { let path_span = attr_item.path.span; @@ -167,7 +167,13 @@ pub fn check_attribute_safety(psess: &ParseSess, safety: AttributeSafety, attr: // square bracket respectively. let diag_span = attr_item.span(); - if attr.span.at_least_rust_2024() { + // Attributes can be safe in earlier editions, and become unsafe in later ones. + let emit_error = match unsafe_since { + None => true, + Some(unsafe_since) => attr.span.edition() >= unsafe_since, + }; + + if emit_error { psess.dcx().emit_err(errors::UnsafeAttrOutsideUnsafe { span: path_span, suggestion: errors::UnsafeAttrOutsideUnsafeSuggestion { @@ -188,6 +194,12 @@ pub fn check_attribute_safety(psess: &ParseSess, safety: AttributeSafety, attr: } } } else if let Safety::Unsafe(unsafe_span) = attr_item.unsafety { + // Allow (but don't require) `#[unsafe(naked)]` so that compiler-builtins can upgrade to it. + // FIXME(#139797): remove this special case when compiler-builtins has upgraded. + if attr.has_name(sym::naked) { + return; + } + psess.dcx().emit_err(errors::InvalidAttrUnsafe { span: unsafe_span, name: attr_item.path.clone(), diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index bea86801ed75..99789b74488c 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -404,7 +404,7 @@ passes_invalid_attr_at_crate_level = passes_invalid_attr_at_crate_level_item = the inner attribute doesn't annotate this {$kind} -passes_invalid_macro_export_arguments = `{$name}` isn't a valid `#[macro_export]` argument +passes_invalid_macro_export_arguments = invalid `#[macro_export]` argument passes_invalid_macro_export_arguments_too_many_items = `#[macro_export]` can only take 1 or 0 arguments @@ -742,9 +742,6 @@ passes_trait_impl_const_stable = passes_transparent_incompatible = transparent {$target} cannot have other repr hints -passes_undefined_naked_function_abi = - Rust ABI is unsupported in naked functions - passes_unknown_external_lang_item = unknown external lang item: `{$lang_item}` @@ -774,8 +771,8 @@ passes_unreachable_due_to_uninhabited = unreachable {$descr} .label_orig = any code following this expression is unreachable .note = this expression has type `{$ty}`, which is uninhabited -passes_unrecognized_field = - unrecognized field name `{$name}` +passes_unrecognized_argument = + unrecognized argument passes_unstable_attr_for_already_stable_feature = can't mark as unstable using an already stable feature diff --git a/compiler/rustc_passes/src/abi_test.rs b/compiler/rustc_passes/src/abi_test.rs index 671b7d7ad76c..b139ed6a66c3 100644 --- a/compiler/rustc_passes/src/abi_test.rs +++ b/compiler/rustc_passes/src/abi_test.rs @@ -9,7 +9,7 @@ use rustc_span::sym; use rustc_target::callconv::FnAbi; use super::layout_test::ensure_wf; -use crate::errors::{AbiInvalidAttribute, AbiNe, AbiOf, UnrecognizedField}; +use crate::errors::{AbiInvalidAttribute, AbiNe, AbiOf, UnrecognizedArgument}; pub fn test_abi(tcx: TyCtxt<'_>) { if !tcx.features().rustc_attrs() { @@ -77,8 +77,8 @@ fn dump_abi_of_fn_item(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribut // The `..` are the names of fields to dump. let meta_items = attr.meta_item_list().unwrap_or_default(); for meta_item in meta_items { - match meta_item.name_or_empty() { - sym::debug => { + match meta_item.name() { + Some(sym::debug) => { let fn_name = tcx.item_name(item_def_id.into()); tcx.dcx().emit_err(AbiOf { span: tcx.def_span(item_def_id), @@ -88,8 +88,8 @@ fn dump_abi_of_fn_item(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribut }); } - name => { - tcx.dcx().emit_err(UnrecognizedField { span: meta_item.span(), name }); + _ => { + tcx.dcx().emit_err(UnrecognizedArgument { span: meta_item.span() }); } } } @@ -118,8 +118,8 @@ fn dump_abi_of_fn_type(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribut } let meta_items = attr.meta_item_list().unwrap_or_default(); for meta_item in meta_items { - match meta_item.name_or_empty() { - sym::debug => { + match meta_item.name() { + Some(sym::debug) => { let ty::FnPtr(sig_tys, hdr) = ty.kind() else { span_bug!( meta_item.span(), @@ -138,7 +138,7 @@ fn dump_abi_of_fn_type(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribut let fn_name = tcx.item_name(item_def_id.into()); tcx.dcx().emit_err(AbiOf { span, fn_name, fn_abi: format!("{:#?}", abi) }); } - sym::assert_eq => { + Some(sym::assert_eq) => { let ty::Tuple(fields) = ty.kind() else { span_bug!( meta_item.span(), @@ -188,8 +188,8 @@ fn dump_abi_of_fn_type(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribut }); } } - name => { - tcx.dcx().emit_err(UnrecognizedField { span: meta_item.span(), name }); + _ => { + tcx.dcx().emit_err(UnrecognizedArgument { span: meta_item.span() }); } } } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 669349f3380a..cbe5058b5519 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -523,9 +523,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> { fn check_no_sanitize(&self, attr: &Attribute, span: Span, target: Target) { if let Some(list) = attr.meta_item_list() { for item in list.iter() { - let sym = item.name_or_empty(); + let sym = item.name(); match sym { - sym::address | sym::hwaddress => { + Some(s @ sym::address | s @ sym::hwaddress) => { let is_valid = matches!(target, Target::Fn | Target::Method(..) | Target::Static); if !is_valid { @@ -533,7 +533,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { attr_span: item.span(), defn_span: span, accepted_kind: "a function or static", - attr_str: sym.as_str(), + attr_str: s.as_str(), }); } } @@ -544,7 +544,10 @@ impl<'tcx> CheckAttrVisitor<'tcx> { attr_span: item.span(), defn_span: span, accepted_kind: "a function", - attr_str: sym.as_str(), + attr_str: &match sym { + Some(name) => name.to_string(), + None => "...".to_string(), + }, }); } } @@ -561,12 +564,15 @@ impl<'tcx> CheckAttrVisitor<'tcx> { allowed_target: Target, ) { if target != allowed_target { + let path = attr.path(); + let path: Vec<_> = path.iter().map(|s| s.as_str()).collect(); + let attr_name = path.join("::"); self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, attr.span(), errors::OnlyHasEffectOn { - attr_name: attr.name_or_empty(), + attr_name, target_name: allowed_target.name().replace(' ', "_"), }, ); @@ -589,7 +595,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> { // * `#[track_caller]` // * `#[test]`, `#[ignore]`, `#[should_panic]` // - // NOTE: when making changes to this list, check that `error_codes/E0736.md` remains accurate + // NOTE: when making changes to this list, check that `error_codes/E0736.md` remains + // accurate. const ALLOW_LIST: &[rustc_span::Symbol] = &[ // conditional compilation sym::cfg_trace, @@ -624,6 +631,21 @@ impl<'tcx> CheckAttrVisitor<'tcx> { match target { Target::Fn | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => { + let fn_sig = self.tcx.hir_node(hir_id).fn_sig().unwrap(); + let abi = fn_sig.header.abi; + if abi.is_rustic_abi() && !self.tcx.features().naked_functions_rustic_abi() { + feature_err( + &self.tcx.sess, + sym::naked_functions_rustic_abi, + fn_sig.span, + format!( + "`#[naked]` is currently unstable on `extern \"{}\"` functions", + abi.as_str() + ), + ) + .emit(); + } + for other_attr in attrs { // this covers "sugared doc comments" of the form `/// ...` // it does not cover `#[doc = "..."]`, which is handled below @@ -657,11 +679,11 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - if !ALLOW_LIST.iter().any(|name| other_attr.has_name(*name)) { + if !other_attr.has_any_name(ALLOW_LIST) { self.dcx().emit_err(errors::NakedFunctionIncompatibleAttribute { span: other_attr.span(), naked_span: attr.span(), - attr: other_attr.name_or_empty(), + attr: other_attr.name().unwrap(), }); return; @@ -1109,6 +1131,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { ItemKind::Trait(_, _, _, generics, _, items) if generics.params.len() != 0 || items.iter().any(|item| matches!(item.kind, AssocItemKind::Type)) => {} + ItemKind::TyAlias(_, _, generics) if generics.params.len() != 0 => {} _ => { self.dcx().emit_err(errors::DocSearchUnboxInvalid { span: meta.span() }); } @@ -1134,7 +1157,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { ) { match target { Target::Use | Target::ExternCrate => { - let do_inline = meta.name_or_empty() == sym::inline; + let do_inline = meta.has_name(sym::inline); 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()]); @@ -1244,8 +1267,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> { fn check_test_attr(&self, meta: &MetaItemInner, hir_id: HirId) { if let Some(metas) = meta.meta_item_list() { for i_meta in metas { - match (i_meta.name_or_empty(), i_meta.meta_item()) { - (sym::attr | sym::no_crate_inject, _) => {} + match (i_meta.name(), i_meta.meta_item()) { + (Some(sym::attr | sym::no_crate_inject), _) => {} (_, Some(m)) => { self.tcx.emit_node_span_lint( INVALID_DOC_ATTRIBUTES, @@ -1306,61 +1329,63 @@ impl<'tcx> CheckAttrVisitor<'tcx> { if let Some(list) = attr.meta_item_list() { for meta in &list { if let Some(i_meta) = meta.meta_item() { - match i_meta.name_or_empty() { - sym::alias => { + match i_meta.name() { + Some(sym::alias) => { if self.check_attr_not_crate_level(meta, hir_id, "alias") { self.check_doc_alias(meta, hir_id, target, aliases); } } - sym::keyword => { + Some(sym::keyword) => { if self.check_attr_not_crate_level(meta, hir_id, "keyword") { self.check_doc_keyword(meta, hir_id); } } - sym::fake_variadic => { + Some(sym::fake_variadic) => { if self.check_attr_not_crate_level(meta, hir_id, "fake_variadic") { self.check_doc_fake_variadic(meta, hir_id); } } - sym::search_unbox => { + Some(sym::search_unbox) => { if self.check_attr_not_crate_level(meta, hir_id, "fake_variadic") { self.check_doc_search_unbox(meta, hir_id); } } - sym::test => { + Some(sym::test) => { if self.check_attr_crate_level(attr, meta, hir_id) { self.check_test_attr(meta, hir_id); } } - sym::html_favicon_url - | sym::html_logo_url - | sym::html_playground_url - | sym::issue_tracker_base_url - | sym::html_root_url - | sym::html_no_source => { + Some( + sym::html_favicon_url + | sym::html_logo_url + | sym::html_playground_url + | sym::issue_tracker_base_url + | sym::html_root_url + | sym::html_no_source, + ) => { self.check_attr_crate_level(attr, meta, hir_id); } - sym::cfg_hide => { + Some(sym::cfg_hide) => { if self.check_attr_crate_level(attr, meta, hir_id) { self.check_doc_cfg_hide(meta, hir_id); } } - sym::inline | sym::no_inline => { + Some(sym::inline | sym::no_inline) => { self.check_doc_inline(attr, meta, hir_id, target, specified_inline) } - sym::masked => self.check_doc_masked(attr, meta, hir_id, target), + Some(sym::masked) => self.check_doc_masked(attr, meta, hir_id, target), - sym::cfg | sym::hidden | sym::notable_trait => {} + Some(sym::cfg | sym::hidden | sym::notable_trait) => {} - sym::rust_logo => { + Some(sym::rust_logo) => { if self.check_attr_crate_level(attr, meta, hir_id) && !self.tcx.features().rustdoc_internals() { @@ -1598,7 +1623,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { if target == Target::ForeignMod && let hir::Node::Item(item) = self.tcx.hir_node(hir_id) && let Item { kind: ItemKind::ForeignMod { abi, .. }, .. } = item - && !matches!(abi, ExternAbi::Rust | ExternAbi::RustIntrinsic) + && !matches!(abi, ExternAbi::Rust) { return; } @@ -2283,7 +2308,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } fn check_macro_use(&self, hir_id: HirId, attr: &Attribute, target: Target) { - let name = attr.name_or_empty(); + let name = attr.name().unwrap(); match target { Target::ExternCrate | Target::Mod => {} _ => { @@ -2315,12 +2340,12 @@ impl<'tcx> CheckAttrVisitor<'tcx> { attr.span(), errors::MacroExport::TooManyItems, ); - } else if meta_item_list[0].name_or_empty() != sym::local_inner_macros { + } else if !meta_item_list[0].has_name(sym::local_inner_macros) { self.tcx.emit_node_span_lint( INVALID_MACRO_EXPORT_ARGUMENTS, hir_id, meta_item_list[0].span(), - errors::MacroExport::UnknownItem { name: meta_item_list[0].name_or_empty() }, + errors::MacroExport::InvalidArgument, ); } } else { @@ -2365,33 +2390,28 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } // Warn on useless empty attributes. - let note = if (matches!( - attr.name_or_empty(), - sym::macro_use - | sym::allow - | sym::expect - | sym::warn - | sym::deny - | sym::forbid - | sym::feature - | sym::target_feature - ) && attr.meta_item_list().is_some_and(|list| list.is_empty())) + let note = if attr.has_any_name(&[ + sym::macro_use, + sym::allow, + sym::expect, + sym::warn, + sym::deny, + sym::forbid, + sym::feature, + sym::target_feature, + ]) && attr.meta_item_list().is_some_and(|list| list.is_empty()) { - errors::UnusedNote::EmptyList { name: attr.name_or_empty() } - } else if matches!( - attr.name_or_empty(), - sym::allow | sym::warn | sym::deny | sym::forbid | sym::expect - ) && let Some(meta) = attr.meta_item_list() + errors::UnusedNote::EmptyList { name: attr.name().unwrap() } + } else if attr.has_any_name(&[sym::allow, sym::warn, sym::deny, sym::forbid, sym::expect]) + && let Some(meta) = attr.meta_item_list() && let [meta] = meta.as_slice() && let Some(item) = meta.meta_item() && let MetaItemKind::NameValue(_) = &item.kind && item.path == sym::reason { - errors::UnusedNote::NoLints { name: attr.name_or_empty() } - } else if matches!( - attr.name_or_empty(), - sym::allow | sym::warn | sym::deny | sym::forbid | sym::expect - ) && let Some(meta) = attr.meta_item_list() + errors::UnusedNote::NoLints { name: attr.name().unwrap() } + } else if attr.has_any_name(&[sym::allow, sym::warn, sym::deny, sym::forbid, sym::expect]) + && let Some(meta) = attr.meta_item_list() && meta.iter().any(|meta| { meta.meta_item().map_or(false, |item| item.path == sym::linker_messages) }) @@ -2424,7 +2444,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { return; } } - } else if attr.name_or_empty() == sym::default_method_body_is_const { + } else if attr.has_name(sym::default_method_body_is_const) { errors::UnusedNote::DefaultMethodBodyConst } else { return; @@ -2881,10 +2901,11 @@ fn check_duplicates( if matches!(duplicates, WarnFollowingWordOnly) && !attr.is_word() { return; } + let attr_name = attr.name().unwrap(); match duplicates { DuplicatesOk => {} WarnFollowing | FutureWarnFollowing | WarnFollowingWordOnly | FutureWarnPreceding => { - match seen.entry(attr.name_or_empty()) { + match seen.entry(attr_name) { Entry::Occupied(mut entry) => { let (this, other) = if matches!(duplicates, FutureWarnPreceding) { let to_remove = entry.insert(attr.span()); @@ -2911,7 +2932,7 @@ fn check_duplicates( } } } - ErrorFollowing | ErrorPreceding => match seen.entry(attr.name_or_empty()) { + ErrorFollowing | ErrorPreceding => match seen.entry(attr_name) { Entry::Occupied(mut entry) => { let (this, other) = if matches!(duplicates, ErrorPreceding) { let to_remove = entry.insert(attr.span()); @@ -2919,11 +2940,7 @@ fn check_duplicates( } else { (attr.span(), *entry.get()) }; - tcx.dcx().emit_err(errors::UnusedMultiple { - this, - other, - name: attr.name_or_empty(), - }); + tcx.dcx().emit_err(errors::UnusedMultiple { this, other, name: attr_name }); } Entry::Vacant(entry) => { entry.insert(attr.span()); diff --git a/compiler/rustc_passes/src/debugger_visualizer.rs b/compiler/rustc_passes/src/debugger_visualizer.rs index 062d56a79a0b..7a7a8175e556 100644 --- a/compiler/rustc_passes/src/debugger_visualizer.rs +++ b/compiler/rustc_passes/src/debugger_visualizer.rs @@ -28,17 +28,17 @@ impl DebuggerVisualizerCollector<'_> { return; }; - let (visualizer_type, visualizer_path) = - match (meta_item.name_or_empty(), meta_item.value_str()) { - (sym::natvis_file, Some(value)) => (DebuggerVisualizerType::Natvis, value), - (sym::gdb_script_file, Some(value)) => { - (DebuggerVisualizerType::GdbPrettyPrinter, value) - } - (_, _) => { - self.sess.dcx().emit_err(DebugVisualizerInvalid { span: meta_item.span }); - return; - } - }; + let (visualizer_type, visualizer_path) = match (meta_item.name(), meta_item.value_str()) + { + (Some(sym::natvis_file), Some(value)) => (DebuggerVisualizerType::Natvis, value), + (Some(sym::gdb_script_file), Some(value)) => { + (DebuggerVisualizerType::GdbPrettyPrinter, value) + } + (_, _) => { + self.sess.dcx().emit_err(DebugVisualizerInvalid { span: meta_item.span }); + return; + } + }; let file = match resolve_path(&self.sess, visualizer_path.as_str(), attr.span) { Ok(file) => file, diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 4e3e0324205a..4052264b0517 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -5,7 +5,7 @@ use rustc_ast::Label; use rustc_errors::codes::*; use rustc_errors::{ Applicability, Diag, DiagCtxtHandle, DiagSymbolList, Diagnostic, EmissionGuarantee, Level, - MultiSpan, SubdiagMessageOp, Subdiagnostic, + MultiSpan, Subdiagnostic, }; use rustc_hir::{self as hir, ExprKind, Target}; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; @@ -756,7 +756,7 @@ pub(crate) enum MacroExport { OnDeclMacro, #[diag(passes_invalid_macro_export_arguments)] - UnknownItem { name: Symbol }, + InvalidArgument, #[diag(passes_invalid_macro_export_arguments_too_many_items)] TooManyItems, @@ -1045,11 +1045,10 @@ pub(crate) struct AbiInvalidAttribute { } #[derive(Diagnostic)] -#[diag(passes_unrecognized_field)] -pub(crate) struct UnrecognizedField { +#[diag(passes_unrecognized_argument)] +pub(crate) struct UnrecognizedArgument { #[primary_span] pub span: Span, - pub name: Symbol, } #[derive(Diagnostic)] @@ -1197,10 +1196,6 @@ pub(crate) struct UnlabeledCfInWhileCondition<'a> { pub cf_type: &'a str, } -#[derive(LintDiagnostic)] -#[diag(passes_undefined_naked_function_abi)] -pub(crate) struct UndefinedNakedFunctionAbi; - #[derive(Diagnostic)] #[diag(passes_no_patterns)] pub(crate) struct NoPatterns { @@ -1437,7 +1432,7 @@ pub(crate) struct UselessAssignment<'a> { #[derive(LintDiagnostic)] #[diag(passes_only_has_effect_on)] pub(crate) struct OnlyHasEffectOn { - pub attr_name: Symbol, + pub attr_name: String, pub target_name: String, } @@ -1856,11 +1851,7 @@ pub(crate) struct UnusedVariableStringInterp { } impl Subdiagnostic for UnusedVariableStringInterp { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { diag.span_label(self.lit, crate::fluent_generated::passes_maybe_string_interpolation); diag.multipart_suggestion( crate::fluent_generated::passes_string_interpolation_only_works, diff --git a/compiler/rustc_passes/src/input_stats.rs b/compiler/rustc_passes/src/input_stats.rs index 1278e98afcf6..718154481722 100644 --- a/compiler/rustc_passes/src/input_stats.rs +++ b/compiler/rustc_passes/src/input_stats.rs @@ -295,6 +295,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { record_variants!( (self, p, p.kind, Some(p.hir_id), hir, Pat, PatKind), [ + Missing, Wild, Binding, Struct, @@ -597,6 +598,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> { record_variants!( (self, p, p.kind, None, ast, Pat, PatKind), [ + Missing, Wild, Ident, Struct, diff --git a/compiler/rustc_passes/src/layout_test.rs b/compiler/rustc_passes/src/layout_test.rs index d4512c9417eb..a19faf0fa836 100644 --- a/compiler/rustc_passes/src/layout_test.rs +++ b/compiler/rustc_passes/src/layout_test.rs @@ -13,7 +13,7 @@ use rustc_trait_selection::traits; use crate::errors::{ LayoutAbi, LayoutAlign, LayoutHomogeneousAggregate, LayoutInvalidAttribute, LayoutOf, - LayoutSize, UnrecognizedField, + LayoutSize, UnrecognizedArgument, }; pub fn test_layout(tcx: TyCtxt<'_>) { @@ -79,28 +79,28 @@ fn dump_layout_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribute) { // The `..` are the names of fields to dump. let meta_items = attr.meta_item_list().unwrap_or_default(); for meta_item in meta_items { - match meta_item.name_or_empty() { + match meta_item.name() { // FIXME: this never was about ABI and now this dump arg is confusing - sym::abi => { + Some(sym::abi) => { tcx.dcx().emit_err(LayoutAbi { span, abi: format!("{:?}", ty_layout.backend_repr), }); } - sym::align => { + Some(sym::align) => { tcx.dcx().emit_err(LayoutAlign { span, align: format!("{:?}", ty_layout.align), }); } - sym::size => { + Some(sym::size) => { tcx.dcx() .emit_err(LayoutSize { span, size: format!("{:?}", ty_layout.size) }); } - sym::homogeneous_aggregate => { + Some(sym::homogeneous_aggregate) => { tcx.dcx().emit_err(LayoutHomogeneousAggregate { span, homogeneous_aggregate: format!( @@ -111,15 +111,15 @@ fn dump_layout_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribute) { }); } - sym::debug => { + Some(sym::debug) => { let normalized_ty = tcx.normalize_erasing_regions(typing_env, ty); // FIXME: using the `Debug` impl here isn't ideal. let ty_layout = format!("{:#?}", *ty_layout); tcx.dcx().emit_err(LayoutOf { span, normalized_ty, ty_layout }); } - name => { - tcx.dcx().emit_err(UnrecognizedField { span: meta_item.span(), name }); + _ => { + tcx.dcx().emit_err(UnrecognizedArgument { span: meta_item.span() }); } } } diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs index 6f6115af96c8..93ff0f66d695 100644 --- a/compiler/rustc_passes/src/lib.rs +++ b/compiler/rustc_passes/src/lib.rs @@ -6,7 +6,6 @@ // tidy-alphabetical-start #![allow(internal_features)] -#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(let_chains)] diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index ed70d9ee91f5..4e9b7fd44d4b 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -96,7 +96,7 @@ use rustc_middle::query::Providers; use rustc_middle::span_bug; use rustc_middle::ty::{self, RootVariableMinCaptureList, Ty, TyCtxt}; use rustc_session::lint; -use rustc_span::{BytePos, Span, Symbol, kw, sym}; +use rustc_span::{BytePos, Span, Symbol, sym}; use tracing::{debug, instrument}; use self::LiveNodeKind::*; @@ -578,8 +578,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { where F: FnMut(Variable) -> bool, { - for var_idx in 0..self.ir.var_kinds.len() { - let var = Variable::from(var_idx); + for var in self.ir.var_kinds.indices() { if test(var) { write!(wr, " {var:?}")?; } @@ -609,8 +608,8 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { debug!( "^^ liveness computation results for body {} (entry={:?})", { - for ln_idx in 0..self.ir.lnks.len() { - debug!("{:?}", self.ln_str(LiveNode::from(ln_idx))); + for ln_idx in self.ir.lnks.indices() { + debug!("{:?}", self.ln_str(ln_idx)); } hir_id }, @@ -1021,7 +1020,10 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { } hir::ExprKind::Call(ref f, args) => { - let succ = self.check_is_ty_uninhabited(expr, succ); + let is_ctor = |f: &Expr<'_>| matches!(f.kind, hir::ExprKind::Path(hir::QPath::Resolved(_, path)) if matches!(path.res, rustc_hir::def::Res::Def(rustc_hir::def::DefKind::Ctor(_, _), _))); + let succ = + if !is_ctor(f) { self.check_is_ty_uninhabited(expr, succ) } else { succ }; + let succ = self.propagate_through_exprs(args, succ); self.propagate_through_expr(f, succ) } @@ -1481,9 +1483,6 @@ impl<'tcx> Liveness<'_, 'tcx> { fn should_warn(&self, var: Variable) -> Option { let name = self.ir.variable_name(var); - if name == kw::Empty { - return None; - } let name = name.as_str(); if name.as_bytes()[0] == b'_' { return None; @@ -1655,7 +1654,7 @@ impl<'tcx> Liveness<'_, 'tcx> { // `&'name Ty` -> `&'name mut Ty` or `&Ty` -> `&mut Ty` Some(mut_ty.ty.span.shrink_to_lo()) }; - let pre = if lt.ident.span.lo() == lt.ident.span.hi() { "" } else { " " }; + let pre = if lt.ident.span.is_empty() { "" } else { " " }; Some(errors::UnusedAssignSuggestion { ty_span, pre, diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_passes/src/naked_functions.rs index d35aedf9a564..3c9f8b72c363 100644 --- a/compiler/rustc_passes/src/naked_functions.rs +++ b/compiler/rustc_passes/src/naked_functions.rs @@ -1,6 +1,5 @@ //! Checks validity of naked functions. -use rustc_abi::ExternAbi; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{LocalDefId, LocalModDefId}; @@ -10,12 +9,11 @@ use rustc_middle::hir::nested_filter::OnlyBodies; use rustc_middle::query::Providers; use rustc_middle::span_bug; use rustc_middle::ty::TyCtxt; -use rustc_session::lint::builtin::UNDEFINED_NAKED_FUNCTION_ABI; use rustc_span::{Span, sym}; use crate::errors::{ NakedAsmOutsideNakedFn, NakedFunctionsAsmBlock, NakedFunctionsMustNakedAsm, NoPatterns, - ParamsNotAllowed, UndefinedNakedFunctionAbi, + ParamsNotAllowed, }; pub(crate) fn provide(providers: &mut Providers) { @@ -29,26 +27,21 @@ fn check_mod_naked_functions(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) { continue; } - let (fn_header, body_id) = match tcx.hir_node_by_def_id(def_id) { + let body = match tcx.hir_node_by_def_id(def_id) { hir::Node::Item(hir::Item { - kind: hir::ItemKind::Fn { sig, body: body_id, .. }, - .. + kind: hir::ItemKind::Fn { body: body_id, .. }, .. }) | hir::Node::TraitItem(hir::TraitItem { - kind: hir::TraitItemKind::Fn(sig, hir::TraitFn::Provided(body_id)), + kind: hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(body_id)), .. }) | hir::Node::ImplItem(hir::ImplItem { - kind: hir::ImplItemKind::Fn(sig, body_id), - .. - }) => (sig.header, *body_id), + kind: hir::ImplItemKind::Fn(_, body_id), .. + }) => tcx.hir_body(*body_id), _ => continue, }; - let body = tcx.hir_body(body_id); - if tcx.has_attr(def_id, sym::naked) { - check_abi(tcx, def_id, fn_header.abi); check_no_patterns(tcx, body.params); check_no_parameters_use(tcx, body); check_asm(tcx, def_id, body); @@ -60,20 +53,6 @@ fn check_mod_naked_functions(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) { } } -/// Checks that function uses non-Rust ABI. -fn check_abi(tcx: TyCtxt<'_>, def_id: LocalDefId, abi: ExternAbi) { - if abi == ExternAbi::Rust { - let hir_id = tcx.local_def_id_to_hir_id(def_id); - let span = tcx.def_span(def_id); - tcx.emit_node_span_lint( - UNDEFINED_NAKED_FUNCTION_ABI, - hir_id, - span, - UndefinedNakedFunctionAbi, - ); - } -} - /// Checks that parameters don't use patterns. Mirrors the checks for function declarations. fn check_no_patterns(tcx: TyCtxt<'_>, params: &[hir::Param<'_>]) { for param in params { diff --git a/compiler/rustc_pattern_analysis/src/errors.rs b/compiler/rustc_pattern_analysis/src/errors.rs index 1f7852e5190d..e60930d6cd21 100644 --- a/compiler/rustc_pattern_analysis/src/errors.rs +++ b/compiler/rustc_pattern_analysis/src/errors.rs @@ -1,4 +1,4 @@ -use rustc_errors::{Diag, EmissionGuarantee, SubdiagMessageOp, Subdiagnostic}; +use rustc_errors::{Diag, EmissionGuarantee, Subdiagnostic}; use rustc_macros::{LintDiagnostic, Subdiagnostic}; use rustc_middle::ty::Ty; use rustc_span::Span; @@ -55,11 +55,7 @@ pub struct Overlap { } impl Subdiagnostic for Overlap { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { let Overlap { span, range } = self; // FIXME(mejrs) unfortunately `#[derive(LintDiagnostic)]` @@ -103,11 +99,7 @@ pub struct GappedRange { } impl Subdiagnostic for GappedRange { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { let GappedRange { span, gap, first_range } = self; // FIXME(mejrs) unfortunately `#[derive(LintDiagnostic)]` diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index 31c4ee0fa0bb..7c12f69f14c1 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -1,5 +1,6 @@ use std::fmt; use std::iter::once; +use std::ops::ControlFlow; use rustc_abi::{FIRST_VARIANT, FieldIdx, Integer, VariantIdx}; use rustc_arena::DroplessArena; @@ -11,7 +12,8 @@ use rustc_middle::mir::{self, Const}; use rustc_middle::thir::{self, Pat, PatKind, PatRange, PatRangeBoundary}; use rustc_middle::ty::layout::IntegerExt; use rustc_middle::ty::{ - self, FieldDef, OpaqueTypeKey, ScalarInt, Ty, TyCtxt, TypeVisitableExt, VariantDef, + self, FieldDef, OpaqueTypeKey, ScalarInt, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, + TypeVisitableExt, TypeVisitor, VariantDef, }; use rustc_middle::{bug, span_bug}; use rustc_session::lint; @@ -135,11 +137,22 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { /// Returns the hidden type corresponding to this key if the body under analysis is allowed to /// know it. fn reveal_opaque_key(&self, key: OpaqueTypeKey<'tcx>) -> Option> { - self.typeck_results - .concrete_opaque_types - .get(&key.def_id) - .map(|x| ty::EarlyBinder::bind(x.ty).instantiate(self.tcx, key.args)) + if let Some(hidden_ty) = self.typeck_results.concrete_opaque_types.get(&key.def_id) { + let ty = ty::EarlyBinder::bind(hidden_ty.ty).instantiate(self.tcx, key.args); + if ty.visit_with(&mut RecursiveOpaque { def_id: key.def_id.into() }).is_continue() { + Some(ty) + } else { + // HACK: We skip revealing opaque types which recursively expand + // to themselves. This is because we may infer hidden types like + // `Opaque = Opaque>` or `Opaque = Opaque<(T,)>` + // in hir typeck. + None + } + } else { + None + } } + // This can take a non-revealed `Ty` because it reveals opaques itself. pub fn is_uninhabited(&self, ty: Ty<'tcx>) -> bool { !ty.inhabited_predicate(self.tcx).apply_revealing_opaque( @@ -460,7 +473,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { PatKind::AscribeUserType { subpattern, .. } | PatKind::ExpandedConstant { subpattern, .. } => return self.lower_pat(subpattern), PatKind::Binding { subpattern: Some(subpat), .. } => return self.lower_pat(subpat), - PatKind::Binding { subpattern: None, .. } | PatKind::Wild => { + PatKind::Missing | PatKind::Binding { subpattern: None, .. } | PatKind::Wild => { ctor = Wildcard; fields = vec![]; arity = 0; @@ -1105,3 +1118,20 @@ pub fn analyze_match<'p, 'tcx>( Ok(report) } + +struct RecursiveOpaque { + def_id: DefId, +} +impl<'tcx> TypeVisitor> for RecursiveOpaque { + type Result = ControlFlow<()>; + + fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result { + if let ty::Alias(ty::Opaque, alias_ty) = t.kind() { + if alias_ty.def_id == self.def_id { + return ControlFlow::Break(()); + } + } + + if t.has_opaque_types() { t.super_visit_with(self) } else { ControlFlow::Continue(()) } + } +} diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 643b82f47530..c7bab828659a 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -1,6 +1,5 @@ // tidy-alphabetical-start #![allow(internal_features)] -#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(associated_type_defaults)] diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs index 30a9e718d236..3c329dd0a0e8 100644 --- a/compiler/rustc_query_impl/src/lib.rs +++ b/compiler/rustc_query_impl/src/lib.rs @@ -3,7 +3,6 @@ // tidy-alphabetical-start #![allow(internal_features)] #![allow(unused_parens)] -#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(min_specialization)] diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index 9f34417973ed..0d56db160996 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -141,7 +141,7 @@ impl DepGraph { let colors = DepNodeColorMap::new(prev_graph_node_count); // Instantiate a node with zero dependencies only once for anonymous queries. - let _green_node_index = current.alloc_node( + let _green_node_index = current.alloc_new_node( DepNode { kind: D::DEP_KIND_ANON_ZERO_DEPS, hash: current.anon_id_seed.into() }, EdgesVec::new(), Fingerprint::ZERO, @@ -149,7 +149,7 @@ impl DepGraph { assert_eq!(_green_node_index, DepNodeIndex::SINGLETON_ZERO_DEPS_ANON_NODE); // Instantiate a dependy-less red node only once for anonymous queries. - let red_node_index = current.alloc_node( + let red_node_index = current.alloc_new_node( DepNode { kind: D::DEP_KIND_RED, hash: Fingerprint::ZERO.into() }, EdgesVec::new(), Fingerprint::ZERO, @@ -438,7 +438,7 @@ impl DepGraphData { // memory impact of this `anon_node_to_index` map remains tolerable, and helps // us avoid useless growth of the graph with almost-equivalent nodes. self.current.anon_node_to_index.get_or_insert_with(target_dep_node, || { - self.current.alloc_node(target_dep_node, task_deps, Fingerprint::ZERO) + self.current.alloc_new_node(target_dep_node, task_deps, Fingerprint::ZERO) }) } }; @@ -680,8 +680,8 @@ impl DepGraphData { qcx: Qcx, diagnostic: &DiagInner, ) -> DepNodeIndex { - // Use `send` so we get an unique index, even though the dep node is not. - let dep_node_index = self.current.encoder.send( + // Use `send_new` so we get an unique index, even though the dep node is not. + let dep_node_index = self.current.encoder.send_new( DepNode { kind: D::DEP_KIND_SIDE_EFFECT, hash: PackedFingerprint::from(Fingerprint::ZERO), @@ -713,20 +713,22 @@ impl DepGraphData { } } - // Manually recreate the node as `promote_node_and_deps_to_current` expects all - // green dependencies. - let dep_node_index = self.current.encoder.send( + // Use `send_and_color` as `promote_node_and_deps_to_current` expects all + // green dependencies. `send_and_color` will also prevent multiple nodes + // being encoded for concurrent calls. + let dep_node_index = self.current.encoder.send_and_color( + prev_index, + &self.colors, DepNode { kind: D::DEP_KIND_SIDE_EFFECT, hash: PackedFingerprint::from(Fingerprint::ZERO), }, Fingerprint::ZERO, std::iter::once(DepNodeIndex::FOREVER_RED_NODE).collect(), + true, ); + // This will just overwrite the same value for concurrent calls. qcx.store_side_effect(dep_node_index, side_effect); - - // Mark the node as green. - self.colors.insert(prev_index, DepNodeColor::Green(dep_node_index)); }) } @@ -736,38 +738,43 @@ impl DepGraphData { edges: EdgesVec, fingerprint: Option, ) -> DepNodeIndex { - let dep_node_index = - self.current.alloc_node(key, edges, fingerprint.unwrap_or(Fingerprint::ZERO)); - if let Some(prev_index) = self.previous.node_to_index_opt(&key) { // Determine the color and index of the new `DepNode`. - let color = if let Some(fingerprint) = fingerprint { + let is_green = if let Some(fingerprint) = fingerprint { if fingerprint == self.previous.fingerprint_by_index(prev_index) { // This is a green node: it existed in the previous compilation, // its query was re-executed, and it has the same result as before. - DepNodeColor::Green(dep_node_index) + true } else { // This is a red node: it existed in the previous compilation, its query // was re-executed, but it has a different result from before. - DepNodeColor::Red + false } } else { // This is a red node, effectively: it existed in the previous compilation // session, its query was re-executed, but it doesn't compute a result hash // (i.e. it represents a `no_hash` query), so we have no way of determining // whether or not the result was the same as before. - DepNodeColor::Red + false }; - debug_assert!( - self.colors.get(prev_index).is_none(), - "DepGraph::with_task() - Duplicate DepNodeColor insertion for {key:?}", + let fingerprint = fingerprint.unwrap_or(Fingerprint::ZERO); + + let dep_node_index = self.current.encoder.send_and_color( + prev_index, + &self.colors, + key, + fingerprint, + edges, + is_green, ); - self.colors.insert(prev_index, color); - } + self.current.record_node(dep_node_index, key, fingerprint); - dep_node_index + dep_node_index + } else { + self.current.alloc_new_node(key, edges, fingerprint.unwrap_or(Fingerprint::ZERO)) + } } fn promote_node_and_deps_to_current(&self, prev_index: SerializedDepNodeIndex) -> DepNodeIndex { @@ -1167,8 +1174,7 @@ pub(super) struct CurrentDepGraph { /// ID from the previous session. In order to side-step this problem, we make /// sure that anonymous `NodeId`s allocated in different sessions don't overlap. /// This is implemented by mixing a session-key into the ID fingerprint of - /// each anon node. The session-key is just a random number generated when - /// the `DepGraph` is created. + /// each anon node. The session-key is a hash of the number of previous sessions. anon_id_seed: Fingerprint, /// These are simple counters that are for profiling and @@ -1186,12 +1192,8 @@ impl CurrentDepGraph { record_stats: bool, previous: Arc, ) -> Self { - use std::time::{SystemTime, UNIX_EPOCH}; - - let duration = SystemTime::now().duration_since(UNIX_EPOCH).unwrap(); - let nanos = duration.as_nanos(); let mut stable_hasher = StableHasher::new(); - nanos.hash(&mut stable_hasher); + previous.session_count().hash(&mut stable_hasher); let anon_id_seed = stable_hasher.finish(); #[cfg(debug_assertions)] @@ -1246,19 +1248,15 @@ impl CurrentDepGraph { assert_eq!(previous, fingerprint, "Unstable fingerprints for {:?}", key); } - /// Writes the node to the current dep-graph and allocates a `DepNodeIndex` for it. - /// Assumes that this is a node that has no equivalent in the previous dep-graph. #[inline(always)] - fn alloc_node( + fn record_node( &self, + dep_node_index: DepNodeIndex, key: DepNode, - edges: EdgesVec, - current_fingerprint: Fingerprint, - ) -> DepNodeIndex { - let dep_node_index = self.encoder.send(key, current_fingerprint, edges); - + _current_fingerprint: Fingerprint, + ) { #[cfg(debug_assertions)] - self.record_edge(dep_node_index, key, current_fingerprint); + self.record_edge(dep_node_index, key, _current_fingerprint); if let Some(ref nodes_in_current_session) = self.nodes_in_current_session { outline(|| { @@ -1267,6 +1265,20 @@ impl CurrentDepGraph { } }); } + } + + /// Writes the node to the current dep-graph and allocates a `DepNodeIndex` for it. + /// Assumes that this is a node that has no equivalent in the previous dep-graph. + #[inline(always)] + fn alloc_new_node( + &self, + key: DepNode, + edges: EdgesVec, + current_fingerprint: Fingerprint, + ) -> DepNodeIndex { + let dep_node_index = self.encoder.send_new(key, current_fingerprint, edges); + + self.record_node(dep_node_index, key, current_fingerprint); dep_node_index } diff --git a/compiler/rustc_query_system/src/dep_graph/serialized.rs b/compiler/rustc_query_system/src/dep_graph/serialized.rs index 7750d6d1fef4..ac24628447d8 100644 --- a/compiler/rustc_query_system/src/dep_graph/serialized.rs +++ b/compiler/rustc_query_system/src/dep_graph/serialized.rs @@ -92,6 +92,9 @@ pub struct SerializedDepGraph { /// Stores a map from fingerprints to nodes per dep node kind. /// This is the reciprocal of `nodes`. index: Vec>, + /// The number of previous compilation sessions. This is used to generate + /// unique anon dep nodes per session. + session_count: u64, } impl SerializedDepGraph { @@ -146,6 +149,11 @@ impl SerializedDepGraph { pub fn node_count(&self) -> usize { self.nodes.len() } + + #[inline] + pub fn session_count(&self) -> u64 { + self.session_count + } } /// A packed representation of an edge's start index and byte width. @@ -226,12 +234,12 @@ impl SerializedDepGraph { // If the length of this node's edge list is small, the length is stored in the header. // If it is not, we fall back to another decoder call. - let num_edges = node_header.len().unwrap_or_else(|| d.read_usize()); + let num_edges = node_header.len().unwrap_or_else(|| d.read_u32()); // The edges index list uses the same varint strategy as rmeta tables; we select the // number of byte elements per-array not per-element. This lets us read the whole edge // list for a node with one decoder call and also use the on-disk format in memory. - let edges_len_bytes = node_header.bytes_per_index() * num_edges; + let edges_len_bytes = node_header.bytes_per_index() * (num_edges as usize); // The in-memory structure for the edges list stores the byte width of the edges on // this node with the offset into the global edge data array. let edges_header = node_header.edges_header(&edge_list_data); @@ -252,6 +260,8 @@ impl SerializedDepGraph { .map(|_| UnhashMap::with_capacity_and_hasher(d.read_u32() as usize, Default::default())) .collect(); + let session_count = d.read_u64(); + for (idx, node) in nodes.iter_enumerated() { if index[node.kind.as_usize()].insert(node.hash, idx).is_some() { // Side effect nodes can have duplicates @@ -273,6 +283,7 @@ impl SerializedDepGraph { edge_list_indices, edge_list_data, index, + session_count, }) } } @@ -296,7 +307,7 @@ struct SerializedNodeHeader { // The fields of a `SerializedNodeHeader`, this struct is an implementation detail and exists only // to make the implementation of `SerializedNodeHeader` simpler. struct Unpacked { - len: Option, + len: Option, bytes_per_index: usize, kind: DepKind, hash: PackedFingerprint, @@ -352,7 +363,7 @@ impl SerializedNodeHeader { assert_eq!(fingerprint, res.fingerprint()); assert_eq!(node, res.node()); if let Some(len) = res.len() { - assert_eq!(edge_count, len); + assert_eq!(edge_count, len as usize); } } Self { bytes, _marker: PhantomData } @@ -366,7 +377,7 @@ impl SerializedNodeHeader { let kind = head & mask(Self::KIND_BITS) as u16; let bytes_per_index = (head >> Self::KIND_BITS) & mask(Self::WIDTH_BITS) as u16; - let len = (head as usize) >> (Self::WIDTH_BITS + Self::KIND_BITS); + let len = (head as u32) >> (Self::WIDTH_BITS + Self::KIND_BITS); Unpacked { len: len.checked_sub(1), @@ -378,7 +389,7 @@ impl SerializedNodeHeader { } #[inline] - fn len(&self) -> Option { + fn len(&self) -> Option { self.unpack().len } @@ -421,7 +432,8 @@ impl NodeInfo { e.write_array(header.bytes); if header.len().is_none() { - e.emit_usize(edges.len()); + // The edges are all unique and the number of unique indices is less than u32::MAX. + e.emit_u32(edges.len().try_into().unwrap()); } let bytes_per_index = header.bytes_per_index(); @@ -456,7 +468,8 @@ impl NodeInfo { e.write_array(header.bytes); if header.len().is_none() { - e.emit_usize(edge_count); + // The edges are all unique and the number of unique indices is less than u32::MAX. + e.emit_u32(edge_count.try_into().unwrap()); } let bytes_per_index = header.bytes_per_index(); @@ -601,7 +614,7 @@ impl EncoderState { stats: _, kind_stats, marker: _, - previous: _, + previous, } = self; let node_count = total_node_count.try_into().unwrap(); @@ -612,6 +625,8 @@ impl EncoderState { count.encode(&mut encoder); } + previous.session_count.checked_add(1).unwrap().encode(&mut encoder); + debug!(?node_count, ?edge_count); debug!("position: {:?}", encoder.position()); IntEncodedWithFixedSize(node_count).encode(&mut encoder); @@ -707,7 +722,8 @@ impl GraphEncoder { } } - pub(crate) fn send( + /// Encodes a node that does not exists in the previous graph. + pub(crate) fn send_new( &self, node: DepNode, fingerprint: Fingerprint, @@ -718,6 +734,40 @@ impl GraphEncoder { self.status.lock().as_mut().unwrap().encode_node(&node, &self.record_graph) } + /// Encodes a node that exists in the previous graph, but was re-executed. + /// + /// This will also ensure the dep node is colored either red or green. + pub(crate) fn send_and_color( + &self, + prev_index: SerializedDepNodeIndex, + colors: &DepNodeColorMap, + node: DepNode, + fingerprint: Fingerprint, + edges: EdgesVec, + is_green: bool, + ) -> DepNodeIndex { + let _prof_timer = self.profiler.generic_activity("incr_comp_encode_dep_graph"); + let node = NodeInfo { node, fingerprint, edges }; + + let mut status = self.status.lock(); + let status = status.as_mut().unwrap(); + + // Check colors inside the lock to avoid racing when `send_promoted` is called concurrently + // on the same index. + match colors.get(prev_index) { + None => { + let dep_node_index = status.encode_node(&node, &self.record_graph); + colors.insert( + prev_index, + if is_green { DepNodeColor::Green(dep_node_index) } else { DepNodeColor::Red }, + ); + dep_node_index + } + Some(DepNodeColor::Green(dep_node_index)) => dep_node_index, + Some(DepNodeColor::Red) => panic!(), + } + } + /// Encodes a node that was promoted from the previous graph. It reads the information directly from /// the previous dep graph and expects all edges to already have a new dep node index assigned. /// @@ -733,8 +783,8 @@ impl GraphEncoder { let mut status = self.status.lock(); let status = status.as_mut().unwrap(); - // Check colors inside the lock to avoid racing when `send_promoted` is called concurrently - // on the same index. + // Check colors inside the lock to avoid racing when `send_promoted` or `send_and_color` + // is called concurrently on the same index. match colors.get(prev_index) { None => { let dep_node_index = diff --git a/compiler/rustc_resolve/Cargo.toml b/compiler/rustc_resolve/Cargo.toml index 9ea9c58cfd17..0fcc3d8f6b3a 100644 --- a/compiler/rustc_resolve/Cargo.toml +++ b/compiler/rustc_resolve/Cargo.toml @@ -18,7 +18,6 @@ rustc_expand = { path = "../rustc_expand" } rustc_feature = { path = "../rustc_feature" } rustc_fluent_macro = { path = "../rustc_fluent_macro" } rustc_hir = { path = "../rustc_hir" } -rustc_index = { path = "../rustc_index" } rustc_macros = { path = "../rustc_macros" } rustc_metadata = { path = "../rustc_metadata" } rustc_middle = { path = "../rustc_middle" } diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 4368f7882ff4..cb328022c76d 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -1207,7 +1207,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { for (rule_i, rule_span) in &self.r.macro_map[&def_id.to_def_id()].rule_spans { self.r .unused_macro_rules - .entry(def_id) + .entry(node_id) .or_default() .insert(*rule_i, (ident, *rule_span)); } diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 6dc854758da5..363a75911ad4 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -170,10 +170,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { fn report_with_use_injections(&mut self, krate: &Crate) { for UseError { mut err, candidates, def_id, instead, suggestion, path, is_call } in - self.use_injections.drain(..) + std::mem::take(&mut self.use_injections) { let (span, found_use) = if let Some(def_id) = def_id.as_local() { - UsePlacementFinder::check(krate, self.def_id_to_node_id[def_id]) + UsePlacementFinder::check(krate, self.def_id_to_node_id(def_id)) } else { (None, FoundUse::No) }; @@ -1435,7 +1435,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let import_suggestions = self.lookup_import_candidates(ident, Namespace::MacroNS, parent_scope, is_expected); let (span, found_use) = match parent_scope.module.nearest_parent_mod().as_local() { - Some(def_id) => UsePlacementFinder::check(krate, self.def_id_to_node_id[def_id]), + Some(def_id) => UsePlacementFinder::check(krate, self.def_id_to_node_id(def_id)), None => (None, FoundUse::No), }; show_candidates( @@ -2550,7 +2550,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { .iter() .filter_map(|item| { let parent_module = self.opt_local_def_id(item.parent_module)?.to_def_id(); - Some(StrippedCfgItem { parent_module, name: item.name, cfg: item.cfg.clone() }) + Some(StrippedCfgItem { + parent_module, + ident: item.ident, + cfg: item.cfg.clone(), + }) }) .collect::>(); local_items.as_slice() @@ -2558,12 +2562,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { self.tcx.stripped_cfg_items(module.krate) }; - for &StrippedCfgItem { parent_module, name, ref cfg } in symbols { - if parent_module != module || name.name != *segment { + for &StrippedCfgItem { parent_module, ident, ref cfg } in symbols { + if parent_module != module || ident.name != *segment { continue; } - let note = errors::FoundItemConfigureOut { span: name.span }; + let note = errors::FoundItemConfigureOut { span: ident.span }; err.subdiagnostic(note); if let MetaItemKind::List(nested) = &cfg.kind diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 5f0a2a597e9b..180d6af219d1 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -296,9 +296,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ) -> Option> { assert!(ns == TypeNS || ns == ValueNS); let orig_ident = ident; - if ident.name == kw::Empty { - return Some(LexicalScopeBinding::Res(Res::Err)); - } let (general_span, normalized_span) = if ident.name == kw::SelfUpper { // FIXME(jseyfried) improve `Self` hygiene let empty_span = ident.span.with_ctxt(SyntaxContext::root()); diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 0b3633a452cb..762e08b2be5f 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -639,38 +639,38 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } if let Some(glob_binding) = resolution.shadowed_glob { - let binding_id = match binding.kind { - NameBindingKind::Res(res) => { - Some(self.def_id_to_node_id[res.def_id().expect_local()]) - } - NameBindingKind::Module(module) => { - Some(self.def_id_to_node_id[module.def_id().expect_local()]) - } - NameBindingKind::Import { import, .. } => import.id(), - }; - if binding.res() != Res::Err && glob_binding.res() != Res::Err && let NameBindingKind::Import { import: glob_import, .. } = glob_binding.kind - && let Some(binding_id) = binding_id && let Some(glob_import_id) = glob_import.id() && let glob_import_def_id = self.local_def_id(glob_import_id) && self.effective_visibilities.is_exported(glob_import_def_id) && glob_binding.vis.is_public() && !binding.vis.is_public() { - self.lint_buffer.buffer_lint( - HIDDEN_GLOB_REEXPORTS, - binding_id, - binding.span, - BuiltinLintDiag::HiddenGlobReexports { - name: key.ident.name.to_string(), - namespace: key.ns.descr().to_owned(), - glob_reexport_span: glob_binding.span, - private_item_span: binding.span, - }, - ); + let binding_id = match binding.kind { + NameBindingKind::Res(res) => { + Some(self.def_id_to_node_id(res.def_id().expect_local())) + } + NameBindingKind::Module(module) => { + Some(self.def_id_to_node_id(module.def_id().expect_local())) + } + NameBindingKind::Import { import, .. } => import.id(), + }; + if let Some(binding_id) = binding_id { + self.lint_buffer.buffer_lint( + HIDDEN_GLOB_REEXPORTS, + binding_id, + binding.span, + BuiltinLintDiag::HiddenGlobReexports { + name: key.ident.name.to_string(), + namespace: key.ns.descr().to_owned(), + glob_reexport_span: glob_binding.span, + private_item_span: binding.span, + }, + ); + } } } } @@ -1012,7 +1012,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // HACK(eddyb) `lint_if_path_starts_with_module` needs at least // 2 segments, so the `resolve_path` above won't trigger it. let mut full_path = import.module_path.clone(); - full_path.push(Segment::from_ident(Ident::empty())); + full_path.push(Segment::from_ident(Ident::dummy())); self.lint_if_path_starts_with_module(Some(finalize), &full_path, None); } diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 20e19caf9096..bae2fdeecafc 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1948,7 +1948,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { self.record_lifetime_res( anchor_id, - LifetimeRes::ElidedAnchor { start: id, end: NodeId::from_u32(id.as_u32() + 1) }, + LifetimeRes::ElidedAnchor { start: id, end: id + 1 }, LifetimeElisionCandidate::Ignore, ); self.resolve_anonymous_lifetime(<, anchor_id, true); @@ -4009,22 +4009,17 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { self.report_error(ident.span, error(ident)); } - // Record as bound if it's valid: - let ident_valid = ident.name != kw::Empty; - if ident_valid { - bindings.last_mut().unwrap().1.insert(ident); - } + // Record as bound. + bindings.last_mut().unwrap().1.insert(ident); if already_bound_or { // `Variant1(a) | Variant2(a)`, ok // Reuse definition from the first `a`. self.innermost_rib_bindings(ValueNS)[&ident] } else { + // A completely fresh binding is added to the set. let res = Res::Local(pat_id); - if ident_valid { - // A completely fresh binding add to the set if it's valid. - self.innermost_rib_bindings(ValueNS).insert(ident, res); - } + self.innermost_rib_bindings(ValueNS).insert(ident, res); res } } @@ -4611,6 +4606,11 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { } }; + // Fix up partial res of segment from `resolve_path` call. + if let Some(id) = path[0].id { + self.r.partial_res_map.insert(id, PartialRes::new(Res::PrimTy(prim))); + } + PartialRes::with_unresolved_segments(Res::PrimTy(prim), path.len() - 1) } PathResult::Module(ModuleOrUniformRoot::Module(module)) => { @@ -5012,8 +5012,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { return false; } let Some(local_did) = did.as_local() else { return true }; - let Some(node_id) = self.r.def_id_to_node_id.get(local_did) else { return true }; - !self.r.proc_macros.contains(node_id) + !self.r.proc_macros.contains(&local_did) } fn resolve_doc_links(&mut self, attrs: &[Attribute], maybe_exported: MaybeExported<'_>) { diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index b62bc6c45e0c..d4fe446cc9f7 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -1994,7 +1994,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { .iter() .flat_map(|i| self.r.tcx.associated_items(i).in_definition_order()) // Only assoc fn with no receivers. - .filter(|item| matches!(item.kind, ty::AssocKind::Fn) && !item.fn_has_self_parameter) + .filter(|item| item.is_fn() && !item.is_method()) .filter_map(|item| { // Only assoc fns that return `Self` let fn_sig = self.r.tcx.fn_sig(item.def_id).skip_binder(); @@ -2007,8 +2007,9 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { if def.did() != def_id { return None; } - let order = !item.name.as_str().starts_with("new"); - Some((order, item.name, input_len)) + let name = item.name(); + let order = !name.as_str().starts_with("new"); + Some((order, name, input_len)) }) .collect::>(); items.sort_by_key(|(order, _, _)| *order); @@ -2238,7 +2239,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { .get(&def_id) .is_some_and(|sig| sig.has_self), None => { - self.r.tcx.fn_arg_names(def_id).first().is_some_and(|&ident| { + self.r.tcx.fn_arg_idents(def_id).first().is_some_and(|&ident| { matches!(ident, Some(Ident { name: kw::SelfLower, .. })) }) } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 3ac66840d87d..b121755acd9c 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -56,7 +56,6 @@ use rustc_hir::def::{ }; use rustc_hir::def_id::{CRATE_DEF_ID, CrateNum, DefId, LOCAL_CRATE, LocalDefId, LocalDefIdMap}; use rustc_hir::{PrimTy, TraitCandidate}; -use rustc_index::IndexVec; use rustc_metadata::creader::{CStore, CrateLoader}; use rustc_middle::metadata::ModChild; use rustc_middle::middle::privacy::EffectiveVisibilities; @@ -1141,7 +1140,7 @@ pub struct Resolver<'ra, 'tcx> { ast_transform_scopes: FxHashMap>, unused_macros: FxIndexMap, /// A map from the macro to all its potentially unused arms. - unused_macro_rules: FxIndexMap>, + unused_macro_rules: FxIndexMap>, proc_macro_stubs: FxHashSet, /// Traces collected during macro resolution and validated when it's complete. single_segment_macro_resolutions: @@ -1184,7 +1183,6 @@ pub struct Resolver<'ra, 'tcx> { next_node_id: NodeId, node_id_to_def_id: NodeMap>, - def_id_to_node_id: IndexVec, /// Indices of unnamed struct or variant fields with unresolved attributes. placeholder_field_indices: FxHashMap, @@ -1202,7 +1200,7 @@ pub struct Resolver<'ra, 'tcx> { trait_impls: FxIndexMap>, /// A list of proc macro LocalDefIds, written out in the order in which /// they are declared in the static array generated by proc_macro_harness. - proc_macros: Vec, + proc_macros: Vec, confused_type_with_std_module: FxIndexMap, /// Whether lifetime elision was successful. lifetime_elision_allowed: FxHashSet, @@ -1339,12 +1337,12 @@ impl<'tcx> Resolver<'_, 'tcx> { expn_id: ExpnId, span: Span, ) -> TyCtxtFeed<'tcx, LocalDefId> { - let data = def_kind.def_path_data(name); assert!( !self.node_id_to_def_id.contains_key(&node_id), - "adding a def'n for node-id {:?} and data {:?} but a previous def'n exists: {:?}", + "adding a def for node-id {:?}, name {:?}, data {:?} but a previous def exists: {:?}", node_id, - data, + name, + def_kind, self.tcx.definitions_untracked().def_key(self.node_id_to_def_id[&node_id].key()), ); @@ -1369,7 +1367,6 @@ impl<'tcx> Resolver<'_, 'tcx> { debug!("create_def: def_id_to_node_id[{:?}] <-> {:?}", def_id, node_id); self.node_id_to_def_id.insert(node_id, feed.downgrade()); } - assert_eq!(self.def_id_to_node_id.push(node_id), def_id); feed } @@ -1385,6 +1382,19 @@ impl<'tcx> Resolver<'_, 'tcx> { pub fn tcx(&self) -> TyCtxt<'tcx> { self.tcx } + + /// This function is very slow, as it iterates over the entire + /// [Resolver::node_id_to_def_id] map just to find the [NodeId] + /// that corresponds to the given [LocalDefId]. Only use this in + /// diagnostics code paths. + fn def_id_to_node_id(&self, def_id: LocalDefId) -> NodeId { + self.node_id_to_def_id + .items() + .filter(|(_, v)| v.key() == def_id) + .map(|(k, _)| *k) + .get_only() + .unwrap() + } } impl<'ra, 'tcx> Resolver<'ra, 'tcx> { @@ -1417,8 +1427,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { &mut Default::default(), ); - let mut def_id_to_node_id = IndexVec::default(); - assert_eq!(def_id_to_node_id.push(CRATE_NODE_ID), CRATE_DEF_ID); let mut node_id_to_def_id = NodeMap::default(); let crate_feed = tcx.create_local_crate_def_id(crate_span); @@ -1553,7 +1561,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { lint_buffer: LintBuffer::default(), next_node_id: CRATE_NODE_ID, node_id_to_def_id, - def_id_to_node_id, placeholder_field_indices: Default::default(), invocation_parents, legacy_const_generic_args: Default::default(), @@ -1633,7 +1640,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } pub fn into_outputs(self) -> ResolverOutputs { - let proc_macros = self.proc_macros.iter().map(|id| self.local_def_id(*id)).collect(); + let proc_macros = self.proc_macros; let expn_that_defined = self.expn_that_defined; let extern_crate_map = self.extern_crate_map; let maybe_unused_trait_imports = self.maybe_unused_trait_imports; @@ -1648,7 +1655,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { .filter_map(|item| { let parent_module = self.node_id_to_def_id.get(&item.parent_module)?.key().to_def_id(); - Some(StrippedCfgItem { parent_module, name: item.name, cfg: item.cfg }) + Some(StrippedCfgItem { parent_module, ident: item.ident, cfg: item.cfg }) }) .collect(), ); @@ -2000,16 +2007,16 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { result, result.map(|r| r.expn_data()) ); - // Then find the last semi-transparent mark from the end if it exists. + // Then find the last semi-opaque mark from the end if it exists. for (mark, transparency) in iter { - if transparency == Transparency::SemiTransparent { + if transparency == Transparency::SemiOpaque { result = Some(mark); } else { break; } } debug!( - "resolve_crate_root: found semi-transparent mark {:?} {:?}", + "resolve_crate_root: found semi-opaque mark {:?} {:?}", result, result.map(|r| r.expn_data()) ); diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 9d6ae0aa9d13..749b7f24c50f 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -323,8 +323,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { } fn record_macro_rule_usage(&mut self, id: NodeId, rule_i: usize) { - let did = self.local_def_id(id); - if let Some(rules) = self.unused_macro_rules.get_mut(&did) { + if let Some(rules) = self.unused_macro_rules.get_mut(&id) { rules.remove(&rule_i); } } @@ -337,15 +336,12 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { ident.span, BuiltinLintDiag::UnusedMacroDefinition(ident.name), ); + // Do not report unused individual rules if the entire macro is unused + self.unused_macro_rules.swap_remove(&node_id); } - for (&def_id, unused_arms) in self.unused_macro_rules.iter() { + for (&node_id, unused_arms) in self.unused_macro_rules.iter() { for (&arm_i, &(ident, rule_span)) in unused_arms.to_sorted_stable_ord() { - if self.unused_macros.contains_key(&def_id) { - // We already lint the entire macro as unused - continue; - } - let node_id = self.def_id_to_node_id[def_id]; self.lint_buffer.buffer_lint( UNUSED_MACRO_RULES, node_id, @@ -466,11 +462,11 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { } fn declare_proc_macro(&mut self, id: NodeId) { - self.proc_macros.push(id) + self.proc_macros.push(self.local_def_id(id)) } - fn append_stripped_cfg_item(&mut self, parent_node: NodeId, name: Ident, cfg: ast::MetaItem) { - self.stripped_cfg_items.push(StrippedCfgItem { parent_module: parent_node, name, cfg }); + fn append_stripped_cfg_item(&mut self, parent_node: NodeId, ident: Ident, cfg: ast::MetaItem) { + self.stripped_cfg_items.push(StrippedCfgItem { parent_module: parent_node, ident, cfg }); } fn registered_tools(&self) -> &RegisteredTools { @@ -932,7 +928,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { .invocation_parents .get(&parent_scope.expansion) .map_or(ast::CRATE_NODE_ID, |parent| { - self.def_id_to_node_id[parent.parent_def] + self.def_id_to_node_id(parent.parent_def) }); self.lint_buffer.buffer_lint( LEGACY_DERIVE_HELPERS, diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs index d56ca9c24538..4b1b3903e403 100644 --- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs +++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs @@ -721,7 +721,8 @@ fn encode_ty_name(tcx: TyCtxt<'_>, def_id: DefId) -> String { | hir::definitions::DefPathData::Use | hir::definitions::DefPathData::GlobalAsm | hir::definitions::DefPathData::MacroNs(..) - | hir::definitions::DefPathData::LifetimeNs(..) => { + | hir::definitions::DefPathData::LifetimeNs(..) + | hir::definitions::DefPathData::AnonAssocTy => { bug!("encode_ty_name: unexpected `{:?}`", disambiguated_data.data); } }); diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs index 129a32c6edd8..d2917478e4e4 100644 --- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs +++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs @@ -240,7 +240,7 @@ fn trait_object_ty<'tcx>(tcx: TyCtxt<'tcx>, poly_trait_ref: ty::PolyTraitRef<'tc .flat_map(|super_poly_trait_ref| { tcx.associated_items(super_poly_trait_ref.def_id()) .in_definition_order() - .filter(|item| item.kind == ty::AssocKind::Type) + .filter(|item| item.is_type()) .filter(|item| !tcx.generics_require_sized_self(item.def_id)) .map(move |assoc_ty| { super_poly_trait_ref.map_bound(|super_trait_ref| { @@ -446,7 +446,7 @@ pub(crate) fn transform_instance<'tcx>( let call = tcx .associated_items(trait_id) .in_definition_order() - .find(|it| it.kind == ty::AssocKind::Fn) + .find(|it| it.is_fn()) .expect("No call-family function on closure-like Fn trait?") .def_id; diff --git a/compiler/rustc_sanitizers/src/lib.rs b/compiler/rustc_sanitizers/src/lib.rs index c4a9cab24d07..e4792563e71e 100644 --- a/compiler/rustc_sanitizers/src/lib.rs +++ b/compiler/rustc_sanitizers/src/lib.rs @@ -4,7 +4,6 @@ //! compiler. // tidy-alphabetical-start -#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![feature(let_chains)] // tidy-alphabetical-end diff --git a/compiler/rustc_serialize/src/opaque.rs b/compiler/rustc_serialize/src/opaque.rs index 81f6266f8d1f..0a55504a556d 100644 --- a/compiler/rustc_serialize/src/opaque.rs +++ b/compiler/rustc_serialize/src/opaque.rs @@ -19,7 +19,7 @@ pub type FileEncodeResult = Result; pub const MAGIC_END_BYTES: &[u8] = b"rust-end-file"; /// The size of the buffer in `FileEncoder`. -const BUF_SIZE: usize = 8192; +const BUF_SIZE: usize = 64 * 1024; /// `FileEncoder` encodes data to file via fixed-size buffer. /// diff --git a/compiler/rustc_session/Cargo.toml b/compiler/rustc_session/Cargo.toml index a087725d34dd..63772a322221 100644 --- a/compiler/rustc_session/Cargo.toml +++ b/compiler/rustc_session/Cargo.toml @@ -7,6 +7,7 @@ edition = "2024" # tidy-alphabetical-start bitflags = "2.4.1" getopts = "0.2" +rand = "0.9.0" rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } rustc_data_structures = { path = "../rustc_data_structures" } diff --git a/compiler/rustc_session/src/code_stats.rs b/compiler/rustc_session/src/code_stats.rs index b4597ae2515d..6b18d450e9e5 100644 --- a/compiler/rustc_session/src/code_stats.rs +++ b/compiler/rustc_session/src/code_stats.rs @@ -72,7 +72,7 @@ pub struct TypeSizeInfo { #[derive(Default)] pub struct CodeStats { - type_sizes: Lock>, + pub type_sizes: Lock>, } impl CodeStats { diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 56b3fe2ab4cb..ff7ea5bd7189 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -14,6 +14,7 @@ use std::str::{self, FromStr}; use std::sync::LazyLock; use std::{cmp, fmt, fs, iter}; +use externs::{ExternOpt, split_extern_opt}; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_data_structures::stable_hasher::{StableOrd, ToStableHashKey}; use rustc_errors::emitter::HumanReadableErrorType; @@ -39,6 +40,7 @@ use crate::utils::CanonicalizedPath; use crate::{EarlyDiagCtxt, HashStableContext, Session, filesearch, lint}; mod cfg; +mod externs; mod native_libs; pub mod sigpipe; @@ -1015,11 +1017,14 @@ impl OutFileName { &self, outputs: &OutputFilenames, flavor: OutputType, - codegen_unit_name: Option<&str>, + codegen_unit_name: &str, + invocation_temp: Option<&str>, ) -> PathBuf { match *self { OutFileName::Real(ref path) => path.clone(), - OutFileName::Stdout => outputs.temp_path(flavor, codegen_unit_name), + OutFileName::Stdout => { + outputs.temp_path_for_cgu(flavor, codegen_unit_name, invocation_temp) + } } } @@ -1094,40 +1099,59 @@ impl OutputFilenames { /// Gets the path where a compilation artifact of the given type for the /// given codegen unit should be placed on disk. If codegen_unit_name is /// None, a path distinct from those of any codegen unit will be generated. - pub fn temp_path(&self, flavor: OutputType, codegen_unit_name: Option<&str>) -> PathBuf { + pub fn temp_path_for_cgu( + &self, + flavor: OutputType, + codegen_unit_name: &str, + invocation_temp: Option<&str>, + ) -> PathBuf { let extension = flavor.extension(); - self.temp_path_ext(extension, codegen_unit_name) + self.temp_path_ext_for_cgu(extension, codegen_unit_name, invocation_temp) } /// Like `temp_path`, but specifically for dwarf objects. - pub fn temp_path_dwo(&self, codegen_unit_name: Option<&str>) -> PathBuf { - self.temp_path_ext(DWARF_OBJECT_EXT, codegen_unit_name) + pub fn temp_path_dwo_for_cgu( + &self, + codegen_unit_name: &str, + invocation_temp: Option<&str>, + ) -> PathBuf { + self.temp_path_ext_for_cgu(DWARF_OBJECT_EXT, codegen_unit_name, invocation_temp) } /// Like `temp_path`, but also supports things where there is no corresponding /// OutputType, like noopt-bitcode or lto-bitcode. - pub fn temp_path_ext(&self, ext: &str, codegen_unit_name: Option<&str>) -> PathBuf { - let mut extension = String::new(); + pub fn temp_path_ext_for_cgu( + &self, + ext: &str, + codegen_unit_name: &str, + invocation_temp: Option<&str>, + ) -> PathBuf { + let mut extension = codegen_unit_name.to_string(); - if let Some(codegen_unit_name) = codegen_unit_name { - extension.push_str(codegen_unit_name); + // Append `.{invocation_temp}` to ensure temporary files are unique. + if let Some(rng) = invocation_temp { + extension.push('.'); + extension.push_str(rng); } + // FIXME: This is sketchy that we're not appending `.rcgu` when the ext is empty. + // Append `.rcgu.{ext}`. if !ext.is_empty() { - if !extension.is_empty() { - extension.push('.'); - extension.push_str(RUST_CGU_EXT); - extension.push('.'); - } - + extension.push('.'); + extension.push_str(RUST_CGU_EXT); + extension.push('.'); extension.push_str(ext); } let temps_directory = self.temps_directory.as_ref().unwrap_or(&self.out_directory); - self.with_directory_and_extension(temps_directory, &extension) } + pub fn temp_path_for_diagnostic(&self, ext: &str) -> PathBuf { + let temps_directory = self.temps_directory.as_ref().unwrap_or(&self.out_directory); + self.with_directory_and_extension(temps_directory, &ext) + } + pub fn with_extension(&self, extension: &str) -> PathBuf { self.with_directory_and_extension(&self.out_directory, extension) } @@ -1144,10 +1168,11 @@ impl OutputFilenames { &self, split_debuginfo_kind: SplitDebuginfo, split_dwarf_kind: SplitDwarfKind, - cgu_name: Option<&str>, + cgu_name: &str, + invocation_temp: Option<&str>, ) -> Option { - let obj_out = self.temp_path(OutputType::Object, cgu_name); - let dwo_out = self.temp_path_dwo(cgu_name); + let obj_out = self.temp_path_for_cgu(OutputType::Object, cgu_name, invocation_temp); + let dwo_out = self.temp_path_dwo_for_cgu(cgu_name, invocation_temp); match (split_debuginfo_kind, split_dwarf_kind) { (SplitDebuginfo::Off, SplitDwarfKind::Single | SplitDwarfKind::Split) => None, // Single mode doesn't change how DWARF is emitted, but does add Split DWARF attributes @@ -1537,9 +1562,10 @@ The default is {DEFAULT_EDITION} and the latest stable edition is {LATEST_STABLE ) }); -static PRINT_KINDS_STRING: LazyLock = LazyLock::new(|| { +static PRINT_HELP: LazyLock = LazyLock::new(|| { format!( - "[{}]", + "Compiler information to print on stdout (or to a file)\n\ + INFO may be one of ({}).", PRINT_KINDS.iter().map(|(name, _)| format!("{name}")).collect::>().join("|") ) }); @@ -1598,14 +1624,7 @@ pub fn rustc_optgroups() -> Vec { "Comma separated list of types of output for the compiler to emit", "[asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir]", ), - opt( - Stable, - Multi, - "", - "print", - "Compiler information to print on stdout", - &PRINT_KINDS_STRING, - ), + opt(Stable, Multi, "", "print", &PRINT_HELP, "INFO[=FILE]"), opt(Stable, FlagMulti, "g", "", "Equivalent to -C debuginfo=2", ""), opt(Stable, FlagMulti, "O", "", "Equivalent to -C opt-level=3", ""), opt(Stable, Opt, "o", "", "Write output to ", "FILENAME"), @@ -2046,7 +2065,8 @@ fn collect_print_requests( check_print_request_stability(early_dcx, unstable_opts, (print_name, *print_kind)); *print_kind } else { - emit_unknown_print_request_help(early_dcx, req) + let is_nightly = nightly_options::match_is_nightly_build(matches); + emit_unknown_print_request_help(early_dcx, req, is_nightly) }; let out = out.unwrap_or(OutFileName::Stdout); @@ -2070,25 +2090,37 @@ fn check_print_request_stability( unstable_opts: &UnstableOptions, (print_name, print_kind): (&str, PrintKind), ) { + if !is_print_request_stable(print_kind) && !unstable_opts.unstable_options { + early_dcx.early_fatal(format!( + "the `-Z unstable-options` flag must also be passed to enable the `{print_name}` \ + print option" + )); + } +} + +fn is_print_request_stable(print_kind: PrintKind) -> bool { match print_kind { PrintKind::AllTargetSpecsJson | PrintKind::CheckCfg | PrintKind::CrateRootLintLevels | PrintKind::SupportedCrateTypes - | PrintKind::TargetSpecJson - if !unstable_opts.unstable_options => - { - early_dcx.early_fatal(format!( - "the `-Z unstable-options` flag must also be passed to enable the `{print_name}` \ - print option" - )); - } - _ => {} + | PrintKind::TargetSpecJson => false, + _ => true, } } -fn emit_unknown_print_request_help(early_dcx: &EarlyDiagCtxt, req: &str) -> ! { - let prints = PRINT_KINDS.iter().map(|(name, _)| format!("`{name}`")).collect::>(); +fn emit_unknown_print_request_help(early_dcx: &EarlyDiagCtxt, req: &str, is_nightly: bool) -> ! { + let prints = PRINT_KINDS + .iter() + .filter_map(|(name, kind)| { + // If we're not on nightly, we don't want to print unstable options + if !is_nightly && !is_print_request_stable(*kind) { + None + } else { + Some(format!("`{name}`")) + } + }) + .collect::>(); let prints = prints.join(", "); let mut diag = early_dcx.early_struct_fatal(format!("unknown print request: `{req}`")); @@ -2188,44 +2220,13 @@ pub fn parse_externs( matches: &getopts::Matches, unstable_opts: &UnstableOptions, ) -> Externs { - fn is_ascii_ident(string: &str) -> bool { - let mut chars = string.chars(); - if let Some(start) = chars.next() - && (start.is_ascii_alphabetic() || start == '_') - { - chars.all(|char| char.is_ascii_alphanumeric() || char == '_') - } else { - false - } - } - let is_unstable_enabled = unstable_opts.unstable_options; let mut externs: BTreeMap = BTreeMap::new(); for arg in matches.opt_strs("extern") { - let (name, path) = match arg.split_once('=') { - None => (arg, None), - Some((name, path)) => (name.to_string(), Some(Path::new(path))), - }; - let (options, name) = match name.split_once(':') { - None => (None, name), - Some((opts, name)) => (Some(opts), name.to_string()), - }; + let ExternOpt { crate_name: name, path, options } = + split_extern_opt(early_dcx, unstable_opts, &arg).unwrap_or_else(|e| e.emit()); - if !is_ascii_ident(&name) { - let mut error = early_dcx.early_struct_fatal(format!( - "crate name `{name}` passed to `--extern` is not a valid ASCII identifier" - )); - let adjusted_name = name.replace('-', "_"); - if is_ascii_ident(&adjusted_name) { - #[allow(rustc::diagnostic_outside_of_impl)] // FIXME - error.help(format!( - "consider replacing the dashes with underscores: `{adjusted_name}`" - )); - } - error.emit(); - } - - let path = path.map(|p| CanonicalizedPath::new(p)); + let path = path.map(|p| CanonicalizedPath::new(p.as_path())); let entry = externs.entry(name.to_owned()); diff --git a/compiler/rustc_session/src/config/externs.rs b/compiler/rustc_session/src/config/externs.rs new file mode 100644 index 000000000000..1420ee38bf21 --- /dev/null +++ b/compiler/rustc_session/src/config/externs.rs @@ -0,0 +1,79 @@ +//! This module contains code to help parse and manipulate `--extern` arguments. + +use std::path::PathBuf; + +use rustc_errors::{Diag, FatalAbort}; + +use super::UnstableOptions; +use crate::EarlyDiagCtxt; + +#[cfg(test)] +mod tests; + +/// Represents the pieces of an `--extern` argument. +pub(crate) struct ExternOpt { + pub(crate) crate_name: String, + pub(crate) path: Option, + pub(crate) options: Option, +} + +/// Breaks out the major components of an `--extern` argument. +/// +/// The options field will be a string containing comma-separated options that will need further +/// parsing and processing. +pub(crate) fn split_extern_opt<'a>( + early_dcx: &'a EarlyDiagCtxt, + unstable_opts: &UnstableOptions, + extern_opt: &str, +) -> Result> { + let (name, path) = match extern_opt.split_once('=') { + None => (extern_opt.to_string(), None), + Some((name, path)) => (name.to_string(), Some(PathBuf::from(path))), + }; + let (options, crate_name) = match name.split_once(':') { + None => (None, name), + Some((opts, crate_name)) => { + if unstable_opts.namespaced_crates && crate_name.starts_with(':') { + // If the name starts with `:`, we know this was actually something like `foo::bar` and + // not a set of options. We can just use the original name as the crate name. + (None, name) + } else { + (Some(opts.to_string()), crate_name.to_string()) + } + } + }; + + if !valid_crate_name(&crate_name, unstable_opts) { + let mut error = early_dcx.early_struct_fatal(format!( + "crate name `{crate_name}` passed to `--extern` is not a valid ASCII identifier" + )); + let adjusted_name = crate_name.replace('-', "_"); + if is_ascii_ident(&adjusted_name) { + #[allow(rustc::diagnostic_outside_of_impl)] // FIXME + error + .help(format!("consider replacing the dashes with underscores: `{adjusted_name}`")); + } + return Err(error); + } + + Ok(ExternOpt { crate_name, path, options }) +} + +fn valid_crate_name(name: &str, unstable_opts: &UnstableOptions) -> bool { + match name.split_once("::") { + Some((a, b)) if unstable_opts.namespaced_crates => is_ascii_ident(a) && is_ascii_ident(b), + Some(_) => false, + None => is_ascii_ident(name), + } +} + +fn is_ascii_ident(string: &str) -> bool { + let mut chars = string.chars(); + if let Some(start) = chars.next() + && (start.is_ascii_alphabetic() || start == '_') + { + chars.all(|char| char.is_ascii_alphanumeric() || char == '_') + } else { + false + } +} diff --git a/compiler/rustc_session/src/config/externs/tests.rs b/compiler/rustc_session/src/config/externs/tests.rs new file mode 100644 index 000000000000..654488695157 --- /dev/null +++ b/compiler/rustc_session/src/config/externs/tests.rs @@ -0,0 +1,92 @@ +use std::path::PathBuf; + +use super::split_extern_opt; +use crate::EarlyDiagCtxt; +use crate::config::UnstableOptions; + +/// Verifies split_extern_opt handles the supported cases. +#[test] +fn test_split_extern_opt() { + let early_dcx = EarlyDiagCtxt::new(<_>::default()); + let unstable_opts = &UnstableOptions::default(); + + let extern_opt = + split_extern_opt(&early_dcx, unstable_opts, "priv,noprelude:foo=libbar.rlib").unwrap(); + assert_eq!(extern_opt.crate_name, "foo"); + assert_eq!(extern_opt.path, Some(PathBuf::from("libbar.rlib"))); + assert_eq!(extern_opt.options, Some("priv,noprelude".to_string())); + + let extern_opt = split_extern_opt(&early_dcx, unstable_opts, "priv,noprelude:foo").unwrap(); + assert_eq!(extern_opt.crate_name, "foo"); + assert_eq!(extern_opt.path, None); + assert_eq!(extern_opt.options, Some("priv,noprelude".to_string())); + + let extern_opt = split_extern_opt(&early_dcx, unstable_opts, "foo=libbar.rlib").unwrap(); + assert_eq!(extern_opt.crate_name, "foo"); + assert_eq!(extern_opt.path, Some(PathBuf::from("libbar.rlib"))); + assert_eq!(extern_opt.options, None); + + let extern_opt = split_extern_opt(&early_dcx, unstable_opts, "foo").unwrap(); + assert_eq!(extern_opt.crate_name, "foo"); + assert_eq!(extern_opt.path, None); + assert_eq!(extern_opt.options, None); +} + +/// Tests some invalid cases for split_extern_opt. +#[test] +fn test_split_extern_opt_invalid() { + let early_dcx = EarlyDiagCtxt::new(<_>::default()); + let unstable_opts = &UnstableOptions::default(); + + // too many `:`s + let result = split_extern_opt(&early_dcx, unstable_opts, "priv:noprelude:foo=libbar.rlib"); + assert!(result.is_err()); + let _ = result.map_err(|e| e.cancel()); + + // can't nest externs without the unstable flag + let result = split_extern_opt(&early_dcx, unstable_opts, "noprelude:foo::bar=libbar.rlib"); + assert!(result.is_err()); + let _ = result.map_err(|e| e.cancel()); +} + +/// Tests some cases for split_extern_opt with nested crates like `foo::bar`. +#[test] +fn test_split_extern_opt_nested() { + let early_dcx = EarlyDiagCtxt::new(<_>::default()); + let unstable_opts = &UnstableOptions { namespaced_crates: true, ..Default::default() }; + + let extern_opt = + split_extern_opt(&early_dcx, unstable_opts, "priv,noprelude:foo::bar=libbar.rlib").unwrap(); + assert_eq!(extern_opt.crate_name, "foo::bar"); + assert_eq!(extern_opt.path, Some(PathBuf::from("libbar.rlib"))); + assert_eq!(extern_opt.options, Some("priv,noprelude".to_string())); + + let extern_opt = + split_extern_opt(&early_dcx, unstable_opts, "priv,noprelude:foo::bar").unwrap(); + assert_eq!(extern_opt.crate_name, "foo::bar"); + assert_eq!(extern_opt.path, None); + assert_eq!(extern_opt.options, Some("priv,noprelude".to_string())); + + let extern_opt = split_extern_opt(&early_dcx, unstable_opts, "foo::bar=libbar.rlib").unwrap(); + assert_eq!(extern_opt.crate_name, "foo::bar"); + assert_eq!(extern_opt.path, Some(PathBuf::from("libbar.rlib"))); + assert_eq!(extern_opt.options, None); + + let extern_opt = split_extern_opt(&early_dcx, unstable_opts, "foo::bar").unwrap(); + assert_eq!(extern_opt.crate_name, "foo::bar"); + assert_eq!(extern_opt.path, None); + assert_eq!(extern_opt.options, None); +} + +/// Tests some invalid cases for split_extern_opt with nested crates like `foo::bar`. +#[test] +fn test_split_extern_opt_nested_invalid() { + let early_dcx = EarlyDiagCtxt::new(<_>::default()); + let unstable_opts = &UnstableOptions { namespaced_crates: true, ..Default::default() }; + + // crates can only be nested one deep. + let result = + split_extern_opt(&early_dcx, unstable_opts, "priv,noprelude:foo::bar::baz=libbar.rlib"); + assert!(result.is_err()); + let _ = result.map_err(|e| e.cancel()); +} diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index c70f1500d393..1b0794f79d3e 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1956,6 +1956,9 @@ options! { "allow the linker to link its default libraries (default: no)"), dlltool: Option = (None, parse_opt_pathbuf, [UNTRACKED], "import library generation tool (ignored except when targeting windows-gnu)"), + #[rustc_lint_opt_deny_field_access("use `Session::dwarf_version` instead of this field")] + dwarf_version: Option = (None, parse_opt_number, [TRACKED], + "version of DWARF debug information to emit (default: 2 or 4, depending on platform)"), embed_bitcode: bool = (true, parse_bool, [TRACKED], "emit bitcode in rlibs (default: yes)"), extra_filename: String = (String::new(), parse_string, [UNTRACKED], @@ -2331,6 +2334,8 @@ options! { "the size at which the `large_assignments` lint starts to be emitted"), mutable_noalias: bool = (true, parse_bool, [TRACKED], "emit noalias metadata for mutable references (default: yes)"), + namespaced_crates: bool = (false, parse_bool, [TRACKED], + "allow crates to be namespaced by other crates (default: no)"), next_solver: NextSolverConfig = (NextSolverConfig::default(), parse_next_solver_config, [TRACKED], "enable and configure the next generation trait solver used by rustc"), nll_facts: bool = (false, parse_bool, [UNTRACKED], diff --git a/compiler/rustc_session/src/output.rs b/compiler/rustc_session/src/output.rs index a24919e434cc..46dae9144cd4 100644 --- a/compiler/rustc_session/src/output.rs +++ b/compiler/rustc_session/src/output.rs @@ -177,6 +177,13 @@ pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec, } #[derive(PartialEq, Eq, PartialOrd, Ord)] @@ -754,7 +764,11 @@ impl Session { /// Returns the DWARF version passed on the CLI or the default for the target. pub fn dwarf_version(&self) -> u32 { - self.opts.unstable_opts.dwarf_version.unwrap_or(self.target.default_dwarf_version) + self.opts + .cg + .dwarf_version + .or(self.opts.unstable_opts.dwarf_version) + .unwrap_or(self.target.default_dwarf_version) } pub fn stack_protector(&self) -> StackProtector { @@ -1117,6 +1131,12 @@ pub fn build_session( let target_filesearch = filesearch::FileSearch::new(&sopts.search_paths, &target_tlib_path, &target); let host_filesearch = filesearch::FileSearch::new(&sopts.search_paths, &host_tlib_path, &host); + + let invocation_temp = sopts + .incremental + .as_ref() + .map(|_| rng().next_u32().to_base_fixed_len(CASE_INSENSITIVE).to_string()); + let sess = Session { target, host, @@ -1140,6 +1160,7 @@ pub fn build_session( expanded_args, target_filesearch, host_filesearch, + invocation_temp, }; validate_commandline_args_with_session_available(&sess); @@ -1310,7 +1331,9 @@ fn validate_commandline_args_with_session_available(sess: &Session) { sess.dcx().emit_err(errors::BranchProtectionRequiresAArch64); } - if let Some(dwarf_version) = sess.opts.unstable_opts.dwarf_version { + if let Some(dwarf_version) = + sess.opts.cg.dwarf_version.or(sess.opts.unstable_opts.dwarf_version) + { // DWARF 1 is not supported by LLVM and DWARF 6 is not yet finalized. if dwarf_version < 2 || dwarf_version > 5 { sess.dcx().emit_err(errors::UnsupportedDwarfVersion { dwarf_version }); diff --git a/compiler/rustc_smir/src/lib.rs b/compiler/rustc_smir/src/lib.rs index 5d465bca4eef..77e5f3423d1e 100644 --- a/compiler/rustc_smir/src/lib.rs +++ b/compiler/rustc_smir/src/lib.rs @@ -9,7 +9,6 @@ // tidy-alphabetical-start #![allow(internal_features)] #![allow(rustc::usage_of_ty_tykind)] -#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![doc( html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/", test(attr(allow(unused_variables), deny(warnings))) diff --git a/compiler/rustc_smir/src/rustc_internal/internal.rs b/compiler/rustc_smir/src/rustc_internal/internal.rs index 36b68cc13982..6e13b87c41d7 100644 --- a/compiler/rustc_smir/src/rustc_internal/internal.rs +++ b/compiler/rustc_smir/src/rustc_internal/internal.rs @@ -491,7 +491,6 @@ impl RustcInternal for Abi { Abi::CCmseNonSecureCall => rustc_abi::ExternAbi::CCmseNonSecureCall, Abi::CCmseNonSecureEntry => rustc_abi::ExternAbi::CCmseNonSecureEntry, Abi::System { unwind } => rustc_abi::ExternAbi::System { unwind }, - Abi::RustIntrinsic => rustc_abi::ExternAbi::RustIntrinsic, Abi::RustCall => rustc_abi::ExternAbi::RustCall, Abi::Unadjusted => rustc_abi::ExternAbi::Unadjusted, Abi::RustCold => rustc_abi::ExternAbi::RustCold, diff --git a/compiler/rustc_smir/src/rustc_internal/mod.rs b/compiler/rustc_smir/src/rustc_internal/mod.rs index a546a44c8700..146ba17d14fc 100644 --- a/compiler/rustc_smir/src/rustc_internal/mod.rs +++ b/compiler/rustc_smir/src/rustc_internal/mod.rs @@ -244,6 +244,7 @@ where /// ```ignore(needs-extern-crate) /// # extern crate rustc_driver; /// # extern crate rustc_interface; +/// # extern crate rustc_middle; /// # #[macro_use] /// # extern crate rustc_smir; /// # extern crate stable_mir; @@ -264,6 +265,7 @@ where /// ```ignore(needs-extern-crate) /// # extern crate rustc_driver; /// # extern crate rustc_interface; +/// # extern crate rustc_middle; /// # #[macro_use] /// # extern crate rustc_smir; /// # extern crate stable_mir; @@ -328,6 +330,7 @@ macro_rules! run_driver { use rustc_driver::{Callbacks, Compilation, run_compiler}; use rustc_middle::ty::TyCtxt; use rustc_interface::interface; + use rustc_smir::rustc_internal; use stable_mir::CompilerError; use std::ops::ControlFlow; diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs index 1ba25aa0e971..a757329bcf2a 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs @@ -871,7 +871,6 @@ impl<'tcx> Stable<'tcx> for rustc_abi::ExternAbi { ExternAbi::CCmseNonSecureCall => Abi::CCmseNonSecureCall, ExternAbi::CCmseNonSecureEntry => Abi::CCmseNonSecureEntry, ExternAbi::System { unwind } => Abi::System { unwind }, - ExternAbi::RustIntrinsic => Abi::RustIntrinsic, ExternAbi::RustCall => Abi::RustCall, ExternAbi::Unadjusted => Abi::Unadjusted, ExternAbi::RustCold => Abi::RustCold, @@ -895,12 +894,21 @@ impl<'tcx> Stable<'tcx> for rustc_session::cstore::ForeignModule { impl<'tcx> Stable<'tcx> for ty::AssocKind { type T = stable_mir::ty::AssocKind; - fn stable(&self, _tables: &mut Tables<'_>) -> Self::T { - use stable_mir::ty::AssocKind; - match self { - ty::AssocKind::Const => AssocKind::Const, - ty::AssocKind::Fn => AssocKind::Fn, - ty::AssocKind::Type => AssocKind::Type, + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { + use stable_mir::ty::{AssocKind, AssocTypeData}; + match *self { + ty::AssocKind::Const { name } => AssocKind::Const { name: name.to_string() }, + ty::AssocKind::Fn { name, has_self } => { + AssocKind::Fn { name: name.to_string(), has_self } + } + ty::AssocKind::Type { data } => AssocKind::Type { + data: match data { + ty::AssocTypeData::Normal(name) => AssocTypeData::Normal(name.to_string()), + ty::AssocTypeData::Rpitit(rpitit) => { + AssocTypeData::Rpitit(rpitit.stable(tables)) + } + }, + }, } } } @@ -923,12 +931,9 @@ impl<'tcx> Stable<'tcx> for ty::AssocItem { fn stable(&self, tables: &mut Tables<'_>) -> Self::T { stable_mir::ty::AssocItem { def_id: tables.assoc_def(self.def_id), - name: self.name.to_string(), kind: self.kind.stable(tables), container: self.container.stable(tables), trait_item_def_id: self.trait_item_def_id.map(|did| tables.assoc_def(did)), - fn_has_self_parameter: self.fn_has_self_parameter, - opt_rpitit_info: self.opt_rpitit_info.map(|rpitit| rpitit.stable(tables)), } } } diff --git a/compiler/rustc_smir/src/stable_mir/mir/pretty.rs b/compiler/rustc_smir/src/stable_mir/mir/pretty.rs index 439ebe978e59..8a6be0cd37a0 100644 --- a/compiler/rustc_smir/src/stable_mir/mir/pretty.rs +++ b/compiler/rustc_smir/src/stable_mir/mir/pretty.rs @@ -22,9 +22,10 @@ impl Display for Ty { impl Display for AssocKind { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { match self { - AssocKind::Fn => write!(f, "method"), - AssocKind::Const => write!(f, "associated const"), - AssocKind::Type => write!(f, "associated type"), + AssocKind::Fn { has_self: true, .. } => write!(f, "method"), + AssocKind::Fn { has_self: false, .. } => write!(f, "associated function"), + AssocKind::Const { .. } => write!(f, "associated const"), + AssocKind::Type { .. } => write!(f, "associated type"), } } } diff --git a/compiler/rustc_smir/src/stable_mir/ty.rs b/compiler/rustc_smir/src/stable_mir/ty.rs index 1efa2fe13c56..4b153007bd86 100644 --- a/compiler/rustc_smir/src/stable_mir/ty.rs +++ b/compiler/rustc_smir/src/stable_mir/ty.rs @@ -1093,7 +1093,6 @@ pub enum Abi { CCmseNonSecureCall, CCmseNonSecureEntry, System { unwind: bool }, - RustIntrinsic, RustCall, Unadjusted, RustCold, @@ -1579,29 +1578,28 @@ crate_def! { #[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct AssocItem { pub def_id: AssocDef, - pub name: Symbol, pub kind: AssocKind, pub container: AssocItemContainer, /// If this is an item in an impl of a trait then this is the `DefId` of /// the associated item on the trait that this implements. pub trait_item_def_id: Option, +} - /// Whether this is a method with an explicit self - /// as its first parameter, allowing method calls. - pub fn_has_self_parameter: bool, - - /// `Some` if the associated item (an associated type) comes from the - /// return-position `impl Trait` in trait desugaring. The `ImplTraitInTraitData` - /// provides additional information about its source. - pub opt_rpitit_info: Option, +#[derive(Clone, PartialEq, Debug, Eq, Serialize)] +pub enum AssocTypeData { + Normal(Symbol), + /// The associated type comes from an RPITIT. It has no name, and the + /// `ImplTraitInTraitData` provides additional information about its + /// source. + Rpitit(ImplTraitInTraitData), } #[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub enum AssocKind { - Const, - Fn, - Type, + Const { name: Symbol }, + Fn { name: Symbol, has_self: bool }, + Type { data: AssocTypeData }, } #[derive(Clone, Debug, Eq, PartialEq, Serialize)] @@ -1618,6 +1616,6 @@ pub enum ImplTraitInTraitData { impl AssocItem { pub fn is_impl_trait_in_trait(&self) -> bool { - self.opt_rpitit_info.is_some() + matches!(self.kind, AssocKind::Type { data: AssocTypeData::Rpitit(_) }) } } diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index 9be16f8ce0c9..d1da68ec2365 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -56,44 +56,33 @@ impl !PartialOrd for SyntaxContext {} /// If this part of two syntax contexts is equal, then the whole syntax contexts should be equal. /// The other fields are only for caching. -type SyntaxContextKey = (SyntaxContext, ExpnId, Transparency); +pub type SyntaxContextKey = (SyntaxContext, ExpnId, Transparency); #[derive(Clone, Copy, Debug)] struct SyntaxContextData { outer_expn: ExpnId, outer_transparency: Transparency, parent: SyntaxContext, - /// This context, but with all transparent and semi-transparent expansions filtered away. + /// This context, but with all transparent and semi-opaque expansions filtered away. opaque: SyntaxContext, /// This context, but with all transparent expansions filtered away. - opaque_and_semitransparent: SyntaxContext, + opaque_and_semiopaque: SyntaxContext, /// Name of the crate to which `$crate` with this context would resolve. dollar_crate_name: Symbol, } -/// Same as `SyntaxContextData`, but `opaque(_and_semitransparent)` cannot be recursive -/// and use `None` if they need to refer to self. Used for encoding and decoding metadata. -#[derive(Encodable, Decodable)] -pub struct SyntaxContextDataNonRecursive { - outer_expn: ExpnId, - outer_transparency: Transparency, - parent: SyntaxContext, - opaque: Option, - opaque_and_semitransparent: Option, -} - impl SyntaxContextData { fn new( (parent, outer_expn, outer_transparency): SyntaxContextKey, opaque: SyntaxContext, - opaque_and_semitransparent: SyntaxContext, + opaque_and_semiopaque: SyntaxContext, ) -> SyntaxContextData { SyntaxContextData { outer_expn, outer_transparency, parent, opaque, - opaque_and_semitransparent, + opaque_and_semiopaque, dollar_crate_name: kw::DollarCrate, } } @@ -104,7 +93,7 @@ impl SyntaxContextData { outer_transparency: Transparency::Opaque, parent: SyntaxContext::root(), opaque: SyntaxContext::root(), - opaque_and_semitransparent: SyntaxContext::root(), + opaque_and_semiopaque: SyntaxContext::root(), dollar_crate_name: kw::DollarCrate, } } @@ -122,19 +111,6 @@ impl SyntaxContextData { } } -impl SyntaxContextDataNonRecursive { - fn recursive(&self, ctxt: SyntaxContext) -> SyntaxContextData { - SyntaxContextData { - outer_expn: self.outer_expn, - outer_transparency: self.outer_transparency, - parent: self.parent, - opaque: self.opaque.unwrap_or(ctxt), - opaque_and_semitransparent: self.opaque_and_semitransparent.unwrap_or(ctxt), - dollar_crate_name: kw::DollarCrate, - } - } -} - rustc_index::newtype_index! { /// A unique ID associated with a macro invocation and expansion. #[orderable] @@ -228,13 +204,13 @@ pub enum Transparency { /// Identifier produced by a transparent expansion is always resolved at call-site. /// Call-site spans in procedural macros, hygiene opt-out in `macro` should use this. Transparent, - /// Identifier produced by a semi-transparent expansion may be resolved + /// Identifier produced by a semi-opaque expansion may be resolved /// either at call-site or at definition-site. /// If it's a local variable, label or `$crate` then it's resolved at def-site. /// Otherwise it's resolved at call-site. /// `macro_rules` macros behave like this, built-in macros currently behave like this too, /// but that's an implementation detail. - SemiTransparent, + SemiOpaque, /// Identifier produced by an opaque expansion is always resolved at definition-site. /// Def-site spans in procedural macros, identifiers from `macro` by default use this. Opaque, @@ -242,7 +218,7 @@ pub enum Transparency { impl Transparency { pub fn fallback(macro_rules: bool) -> Self { - if macro_rules { Transparency::SemiTransparent } else { Transparency::Opaque } + if macro_rules { Transparency::SemiOpaque } else { Transparency::Opaque } } } @@ -490,7 +466,7 @@ impl HygieneData { fn normalize_to_macro_rules(&self, ctxt: SyntaxContext) -> SyntaxContext { debug_assert!(!self.syntax_context_data[ctxt.0 as usize].is_decode_placeholder()); - self.syntax_context_data[ctxt.0 as usize].opaque_and_semitransparent + self.syntax_context_data[ctxt.0 as usize].opaque_and_semiopaque } fn outer_expn(&self, ctxt: SyntaxContext) -> ExpnId { @@ -583,7 +559,7 @@ impl HygieneData { } let call_site_ctxt = self.expn_data(expn_id).call_site.ctxt(); - let mut call_site_ctxt = if transparency == Transparency::SemiTransparent { + let mut call_site_ctxt = if transparency == Transparency::SemiOpaque { self.normalize_to_macros_2_0(call_site_ctxt) } else { self.normalize_to_macro_rules(call_site_ctxt) @@ -629,48 +605,34 @@ impl HygieneData { self.syntax_context_data.push(SyntaxContextData::decode_placeholder()); self.syntax_context_map.insert(key, ctxt); - // Opaque and semi-transparent versions of the parent. Note that they may be equal to the + // Opaque and semi-opaque versions of the parent. Note that they may be equal to the // parent itself. E.g. `parent_opaque` == `parent` if the expn chain contains only opaques, - // and `parent_opaque_and_semitransparent` == `parent` if the expn contains only opaques - // and semi-transparents. + // and `parent_opaque_and_semiopaque` == `parent` if the expn contains only (semi-)opaques. let parent_opaque = self.syntax_context_data[parent.0 as usize].opaque; - let parent_opaque_and_semitransparent = - self.syntax_context_data[parent.0 as usize].opaque_and_semitransparent; + let parent_opaque_and_semiopaque = + self.syntax_context_data[parent.0 as usize].opaque_and_semiopaque; - // Evaluate opaque and semi-transparent versions of the new syntax context. - let (opaque, opaque_and_semitransparent) = match transparency { - Transparency::Transparent => (parent_opaque, parent_opaque_and_semitransparent), - Transparency::SemiTransparent => ( + // Evaluate opaque and semi-opaque versions of the new syntax context. + let (opaque, opaque_and_semiopaque) = match transparency { + Transparency::Transparent => (parent_opaque, parent_opaque_and_semiopaque), + Transparency::SemiOpaque => ( parent_opaque, - // Will be the same as `ctxt` if the expn chain contains only opaques and semi-transparents. - self.alloc_ctxt(parent_opaque_and_semitransparent, expn_id, transparency), + // Will be the same as `ctxt` if the expn chain contains only (semi-)opaques. + self.alloc_ctxt(parent_opaque_and_semiopaque, expn_id, transparency), ), Transparency::Opaque => ( // Will be the same as `ctxt` if the expn chain contains only opaques. self.alloc_ctxt(parent_opaque, expn_id, transparency), - // Will be the same as `ctxt` if the expn chain contains only opaques and semi-transparents. - self.alloc_ctxt(parent_opaque_and_semitransparent, expn_id, transparency), + // Will be the same as `ctxt` if the expn chain contains only (semi-)opaques. + self.alloc_ctxt(parent_opaque_and_semiopaque, expn_id, transparency), ), }; // Fill the full data, now that we have it. self.syntax_context_data[ctxt.as_u32() as usize] = - SyntaxContextData::new(key, opaque, opaque_and_semitransparent); + SyntaxContextData::new(key, opaque, opaque_and_semiopaque); ctxt } - - fn non_recursive_ctxt(&self, ctxt: SyntaxContext) -> SyntaxContextDataNonRecursive { - debug_assert!(!self.syntax_context_data[ctxt.0 as usize].is_decode_placeholder()); - let data = &self.syntax_context_data[ctxt.0 as usize]; - SyntaxContextDataNonRecursive { - outer_expn: data.outer_expn, - outer_transparency: data.outer_transparency, - parent: data.parent, - opaque: (data.opaque != ctxt).then_some(data.opaque), - opaque_and_semitransparent: (data.opaque_and_semitransparent != ctxt) - .then_some(data.opaque_and_semitransparent), - } - } } pub fn walk_chain(span: Span, to: SyntaxContext) -> Span { @@ -1300,7 +1262,7 @@ impl HygieneEncodeContext { pub fn encode( &self, encoder: &mut T, - mut encode_ctxt: impl FnMut(&mut T, u32, &SyntaxContextDataNonRecursive), + mut encode_ctxt: impl FnMut(&mut T, u32, &SyntaxContextKey), mut encode_expn: impl FnMut(&mut T, ExpnId, &ExpnData, ExpnHash), ) { // When we serialize a `SyntaxContextData`, we may end up serializing @@ -1425,10 +1387,7 @@ pub fn decode_expn_id( // to track which `SyntaxContext`s we have already decoded. // The provided closure will be invoked to deserialize a `SyntaxContextData` // if we haven't already seen the id of the `SyntaxContext` we are deserializing. -pub fn decode_syntax_context< - D: Decoder, - F: FnOnce(&mut D, u32) -> SyntaxContextDataNonRecursive, ->( +pub fn decode_syntax_context SyntaxContextKey>( d: &mut D, context: &HygieneDecodeContext, decode_data: F, @@ -1450,16 +1409,9 @@ pub fn decode_syntax_context< // Don't try to decode data while holding the lock, since we need to // be able to recursively decode a SyntaxContext - let ctxt_data = decode_data(d, raw_id); - - let ctxt = HygieneData::with(|hygiene_data| { - let ctxt_key = (ctxt_data.parent, ctxt_data.outer_expn, ctxt_data.outer_transparency); - *hygiene_data.syntax_context_map.entry(ctxt_key).or_insert_with(|| { - let ctxt = SyntaxContext::from_usize(hygiene_data.syntax_context_data.len()); - hygiene_data.syntax_context_data.push(ctxt_data.recursive(ctxt)); - ctxt - }) - }); + let (parent, expn_id, transparency) = decode_data(d, raw_id); + let ctxt = + HygieneData::with(|hygiene_data| hygiene_data.alloc_ctxt(parent, expn_id, transparency)); let mut inner = context.inner.lock(); let new_len = raw_id as usize + 1; @@ -1471,12 +1423,21 @@ pub fn decode_syntax_context< ctxt } -fn for_all_ctxts_in( +fn for_all_ctxts_in( ctxts: impl Iterator, mut f: F, ) { - let all_data: Vec<_> = - HygieneData::with(|data| ctxts.map(|ctxt| (ctxt, data.non_recursive_ctxt(ctxt))).collect()); + let all_data: Vec<_> = HygieneData::with(|data| { + ctxts + .map(|ctxt| { + (ctxt, { + let item = data.syntax_context_data[ctxt.0 as usize]; + debug_assert!(!item.is_decode_placeholder()); + item.key() + }) + }) + .collect() + }); for (ctxt, data) in all_data.into_iter() { f(ctxt.0, ctxt, &data); } diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 9e6ba2e1b9ce..f788fd48037a 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -116,9 +116,13 @@ pub struct SessionGlobals { } impl SessionGlobals { - pub fn new(edition: Edition, sm_inputs: Option) -> SessionGlobals { + pub fn new( + edition: Edition, + extra_symbols: &[&'static str], + sm_inputs: Option, + ) -> SessionGlobals { SessionGlobals { - symbol_interner: symbol::Interner::fresh(), + symbol_interner: symbol::Interner::with_extra_symbols(extra_symbols), span_interner: Lock::new(span_encoding::SpanInterner::default()), metavar_spans: Default::default(), hygiene_data: Lock::new(hygiene::HygieneData::new(edition)), @@ -129,6 +133,7 @@ impl SessionGlobals { pub fn create_session_globals_then( edition: Edition, + extra_symbols: &[&'static str], sm_inputs: Option, f: impl FnOnce() -> R, ) -> R { @@ -137,7 +142,7 @@ pub fn create_session_globals_then( "SESSION_GLOBALS should never be overwritten! \ Use another thread if you need another SessionGlobals" ); - let session_globals = SessionGlobals::new(edition, sm_inputs); + let session_globals = SessionGlobals::new(edition, extra_symbols, sm_inputs); SESSION_GLOBALS.set(&session_globals, f) } @@ -156,7 +161,7 @@ where F: FnOnce(&SessionGlobals) -> R, { if !SESSION_GLOBALS.is_set() { - let session_globals = SessionGlobals::new(edition, None); + let session_globals = SessionGlobals::new(edition, &[], None); SESSION_GLOBALS.set(&session_globals, || SESSION_GLOBALS.with(f)) } else { SESSION_GLOBALS.with(f) @@ -172,7 +177,7 @@ where /// Default edition, no source map. pub fn create_default_session_globals_then(f: impl FnOnce() -> R) -> R { - create_session_globals_then(edition::DEFAULT_EDITION, None, f) + create_session_globals_then(edition::DEFAULT_EDITION, &[], None, f) } // If this ever becomes non thread-local, `decode_syntax_context` @@ -1112,7 +1117,7 @@ impl Span { /// Equivalent of `Span::mixed_site` from the proc macro API, /// except that the location is taken from the `self` span. pub fn with_mixed_site_ctxt(self, expn_id: ExpnId) -> Span { - self.with_ctxt_from_mark(expn_id, Transparency::SemiTransparent) + self.with_ctxt_from_mark(expn_id, Transparency::SemiOpaque) } /// Produces a span with the same location as `self` and context produced by a macro with the diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index 6fdf8e46fec6..0273bb040f43 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -633,6 +633,24 @@ impl SourceMap { sp } + /// Extends the given `Span` to just before the previous occurrence of `c`. Return the same span + /// if an error occurred while retrieving the code snippet. + pub fn span_extend_to_prev_char_before( + &self, + sp: Span, + c: char, + accept_newlines: bool, + ) -> Span { + if let Ok(prev_source) = self.span_to_prev_source(sp) { + let prev_source = prev_source.rsplit(c).next().unwrap_or(""); + if accept_newlines || !prev_source.contains('\n') { + return sp.with_lo(BytePos(sp.lo().0 - prev_source.len() as u32 - 1_u32)); + } + } + + sp + } + /// Extends the given `Span` to just after the previous occurrence of `pat` when surrounded by /// whitespace. Returns None if the pattern could not be found or if an error occurred while /// retrieving the code snippet. diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 31847ae3b465..f7b10d3c529b 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -454,6 +454,7 @@ symbols! { and_then, anon, anon_adt, + anon_assoc, anonymous_lifetime_in_impl_trait, any, append_const_msg, @@ -915,6 +916,7 @@ symbols! { expf16, expf32, expf64, + explicit_extern_abis, explicit_generic_args_with_impl_trait, explicit_tail_calls, export_name, @@ -1067,7 +1069,6 @@ symbols! { ge, gen_blocks, gen_future, - gen_kill, generator_clone, generators, generic_arg_infer, @@ -1185,6 +1186,7 @@ symbols! { instruction_set, integer_: "integer", // underscore to avoid clashing with the function `sym::integer` below integral, + internal_features, into_async_iter_into_iter, into_future, into_iter, @@ -1399,6 +1401,7 @@ symbols! { naked, naked_asm, naked_functions, + naked_functions_rustic_abi, naked_functions_target_feature, name, names, @@ -1881,6 +1884,7 @@ symbols! { select_unpredictable, self_in_typedefs, self_struct_ctor, + semiopaque, semitransparent, sha2, sha3, @@ -1913,6 +1917,7 @@ symbols! { simd_eq, simd_expose_provenance, simd_extract, + simd_extract_dyn, simd_fabs, simd_fcos, simd_fexp, @@ -1931,6 +1936,7 @@ symbols! { simd_ge, simd_gt, simd_insert, + simd_insert_dyn, simd_le, simd_lt, simd_masked_load, @@ -2211,7 +2217,8 @@ symbols! { unsafe_extern_blocks, unsafe_fields, unsafe_no_drop_flag, - unsafe_pin_internals, + unsafe_pinned, + unsafe_unpin, unsize, unsized_const_param_ty, unsized_const_params, @@ -2538,15 +2545,10 @@ rustc_index::newtype_index! { } impl Symbol { - const fn new(n: u32) -> Self { + pub const fn new(n: u32) -> Self { Symbol(SymbolIndex::from_u32(n)) } - /// for use in Decoder only - pub fn new_from_decoded(n: u32) -> Self { - Self::new(n) - } - /// Maps a string to its interned representation. #[rustc_diagnostic_item = "SymbolIntern"] pub fn intern(string: &str) -> Self { @@ -2632,11 +2634,14 @@ struct InternerInner { } impl Interner { - fn prefill(init: &[&'static str]) -> Self { - Interner(Lock::new(InternerInner { - arena: Default::default(), - strings: init.iter().copied().collect(), - })) + fn prefill(init: &[&'static str], extra: &[&'static str]) -> Self { + let strings = FxIndexSet::from_iter(init.iter().copied().chain(extra.iter().copied())); + assert_eq!( + strings.len(), + init.len() + extra.len(), + "`init` or `extra` contain duplicate symbols", + ); + Interner(Lock::new(InternerInner { arena: Default::default(), strings })) } #[inline] @@ -2760,9 +2765,9 @@ impl Symbol { self != kw::Empty && self != kw::Underscore && !self.is_path_segment_keyword() } - /// Is this symbol was interned in compiler's `symbols!` macro - pub fn is_preinterned(self) -> bool { - self.as_u32() < PREINTERNED_SYMBOLS_COUNT + /// Was this symbol predefined in the compiler's `symbols!` macro + pub fn is_predefined(self) -> bool { + self.as_u32() < PREDEFINED_SYMBOLS_COUNT } } diff --git a/compiler/rustc_span/src/symbol/tests.rs b/compiler/rustc_span/src/symbol/tests.rs index c6aa7627b2b5..660d0d7179af 100644 --- a/compiler/rustc_span/src/symbol/tests.rs +++ b/compiler/rustc_span/src/symbol/tests.rs @@ -3,7 +3,7 @@ use crate::create_default_session_globals_then; #[test] fn interner_tests() { - let i = Interner::prefill(&[]); + let i = Interner::prefill(&[], &[]); // first one is zero: assert_eq!(i.intern("dog"), Symbol::new(0)); // re-use gets the same entry: diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs index c9b15151a2cb..cc33974cc627 100644 --- a/compiler/rustc_symbol_mangling/src/lib.rs +++ b/compiler/rustc_symbol_mangling/src/lib.rs @@ -89,7 +89,6 @@ // tidy-alphabetical-start #![allow(internal_features)] -#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(let_chains)] diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 99d44bcd7eb8..f310aa655002 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -368,7 +368,7 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> { } fn print_region(&mut self, region: ty::Region<'_>) -> Result<(), PrintError> { - let i = match *region { + let i = match region.kind() { // Erased lifetimes use the index 0, for a // shorter mangling of `L_`. ty::ReErased => 0, @@ -615,7 +615,7 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> { cx.print_def_path(trait_ref.def_id, trait_ref.args)?; } ty::ExistentialPredicate::Projection(projection) => { - let name = cx.tcx.associated_item(projection.def_id).name; + let name = cx.tcx.associated_item(projection.def_id).name(); cx.push("p"); cx.push_ident(name.as_str()); match projection.term.unpack() { @@ -776,7 +776,7 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> { self.push_disambiguator( disambiguated_field.disambiguator as u64, ); - self.push_ident(field_name.unwrap_or(kw::Empty).as_str()); + self.push_ident(field_name.unwrap().as_str()); field.print(self)?; } @@ -858,7 +858,8 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> { | DefPathData::GlobalAsm | DefPathData::Impl | DefPathData::MacroNs(_) - | DefPathData::LifetimeNs(_) => { + | DefPathData::LifetimeNs(_) + | DefPathData::AnonAssocTy => { bug!("symbol_names: unexpected DefPathData: {:?}", disambiguated_data.data) } }; diff --git a/compiler/rustc_target/src/callconv/loongarch.rs b/compiler/rustc_target/src/callconv/loongarch.rs index 209d7483e612..c779720f97b9 100644 --- a/compiler/rustc_target/src/callconv/loongarch.rs +++ b/compiler/rustc_target/src/callconv/loongarch.rs @@ -1,6 +1,6 @@ use rustc_abi::{ - BackendRepr, ExternAbi, FieldsShape, HasDataLayout, Primitive, Reg, RegKind, Size, - TyAbiInterface, TyAndLayout, Variants, + BackendRepr, FieldsShape, HasDataLayout, Primitive, Reg, RegKind, Size, TyAbiInterface, + TyAndLayout, Variants, }; use crate::callconv::{ArgAbi, ArgExtension, CastTarget, FnAbi, PassMode, Uniform}; @@ -364,15 +364,11 @@ where } } -pub(crate) fn compute_rust_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>, abi: ExternAbi) +pub(crate) fn compute_rust_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>) where Ty: TyAbiInterface<'a, C> + Copy, C: HasDataLayout + HasTargetSpec, { - if abi == ExternAbi::RustIntrinsic { - return; - } - let grlen = cx.data_layout().pointer_size.bits(); for arg in fn_abi.args.iter_mut() { diff --git a/compiler/rustc_target/src/callconv/mod.rs b/compiler/rustc_target/src/callconv/mod.rs index 55e39d093e23..7ecc46cc69db 100644 --- a/compiler/rustc_target/src/callconv/mod.rs +++ b/compiler/rustc_target/src/callconv/mod.rs @@ -717,16 +717,16 @@ impl<'a, Ty> FnAbi<'a, Ty> { } } - pub fn adjust_for_rust_abi(&mut self, cx: &C, abi: ExternAbi) + pub fn adjust_for_rust_abi(&mut self, cx: &C) where Ty: TyAbiInterface<'a, C> + Copy, C: HasDataLayout + HasTargetSpec, { let spec = cx.target_spec(); match &*spec.arch { - "x86" => x86::compute_rust_abi_info(cx, self, abi), - "riscv32" | "riscv64" => riscv::compute_rust_abi_info(cx, self, abi), - "loongarch64" => loongarch::compute_rust_abi_info(cx, self, abi), + "x86" => x86::compute_rust_abi_info(cx, self), + "riscv32" | "riscv64" => riscv::compute_rust_abi_info(cx, self), + "loongarch64" => loongarch::compute_rust_abi_info(cx, self), "aarch64" => aarch64::compute_rust_abi_info(cx, self), _ => {} }; @@ -850,10 +850,7 @@ impl<'a, Ty> FnAbi<'a, Ty> { // // Note that the intrinsic ABI is exempt here as those are not // real functions anyway, and the backend expects very specific types. - if abi != ExternAbi::RustIntrinsic - && spec.simd_types_indirect - && !can_pass_simd_directly(arg) - { + if spec.simd_types_indirect && !can_pass_simd_directly(arg) { arg.make_indirect(); } } diff --git a/compiler/rustc_target/src/callconv/riscv.rs b/compiler/rustc_target/src/callconv/riscv.rs index 7368e225efa7..cd1d3cd1eee0 100644 --- a/compiler/rustc_target/src/callconv/riscv.rs +++ b/compiler/rustc_target/src/callconv/riscv.rs @@ -5,8 +5,8 @@ // https://github.com/llvm/llvm-project/blob/8e780252a7284be45cf1ba224cabd884847e8e92/clang/lib/CodeGen/TargetInfo.cpp#L9311-L9773 use rustc_abi::{ - BackendRepr, ExternAbi, FieldsShape, HasDataLayout, Primitive, Reg, RegKind, Size, - TyAbiInterface, TyAndLayout, Variants, + BackendRepr, FieldsShape, HasDataLayout, Primitive, Reg, RegKind, Size, TyAbiInterface, + TyAndLayout, Variants, }; use crate::callconv::{ArgAbi, ArgExtension, CastTarget, FnAbi, PassMode, Uniform}; @@ -370,15 +370,11 @@ where } } -pub(crate) fn compute_rust_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>, abi: ExternAbi) +pub(crate) fn compute_rust_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>) where Ty: TyAbiInterface<'a, C> + Copy, C: HasDataLayout + HasTargetSpec, { - if abi == ExternAbi::RustIntrinsic { - return; - } - let xlen = cx.data_layout().pointer_size.bits(); for arg in fn_abi.args.iter_mut() { diff --git a/compiler/rustc_target/src/callconv/x86.rs b/compiler/rustc_target/src/callconv/x86.rs index ba3c14062112..8328f818f9b8 100644 --- a/compiler/rustc_target/src/callconv/x86.rs +++ b/compiler/rustc_target/src/callconv/x86.rs @@ -1,6 +1,6 @@ use rustc_abi::{ - AddressSpace, Align, BackendRepr, ExternAbi, HasDataLayout, Primitive, Reg, RegKind, - TyAbiInterface, TyAndLayout, + AddressSpace, Align, BackendRepr, HasDataLayout, Primitive, Reg, RegKind, TyAbiInterface, + TyAndLayout, }; use crate::callconv::{ArgAttribute, FnAbi, PassMode}; @@ -193,7 +193,7 @@ pub(crate) fn fill_inregs<'a, Ty, C>( } } -pub(crate) fn compute_rust_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>, abi: ExternAbi) +pub(crate) fn compute_rust_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>) where Ty: TyAbiInterface<'a, C> + Copy, C: HasDataLayout + HasTargetSpec, @@ -201,10 +201,7 @@ where // Avoid returning floats in x87 registers on x86 as loading and storing from x87 // registers will quiet signalling NaNs. Also avoid using SSE registers since they // are not always available (depending on target features). - if !fn_abi.ret.is_ignore() - // Intrinsics themselves are not "real" functions, so theres no need to change their ABIs. - && abi != ExternAbi::RustIntrinsic - { + if !fn_abi.ret.is_ignore() { let has_float = match fn_abi.ret.layout.backend_repr { BackendRepr::Scalar(s) => matches!(s.primitive(), Primitive::Float(_)), BackendRepr::ScalarPair(s1, s2) => { diff --git a/compiler/rustc_target/src/spec/base/lynxos178.rs b/compiler/rustc_target/src/spec/base/lynxos178.rs new file mode 100644 index 000000000000..b9434ff5faaf --- /dev/null +++ b/compiler/rustc_target/src/spec/base/lynxos178.rs @@ -0,0 +1,31 @@ +use std::borrow::Cow; + +use crate::spec::{ + PanicStrategy, RelocModel, RelroLevel, SplitDebuginfo, StackProbeType, TargetOptions, cvs, +}; + +pub(crate) fn opts() -> TargetOptions { + TargetOptions { + os: "lynxos178".into(), + dynamic_linking: false, + families: cvs!["unix"], + position_independent_executables: false, + static_position_independent_executables: false, + relro_level: RelroLevel::Full, + has_thread_local: false, + crt_static_respected: true, + panic_strategy: PanicStrategy::Abort, + linker: Some(Cow::Borrowed("x86_64-lynx-lynxos178-gcc")), + no_default_libraries: false, + eh_frame_header: false, // GNU ld (GNU Binutils) 2.37.50 does not support --eh-frame-hdr + max_atomic_width: Some(64), + supported_split_debuginfo: Cow::Borrowed(&[ + SplitDebuginfo::Packed, + SplitDebuginfo::Unpacked, + SplitDebuginfo::Off, + ]), + relocation_model: RelocModel::Static, + stack_probes: StackProbeType::Inline, + ..Default::default() + } +} diff --git a/compiler/rustc_target/src/spec/base/mod.rs b/compiler/rustc_target/src/spec/base/mod.rs index 71b6528c2dd1..b368d93f0072 100644 --- a/compiler/rustc_target/src/spec/base/mod.rs +++ b/compiler/rustc_target/src/spec/base/mod.rs @@ -19,6 +19,7 @@ pub(crate) mod linux_musl; pub(crate) mod linux_ohos; pub(crate) mod linux_uclibc; pub(crate) mod linux_wasm; +pub(crate) mod lynxos178; pub(crate) mod msvc; pub(crate) mod netbsd; pub(crate) mod nto_qnx; diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 79f73ef28b36..3c769dad630a 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -2078,6 +2078,7 @@ supported_targets! { ("riscv32imafc-unknown-nuttx-elf", riscv32imafc_unknown_nuttx_elf), ("riscv64imac-unknown-nuttx-elf", riscv64imac_unknown_nuttx_elf), ("riscv64gc-unknown-nuttx-elf", riscv64gc_unknown_nuttx_elf), + ("x86_64-lynx-lynxos178", x86_64_lynx_lynxos178), ("x86_64-pc-cygwin", x86_64_pc_cygwin), } @@ -2962,14 +2963,9 @@ impl Target { pub fn is_abi_supported(&self, abi: ExternAbi) -> bool { use ExternAbi::*; match abi { - Rust - | C { .. } - | System { .. } - | RustIntrinsic - | RustCall - | Unadjusted - | Cdecl { .. } - | RustCold => true, + Rust | C { .. } | System { .. } | RustCall | Unadjusted | Cdecl { .. } | RustCold => { + true + } EfiApi => { ["arm", "aarch64", "riscv32", "riscv64", "x86", "x86_64"].contains(&&self.arch[..]) } diff --git a/compiler/rustc_target/src/spec/targets/riscv64_linux_android.rs b/compiler/rustc_target/src/spec/targets/riscv64_linux_android.rs index 9f02ed4bcbe9..b9176c939f80 100644 --- a/compiler/rustc_target/src/spec/targets/riscv64_linux_android.rs +++ b/compiler/rustc_target/src/spec/targets/riscv64_linux_android.rs @@ -19,7 +19,7 @@ pub(crate) fn target() -> Target { options: TargetOptions { code_model: Some(CodeModel::Medium), cpu: "generic-rv64".into(), - features: "+m,+a,+f,+d,+c,+zicsr,+zifencei,+zba,+zbb,+zbs,+v".into(), + features: "+m,+a,+f,+d,+c,+b,+v,+zicsr,+zifencei".into(), llvm_abiname: "lp64d".into(), supported_sanitizers: SanitizerSet::ADDRESS, max_atomic_width: Some(64), diff --git a/compiler/rustc_target/src/spec/targets/x86_64_lynx_lynxos178.rs b/compiler/rustc_target/src/spec/targets/x86_64_lynx_lynxos178.rs new file mode 100644 index 000000000000..654ae7c9c5be --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/x86_64_lynx_lynxos178.rs @@ -0,0 +1,34 @@ +use crate::spec::{SanitizerSet, StackProbeType, Target, base}; + +pub(crate) fn target() -> Target { + let mut base = base::lynxos178::opts(); + base.cpu = "x86-64".into(); + base.plt_by_default = false; + base.max_atomic_width = Some(64); + base.stack_probes = StackProbeType::Inline; + base.static_position_independent_executables = false; + base.supported_sanitizers = SanitizerSet::ADDRESS + | SanitizerSet::CFI + | SanitizerSet::KCFI + | SanitizerSet::DATAFLOW + | SanitizerSet::LEAK + | SanitizerSet::MEMORY + | SanitizerSet::SAFESTACK + | SanitizerSet::THREAD; + base.supports_xray = true; + + Target { + llvm_target: "x86_64-unknown-unknown-gnu".into(), + metadata: crate::spec::TargetMetadata { + description: Some("LynxOS-178".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), + }, + pointer_width: 64, + data_layout: + "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128".into(), + arch: "x86_64".into(), + options: base, + } +} diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index b4ec1879fed5..aeace6a40c72 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -491,7 +491,8 @@ const MIPS_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ static RISCV_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ // tidy-alphabetical-start ("a", Stable, &["zaamo", "zalrsc"]), - ("c", Stable, &[]), + ("b", Unstable(sym::riscv_target_feature), &["zba", "zbb", "zbs"]), + ("c", Stable, &["zca"]), ("d", Unstable(sym::riscv_target_feature), &["f"]), ("e", Unstable(sym::riscv_target_feature), &[]), ("f", Unstable(sym::riscv_target_feature), &["zicsr"]), @@ -520,17 +521,25 @@ static RISCV_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("zbkc", Stable, &[]), ("zbkx", Stable, &[]), ("zbs", Stable, &[]), + ("zca", Unstable(sym::riscv_target_feature), &[]), + ("zcb", Unstable(sym::riscv_target_feature), &["zca"]), + ("zcmop", Unstable(sym::riscv_target_feature), &["zca"]), ("zdinx", Unstable(sym::riscv_target_feature), &["zfinx"]), + ("zfa", Unstable(sym::riscv_target_feature), &["f"]), ("zfh", Unstable(sym::riscv_target_feature), &["zfhmin"]), ("zfhmin", Unstable(sym::riscv_target_feature), &["f"]), ("zfinx", Unstable(sym::riscv_target_feature), &["zicsr"]), ("zhinx", Unstable(sym::riscv_target_feature), &["zhinxmin"]), ("zhinxmin", Unstable(sym::riscv_target_feature), &["zfinx"]), + ("zicboz", Unstable(sym::riscv_target_feature), &[]), ("zicntr", Unstable(sym::riscv_target_feature), &["zicsr"]), + ("zicond", Unstable(sym::riscv_target_feature), &[]), ("zicsr", Unstable(sym::riscv_target_feature), &[]), ("zifencei", Unstable(sym::riscv_target_feature), &[]), + ("zihintntl", Unstable(sym::riscv_target_feature), &[]), ("zihintpause", Unstable(sym::riscv_target_feature), &[]), ("zihpm", Unstable(sym::riscv_target_feature), &["zicsr"]), + ("zimop", Unstable(sym::riscv_target_feature), &[]), ("zk", Stable, &["zkn", "zkr", "zkt"]), ("zkn", Stable, &["zbkb", "zbkc", "zbkx", "zkne", "zknd", "zknh"]), ("zknd", Stable, &[]), @@ -541,6 +550,7 @@ static RISCV_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("zksed", Stable, &[]), ("zksh", Stable, &[]), ("zkt", Stable, &[]), + ("ztso", Unstable(sym::riscv_target_feature), &[]), ("zvbb", Unstable(sym::riscv_target_feature), &["zvkb"]), ("zvbc", Unstable(sym::riscv_target_feature), &["zve64x"]), ("zve32f", Unstable(sym::riscv_target_feature), &["zve32x", "f"]), diff --git a/compiler/rustc_trait_selection/messages.ftl b/compiler/rustc_trait_selection/messages.ftl index 05bbb42fb7c6..74e38f525c8e 100644 --- a/compiler/rustc_trait_selection/messages.ftl +++ b/compiler/rustc_trait_selection/messages.ftl @@ -268,8 +268,8 @@ trait_selection_oc_type_compat = type not compatible with trait trait_selection_opaque_captures_lifetime = hidden type for `{$opaque_ty}` captures lifetime that does not appear in bounds .label = opaque type defined here trait_selection_opaque_type_non_generic_param = - expected generic {$kind} parameter, found `{$ty}` - .label = {STREQ($ty, "'static") -> + expected generic {$kind} parameter, found `{$arg}` + .label = {STREQ($arg, "'static") -> [true] cannot use static lifetime; use a bound lifetime instead or remove the lifetime parameter from the opaque type *[other] this generic parameter must be used with a generic {$kind} parameter } diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs index 40f8af1f6913..fdd547448f00 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs @@ -2334,13 +2334,13 @@ impl<'tcx> ObligationCause<'tcx> { subdiags: Vec, ) -> ObligationCauseFailureCode { match self.code() { - ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Fn, .. } => { + ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Fn { .. }, .. } => { ObligationCauseFailureCode::MethodCompat { span, subdiags } } - ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Type, .. } => { + ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Type { .. }, .. } => { ObligationCauseFailureCode::TypeCompat { span, subdiags } } - ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Const, .. } => { + ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Const { .. }, .. } => { ObligationCauseFailureCode::ConstCompat { span, subdiags } } ObligationCauseCode::BlockTailExpression(.., hir::MatchSource::TryDesugar(_)) => { @@ -2398,13 +2398,13 @@ impl<'tcx> ObligationCause<'tcx> { fn as_requirement_str(&self) -> &'static str { match self.code() { - ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Fn, .. } => { + ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Fn { .. }, .. } => { "method type is compatible with trait" } - ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Type, .. } => { + ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Type { .. }, .. } => { "associated type is compatible with trait" } - ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Const, .. } => { + ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Const { .. }, .. } => { "const is compatible with trait" } ObligationCauseCode::MainFunctionType => "`main` function has the correct type", @@ -2422,9 +2422,13 @@ pub struct ObligationCauseAsDiagArg<'tcx>(pub ObligationCause<'tcx>); impl IntoDiagArg for ObligationCauseAsDiagArg<'_> { fn into_diag_arg(self, _: &mut Option) -> rustc_errors::DiagArgValue { let kind = match self.0.code() { - ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Fn, .. } => "method_compat", - ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Type, .. } => "type_compat", - ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Const, .. } => { + ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Fn { .. }, .. } => { + "method_compat" + } + ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Type { .. }, .. } => { + "type_compat" + } + ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Const { .. }, .. } => { "const_compat" } ObligationCauseCode::MainFunctionType => "fn_main_correct_type", diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs index 3559c660ee27..eaa06d8e8b0a 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs @@ -6,7 +6,7 @@ use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{Visitor, VisitorExt, walk_ty}; use rustc_hir::{ self as hir, AmbigArg, GenericBound, GenericParam, GenericParamKind, Item, ItemKind, Lifetime, - LifetimeName, LifetimeParamKind, MissingLifetimeKind, Node, TyKind, + LifetimeKind, LifetimeParamKind, MissingLifetimeKind, Node, TyKind, }; use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor}; use rustc_span::def_id::LocalDefId; @@ -165,7 +165,7 @@ pub fn suggest_new_region_bound( if let Some(span) = opaque.bounds.iter().find_map(|arg| match arg { GenericBound::Outlives(Lifetime { - res: LifetimeName::Static, ident, .. + kind: LifetimeKind::Static, ident, .. }) => Some(ident.span), _ => None, }) { @@ -253,7 +253,7 @@ pub fn suggest_new_region_bound( } } TyKind::TraitObject(_, lt) => { - if let LifetimeName::ImplicitObjectLifetimeDefault = lt.res { + if let LifetimeKind::ImplicitObjectLifetimeDefault = lt.kind { err.span_suggestion_verbose( fn_return.span.shrink_to_hi(), format!("{declare} the trait object {captures}, {explicit}",), @@ -414,7 +414,7 @@ pub struct HirTraitObjectVisitor<'a>(pub &'a mut Vec, pub DefId); impl<'a, 'tcx> Visitor<'tcx> for HirTraitObjectVisitor<'a> { fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx, AmbigArg>) { if let TyKind::TraitObject(poly_trait_refs, lifetime_ptr) = t.kind - && let Lifetime { res: LifetimeName::ImplicitObjectLifetimeDefault, .. } = + && let Lifetime { kind: LifetimeKind::ImplicitObjectLifetimeDefault, .. } = lifetime_ptr.pointer() { for ptr in poly_trait_refs { diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs index 742059228510..b66bd2c6ab78 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs @@ -98,7 +98,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { let assoc_item = self.tcx().associated_item(trait_item_def_id); let mut visitor = TypeParamSpanVisitor { tcx: self.tcx(), types: vec![] }; match assoc_item.kind { - ty::AssocKind::Fn => { + ty::AssocKind::Fn { .. } => { if let Some(hir_id) = assoc_item.def_id.as_local().map(|id| self.tcx().local_def_id_to_hir_id(id)) { diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/util.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/util.rs index 683b5b528c6e..4a71ab4e06a3 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/util.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/util.rs @@ -42,7 +42,7 @@ pub fn find_param_with_region<'tcx>( anon_region: Region<'tcx>, replace_region: Region<'tcx>, ) -> Option> { - let (id, kind) = match *anon_region { + let (id, kind) = match anon_region.kind() { ty::ReLateParam(late_param) => (late_param.scope, late_param.kind), ty::ReEarlyParam(ebr) => { let region_def = tcx.generics_of(generic_param_scope).region_param(ebr, tcx).def_id; @@ -158,6 +158,6 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { && self .tcx() .opt_associated_item(scope_def_id.to_def_id()) - .is_some_and(|i| i.fn_has_self_parameter) + .is_some_and(|i| i.is_method()) } } diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs index 5583deda99a4..be508c8cee13 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs @@ -782,8 +782,8 @@ fn foo(&self) -> Self::T { String::new() } let methods: Vec<(Span, String)> = items .in_definition_order() .filter(|item| { - ty::AssocKind::Fn == item.kind - && Some(item.name) != current_method_ident + item.is_fn() + && Some(item.name()) != current_method_ident && !tcx.is_doc_hidden(item.def_id) }) .filter_map(|item| { diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs index c7f0a88f951a..1cf1ac5403f0 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs @@ -299,7 +299,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { self.tcx.param_env(generic_param_scope), terr, ); - match (*sub, *sup) { + match (sub.kind(), sup.kind()) { (ty::RePlaceholder(_), ty::RePlaceholder(_)) => {} (ty::RePlaceholder(_), _) => { note_and_explain_region( @@ -391,7 +391,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { }) } infer::RelateParamBound(span, ty, opt_span) => { - let prefix = match *sub { + let prefix = match sub.kind() { ty::ReStatic => note_and_explain::PrefixKind::TypeSatisfy, _ => note_and_explain::PrefixKind::TypeOutlive, }; @@ -850,14 +850,14 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { add_lt_suggs: &mut Vec<(Span, String)>, ) -> String { struct LifetimeReplaceVisitor<'a> { - needle: hir::LifetimeName, + needle: hir::LifetimeKind, new_lt: &'a str, add_lt_suggs: &'a mut Vec<(Span, String)>, } impl<'hir> hir::intravisit::Visitor<'hir> for LifetimeReplaceVisitor<'_> { fn visit_lifetime(&mut self, lt: &'hir hir::Lifetime) { - if lt.res == self.needle { + if lt.kind == self.needle { self.add_lt_suggs.push(lt.suggestion(self.new_lt)); } } @@ -894,7 +894,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { }; let mut visitor = LifetimeReplaceVisitor { - needle: hir::LifetimeName::Param(lifetime_def_id), + needle: hir::LifetimeKind::Param(lifetime_def_id), add_lt_suggs, new_lt: &new_lt, }; @@ -967,7 +967,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { format!("...so that the {}", sup_trace.cause.as_requirement_str()), ); - err.note_expected_found(&"", sup_expected, &"", sup_found); + err.note_expected_found("", sup_expected, "", sup_found); return if sub_region.is_error() | sup_region.is_error() { err.delay_as_bug() } else { @@ -1017,7 +1017,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { infer::BoundRegion(_, br, infer::AssocTypeProjection(def_id)) => format!( " for lifetime parameter {}in trait containing associated type `{}`", br_string(br), - self.tcx.associated_item(def_id).name + self.tcx.associated_item(def_id).name() ), infer::RegionParameterDefinition(_, name) => { format!(" for lifetime parameter `{name}`") @@ -1048,7 +1048,7 @@ pub(super) fn note_and_explain_region<'tcx>( suffix: &str, alt_span: Option, ) { - let (description, span) = match *region { + let (description, span) = match region.kind() { ty::ReEarlyParam(_) | ty::ReLateParam(_) | ty::RePlaceholder(_) | ty::ReStatic => { msg_span_from_named_region(tcx, generic_param_scope, region, alt_span) } @@ -1085,7 +1085,7 @@ fn msg_span_from_named_region<'tcx>( region: ty::Region<'tcx>, alt_span: Option, ) -> (String, Option) { - match *region { + match region.kind() { ty::ReEarlyParam(br) => { let param_def_id = tcx.generics_of(generic_param_scope).region_param(br, tcx).def_id; let span = tcx.def_span(param_def_id); @@ -1185,7 +1185,7 @@ pub fn unexpected_hidden_region_diagnostic<'a, 'tcx>( }); // Explain the region we are capturing. - match *hidden_region { + match hidden_region.kind() { ty::ReEarlyParam(_) | ty::ReLateParam(_) | ty::ReStatic => { // Assuming regionck succeeded (*), we ought to always be // capturing *some* region from the fn header, and hence it diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs index 59c93db9c8ff..54b50851b74d 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs @@ -348,11 +348,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { && let None = self.tainted_by_errors() { let (verb, noun) = match self.tcx.associated_item(item_id).kind { - ty::AssocKind::Const => ("refer to the", "constant"), - ty::AssocKind::Fn => ("call", "function"), + ty::AssocKind::Const { .. } => ("refer to the", "constant"), + ty::AssocKind::Fn { .. } => ("call", "function"), // This is already covered by E0223, but this following single match // arm doesn't hurt here. - ty::AssocKind::Type => ("refer to the", "type"), + ty::AssocKind::Type { .. } => ("refer to the", "type"), }; // Replace the more general E0283 with a more specific error diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index bc45fc11e9bb..5648021f6134 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -2,6 +2,7 @@ use core::ops::ControlFlow; use std::borrow::Cow; use std::path::PathBuf; +use rustc_abi::ExternAbi; use rustc_ast::TraitObjectSyntax; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::unord::UnordSet; @@ -2799,32 +2800,57 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } // Note any argument mismatches - let given_ty = params.skip_binder(); + let ty::Tuple(given) = *params.skip_binder().kind() else { + return; + }; + let expected_ty = trait_pred.skip_binder().trait_ref.args.type_at(1); - if let ty::Tuple(given) = given_ty.kind() - && let ty::Tuple(expected) = expected_ty.kind() - { - if expected.len() != given.len() { - // Note number of types that were expected and given - err.note( - format!( - "expected a closure taking {} argument{}, but one taking {} argument{} was given", - given.len(), - pluralize!(given.len()), - expected.len(), - pluralize!(expected.len()), - ) - ); - } else if !self.same_type_modulo_infer(given_ty, expected_ty) { - // Print type mismatch - let (expected_args, given_args) = self.cmp(given_ty, expected_ty); - err.note_expected_found( - &"a closure with arguments", - expected_args, - &"a closure with arguments", - given_args, - ); - } + let ty::Tuple(expected) = *expected_ty.kind() else { + return; + }; + + if expected.len() != given.len() { + // Note number of types that were expected and given + err.note(format!( + "expected a closure taking {} argument{}, but one taking {} argument{} was given", + given.len(), + pluralize!(given.len()), + expected.len(), + pluralize!(expected.len()), + )); + return; + } + + let given_ty = Ty::new_fn_ptr( + self.tcx, + params.rebind(self.tcx.mk_fn_sig( + given, + self.tcx.types.unit, + false, + hir::Safety::Safe, + ExternAbi::Rust, + )), + ); + let expected_ty = Ty::new_fn_ptr( + self.tcx, + trait_pred.rebind(self.tcx.mk_fn_sig( + expected, + self.tcx.types.unit, + false, + hir::Safety::Safe, + ExternAbi::Rust, + )), + ); + + if !self.same_type_modulo_infer(given_ty, expected_ty) { + // Print type mismatch + let (expected_args, given_args) = self.cmp(expected_ty, given_ty); + err.note_expected_found( + "a closure with signature", + expected_args, + "a closure with signature", + given_args, + ); } } diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index 38fcba4ea625..7d95a7b3fed2 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -1988,7 +1988,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { { let closure: Vec<_> = self .tcx - .fn_arg_names(fn_def_id) + .fn_arg_idents(fn_def_id) .iter() .enumerate() .map(|(i, ident)| { @@ -2112,16 +2112,20 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { trait_ref: DefId, ) { if let Some(assoc_item) = self.tcx.opt_associated_item(item_def_id) { - if let ty::AssocKind::Const | ty::AssocKind::Type = assoc_item.kind { + if let ty::AssocKind::Const { .. } | ty::AssocKind::Type { .. } = assoc_item.kind { err.note(format!( "{}s cannot be accessed directly on a `trait`, they can only be \ accessed through a specific `impl`", - self.tcx.def_kind_descr(assoc_item.kind.as_def_kind(), item_def_id) + self.tcx.def_kind_descr(assoc_item.as_def_kind(), item_def_id) )); err.span_suggestion( span, "use the fully qualified path to an implementation", - format!("::{}", self.tcx.def_path_str(trait_ref), assoc_item.name), + format!( + "::{}", + self.tcx.def_path_str(trait_ref), + assoc_item.name() + ), Applicability::HasPlaceholders, ); } @@ -3018,12 +3022,23 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { [] => span_bug!(ty.span, "trait object with no traits: {ty:?}"), }; let needs_parens = traits.len() != 1; - err.span_suggestion_verbose( - span, - "you can use `impl Trait` as the argument type", - "impl ", - Applicability::MaybeIncorrect, - ); + // Don't recommend impl Trait as a closure argument + if let Some(hir_id) = hir_id + && matches!( + self.tcx.parent_hir_node(hir_id), + hir::Node::Item(hir::Item { + kind: hir::ItemKind::Fn { .. }, + .. + }) + ) + { + err.span_suggestion_verbose( + span, + "you can use `impl Trait` as the argument type", + "impl ", + Applicability::MaybeIncorrect, + ); + } let sugg = if !needs_parens { vec![(span.shrink_to_lo(), format!("&{kw}"))] } else { @@ -5397,10 +5412,10 @@ fn point_at_assoc_type_restriction( ); } if let Some(new) = - tcx.associated_items(data.impl_or_alias_def_id).find_by_name_and_kind( + tcx.associated_items(data.impl_or_alias_def_id).find_by_ident_and_kind( tcx, Ident::with_dummy_span(name), - ty::AssocKind::Type, + ty::AssocTag::Type, data.impl_or_alias_def_id, ) { diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs index 9f7bfe5101ab..756d9a57b935 100644 --- a/compiler/rustc_trait_selection/src/errors.rs +++ b/compiler/rustc_trait_selection/src/errors.rs @@ -4,7 +4,7 @@ use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; use rustc_errors::codes::*; use rustc_errors::{ Applicability, Diag, DiagCtxtHandle, DiagMessage, DiagStyledString, Diagnostic, - EmissionGuarantee, IntoDiagArg, Level, MultiSpan, SubdiagMessageOp, Subdiagnostic, + EmissionGuarantee, IntoDiagArg, Level, MultiSpan, Subdiagnostic, }; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; @@ -107,11 +107,7 @@ pub enum AdjustSignatureBorrow { } impl Subdiagnostic for AdjustSignatureBorrow { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { match self { AdjustSignatureBorrow::Borrow { to_borrow } => { diag.arg("len", to_borrow.len()); @@ -381,11 +377,7 @@ pub enum RegionOriginNote<'a> { } impl Subdiagnostic for RegionOriginNote<'_> { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { let mut label_or_note = |span, msg: DiagMessage| { let sub_count = diag.children.iter().filter(|d| d.span.is_dummy()).count(); let expanded_sub_count = diag.children.iter().filter(|d| !d.span.is_dummy()).count(); @@ -415,7 +407,7 @@ impl Subdiagnostic for RegionOriginNote<'_> { label_or_note(span, fluent::trait_selection_subtype); diag.arg("requirement", requirement); - diag.note_expected_found(&"", expected, &"", found); + diag.note_expected_found("", expected, "", found); } RegionOriginNote::WithRequirement { span, requirement, expected_found: None } => { // FIXME: this really should be handled at some earlier stage. Our @@ -446,11 +438,7 @@ pub enum LifetimeMismatchLabels { } impl Subdiagnostic for LifetimeMismatchLabels { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { match self { LifetimeMismatchLabels::InRet { param_span, ret_span, span, label_var1 } => { diag.span_label(param_span, fluent::trait_selection_declared_different); @@ -495,11 +483,7 @@ pub struct AddLifetimeParamsSuggestion<'a> { } impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { let mut mk_suggestion = || { let Some(anon_reg) = self.tcx.is_suitable_region(self.generic_param_scope, self.sub) else { @@ -689,11 +673,7 @@ pub struct IntroducesStaticBecauseUnmetLifetimeReq { } impl Subdiagnostic for IntroducesStaticBecauseUnmetLifetimeReq { - fn add_to_diag_with>( - mut self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { + fn add_to_diag(mut self, diag: &mut Diag<'_, G>) { self.unmet_requirements .push_span_label(self.binding_span, fluent::trait_selection_msl_introduces_static); diag.span_note(self.unmet_requirements, fluent::trait_selection_msl_unmet_req); @@ -1008,17 +988,13 @@ pub struct ConsiderBorrowingParamHelp { } impl Subdiagnostic for ConsiderBorrowingParamHelp { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { let mut type_param_span: MultiSpan = self.spans.clone().into(); for &span in &self.spans { // Seems like we can't call f() here as Into is required type_param_span.push_span_label(span, fluent::trait_selection_tid_consider_borrowing); } - let msg = f(diag, fluent::trait_selection_tid_param_help.into()); + let msg = diag.eagerly_translate(fluent::trait_selection_tid_param_help); diag.span_help(type_param_span, msg); } } @@ -1053,18 +1029,14 @@ pub struct DynTraitConstraintSuggestion { } impl Subdiagnostic for DynTraitConstraintSuggestion { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { let mut multi_span: MultiSpan = vec![self.span].into(); multi_span.push_span_label(self.span, fluent::trait_selection_dtcs_has_lifetime_req_label); multi_span .push_span_label(self.ident.span, fluent::trait_selection_dtcs_introduces_requirement); - let msg = f(diag, fluent::trait_selection_dtcs_has_req_note.into()); + let msg = diag.eagerly_translate(fluent::trait_selection_dtcs_has_req_note); diag.span_note(multi_span, msg); - let msg = f(diag, fluent::trait_selection_dtcs_suggestion.into()); + let msg = diag.eagerly_translate(fluent::trait_selection_dtcs_suggestion); diag.span_suggestion_verbose( self.span.shrink_to_hi(), msg, @@ -1101,11 +1073,7 @@ pub struct ReqIntroducedLocations { } impl Subdiagnostic for ReqIntroducedLocations { - fn add_to_diag_with>( - mut self, - diag: &mut Diag<'_, G>, - f: &F, - ) { + fn add_to_diag(mut self, diag: &mut Diag<'_, G>) { for sp in self.spans { self.span.push_span_label(sp, fluent::trait_selection_ril_introduced_here); } @@ -1114,7 +1082,7 @@ impl Subdiagnostic for ReqIntroducedLocations { self.span.push_span_label(self.fn_decl_span, fluent::trait_selection_ril_introduced_by); } self.span.push_span_label(self.cause_span, fluent::trait_selection_ril_because_of); - let msg = f(diag, fluent::trait_selection_ril_static_introduced_by.into()); + let msg = diag.eagerly_translate(fluent::trait_selection_ril_static_introduced_by); diag.span_note(self.span, msg); } } @@ -1513,13 +1481,9 @@ pub struct SuggestTuplePatternMany { } impl Subdiagnostic for SuggestTuplePatternMany { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { diag.arg("path", self.path); - let message = f(diag, crate::fluent_generated::trait_selection_stp_wrap_many.into()); + let message = diag.eagerly_translate(fluent::trait_selection_stp_wrap_many); diag.multipart_suggestions( message, self.compatible_variants.into_iter().map(|variant| { @@ -1752,11 +1716,7 @@ pub struct AddPreciseCapturingAndParams { } impl Subdiagnostic for AddPreciseCapturingAndParams { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { diag.arg("new_lifetime", self.new_lifetime); diag.multipart_suggestion_verbose( fluent::trait_selection_precise_capturing_new_but_apit, @@ -1896,11 +1856,7 @@ pub struct AddPreciseCapturingForOvercapture { } impl Subdiagnostic for AddPreciseCapturingForOvercapture { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { let applicability = if self.apit_spans.is_empty() { Applicability::MachineApplicable } else { @@ -1926,7 +1882,7 @@ impl Subdiagnostic for AddPreciseCapturingForOvercapture { #[derive(Diagnostic)] #[diag(trait_selection_opaque_type_non_generic_param, code = E0792)] pub(crate) struct NonGenericOpaqueTypeParam<'a, 'tcx> { - pub ty: GenericArg<'tcx>, + pub arg: GenericArg<'tcx>, pub kind: &'a str, #[primary_span] pub span: Span, diff --git a/compiler/rustc_trait_selection/src/errors/note_and_explain.rs b/compiler/rustc_trait_selection/src/errors/note_and_explain.rs index 46622246a178..84e7686fdd3f 100644 --- a/compiler/rustc_trait_selection/src/errors/note_and_explain.rs +++ b/compiler/rustc_trait_selection/src/errors/note_and_explain.rs @@ -1,4 +1,4 @@ -use rustc_errors::{Diag, EmissionGuarantee, IntoDiagArg, SubdiagMessageOp, Subdiagnostic}; +use rustc_errors::{Diag, EmissionGuarantee, IntoDiagArg, Subdiagnostic}; use rustc_hir::def_id::LocalDefId; use rustc_middle::bug; use rustc_middle::ty::{self, TyCtxt}; @@ -20,7 +20,7 @@ impl<'a> DescriptionCtx<'a> { region: ty::Region<'tcx>, alt_span: Option, ) -> Option { - let (span, kind, arg) = match *region { + let (span, kind, arg) = match region.kind() { ty::ReEarlyParam(br) => { let scope = tcx .parent(tcx.generics_of(generic_param_scope).region_param(br, tcx).def_id) @@ -162,17 +162,13 @@ impl RegionExplanation<'_> { } impl Subdiagnostic for RegionExplanation<'_> { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { diag.arg("pref_kind", self.prefix); diag.arg("suff_kind", self.suffix); diag.arg("desc_kind", self.desc.kind); diag.arg("desc_arg", self.desc.arg); - let msg = f(diag, fluent::trait_selection_region_explanation.into()); + let msg = diag.eagerly_translate(fluent::trait_selection_region_explanation); if let Some(span) = self.desc.span { diag.span_note(span, msg); } else { diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs index c7b8f0631962..cce67b066dde 100644 --- a/compiler/rustc_trait_selection/src/opaque_types.rs +++ b/compiler/rustc_trait_selection/src/opaque_types.rs @@ -46,7 +46,7 @@ pub fn check_opaque_type_parameter_valid<'tcx>( GenericArgKind::Lifetime(lt) => match defining_scope_kind { DefiningScopeKind::HirTypeck => continue, DefiningScopeKind::MirBorrowck => { - matches!(*lt, ty::ReEarlyParam(_) | ty::ReLateParam(_)) + matches!(lt.kind(), ty::ReEarlyParam(_) | ty::ReLateParam(_)) || (lt.is_static() && opaque_env.param_equal_static(i)) } }, @@ -70,7 +70,7 @@ pub fn check_opaque_type_parameter_valid<'tcx>( opaque_env.param_is_error(i)?; return Err(infcx.dcx().emit_err(NonGenericOpaqueTypeParam { - ty: arg, + arg, kind, span, param_span: tcx.def_span(opaque_param.def_id), diff --git a/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs index 3a939df25e07..d8dcd12aecb9 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs @@ -13,9 +13,9 @@ use rustc_next_trait_solver::solve::{GenerateProofTree, SolverDelegateEvalExt as use rustc_type_ir::solve::NoSolution; use tracing::{instrument, trace}; -use crate::solve::Certainty; use crate::solve::delegate::SolverDelegate; use crate::solve::inspect::{self, ProofTreeInferCtxtExt, ProofTreeVisitor}; +use crate::solve::{Certainty, deeply_normalize_for_diagnostics}; use crate::traits::{FulfillmentError, FulfillmentErrorCode, wf}; pub(super) fn fulfillment_error_for_no_solution<'tcx>( @@ -151,7 +151,7 @@ fn find_best_leaf_obligation<'tcx>( // // We should probably fix the visitor to not do so instead, as this also // means the leaf obligation may be incorrect. - infcx + let obligation = infcx .fudge_inference_if_ok(|| { infcx .visit_proof_tree( @@ -161,7 +161,8 @@ fn find_best_leaf_obligation<'tcx>( .break_value() .ok_or(()) }) - .unwrap_or(obligation) + .unwrap_or(obligation); + deeply_normalize_for_diagnostics(infcx, obligation.param_env, obligation) } struct BestObligation<'tcx> { @@ -291,6 +292,40 @@ impl<'tcx> BestObligation<'tcx> { } } + /// When a higher-ranked projection goal fails, check that the corresponding + /// higher-ranked trait goal holds or not. This is because the process of + /// instantiating and then re-canonicalizing the binder of the projection goal + /// forces us to be unable to see that the leak check failed in the nested + /// `NormalizesTo` goal, so we don't fall back to the rigid projection check + /// that should catch when a projection goal fails due to an unsatisfied trait + /// goal. + fn detect_trait_error_in_higher_ranked_projection( + &mut self, + goal: &inspect::InspectGoal<'_, 'tcx>, + ) -> ControlFlow> { + let tcx = goal.infcx().tcx; + if let Some(projection_clause) = goal.goal().predicate.as_projection_clause() + && !projection_clause.bound_vars().is_empty() + { + let pred = projection_clause.map_bound(|proj| proj.projection_term.trait_ref(tcx)); + let obligation = Obligation::new( + tcx, + self.obligation.cause.clone(), + goal.goal().param_env, + deeply_normalize_for_diagnostics(goal.infcx(), goal.goal().param_env, pred), + ); + self.with_derived_obligation(obligation, |this| { + goal.infcx().visit_proof_tree_at_depth( + goal.goal().with(tcx, pred), + goal.depth() + 1, + this, + ) + }) + } else { + ControlFlow::Continue(()) + } + } + /// It is likely that `NormalizesTo` failed without any applicable candidates /// because the alias is not well-formed. /// @@ -360,7 +395,8 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> { (true, Ok(Certainty::Maybe(MaybeCause::Ambiguity))) | (false, Err(_)) => {} _ => return ControlFlow::Continue(()), } - let pred_kind = goal.goal().predicate.kind(); + + let pred = goal.goal().predicate; let candidates = self.non_trivial_candidates(goal); let candidate = match candidates.as_slice() { @@ -374,7 +410,7 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> { source: CandidateSource::Impl(impl_def_id), result: _, } = candidate.kind() - && goal.infcx().tcx.do_not_recommend_impl(impl_def_id) + && tcx.do_not_recommend_impl(impl_def_id) { trace!("#[do_not_recommend] -> exit"); return ControlFlow::Break(self.obligation.clone()); @@ -382,12 +418,12 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> { // FIXME: Also, what about considering >1 layer up the stack? May be necessary // for normalizes-to. - let child_mode = match pred_kind.skip_binder() { - ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => { - ChildMode::Trait(pred_kind.rebind(pred)) + let child_mode = match pred.kind().skip_binder() { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) => { + ChildMode::Trait(pred.kind().rebind(trait_pred)) } - ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(pred)) => { - ChildMode::Host(pred_kind.rebind(pred)) + ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(host_pred)) => { + ChildMode::Host(pred.kind().rebind(host_pred)) } ty::PredicateKind::NormalizesTo(normalizes_to) if matches!( @@ -395,7 +431,7 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> { ty::AliasTermKind::ProjectionTy | ty::AliasTermKind::ProjectionConst ) => { - ChildMode::Trait(pred_kind.rebind(ty::TraitPredicate { + ChildMode::Trait(pred.kind().rebind(ty::TraitPredicate { trait_ref: normalizes_to.alias.trait_ref(tcx), polarity: ty::PredicatePolarity::Positive, })) @@ -429,10 +465,12 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> { for nested_goal in nested_goals { trace!(nested_goal = ?(nested_goal.goal(), nested_goal.source(), nested_goal.result())); + let nested_pred = nested_goal.goal().predicate; + let make_obligation = |cause| Obligation { cause, param_env: nested_goal.goal().param_env, - predicate: nested_goal.goal().predicate, + predicate: nested_pred, recursion_depth: self.obligation.recursion_depth + 1, }; @@ -482,30 +520,21 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> { // alias-relate may fail because the lhs or rhs can't be normalized, // and therefore is treated as rigid. - if let Some(ty::PredicateKind::AliasRelate(lhs, rhs, _)) = pred_kind.no_bound_vars() { - if let Some(obligation) = goal - .infcx() - .visit_proof_tree_at_depth( - goal.goal().with(goal.infcx().tcx, ty::ClauseKind::WellFormed(lhs.into())), - goal.depth() + 1, - self, - ) - .break_value() - { - return ControlFlow::Break(obligation); - } else if let Some(obligation) = goal - .infcx() - .visit_proof_tree_at_depth( - goal.goal().with(goal.infcx().tcx, ty::ClauseKind::WellFormed(rhs.into())), - goal.depth() + 1, - self, - ) - .break_value() - { - return ControlFlow::Break(obligation); - } + if let Some(ty::PredicateKind::AliasRelate(lhs, rhs, _)) = pred.kind().no_bound_vars() { + goal.infcx().visit_proof_tree_at_depth( + goal.goal().with(tcx, ty::ClauseKind::WellFormed(lhs.into())), + goal.depth() + 1, + self, + )?; + goal.infcx().visit_proof_tree_at_depth( + goal.goal().with(tcx, ty::ClauseKind::WellFormed(rhs.into())), + goal.depth() + 1, + self, + )?; } + self.detect_trait_error_in_higher_ranked_projection(goal)?; + ControlFlow::Break(self.obligation.clone()) } } diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs index 48a05ad29fbd..24b87000e32b 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs @@ -292,7 +292,7 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> { inspect::ProbeStep::NestedProbe(ref probe) => { match probe.kind { // These never assemble candidates for the goal we're trying to solve. - inspect::ProbeKind::UpcastProjectionCompatibility + inspect::ProbeKind::ProjectionCompatibility | inspect::ProbeKind::ShadowedEnvProbing => continue, inspect::ProbeKind::NormalizedSelfTyAssembly @@ -314,8 +314,10 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> { } match probe.kind { - inspect::ProbeKind::UpcastProjectionCompatibility - | inspect::ProbeKind::ShadowedEnvProbing => bug!(), + inspect::ProbeKind::ProjectionCompatibility + | inspect::ProbeKind::ShadowedEnvProbing => { + bug!() + } inspect::ProbeKind::NormalizedSelfTyAssembly | inspect::ProbeKind::UnsizeAssembly => {} diff --git a/compiler/rustc_trait_selection/src/solve/normalize.rs b/compiler/rustc_trait_selection/src/solve/normalize.rs index 232357dc71a0..79fb044a67f8 100644 --- a/compiler/rustc_trait_selection/src/solve/normalize.rs +++ b/compiler/rustc_trait_selection/src/solve/normalize.rs @@ -253,20 +253,28 @@ impl<'tcx> TypeFolder> for DeeplyNormalizeForDiagnosticsFolder<'_, } fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - deeply_normalize_with_skipped_universes( - self.at, - ty, - vec![None; ty.outer_exclusive_binder().as_usize()], - ) - .unwrap_or_else(|_: Vec>| ty.super_fold_with(self)) + let infcx = self.at.infcx; + infcx + .commit_if_ok(|_| { + deeply_normalize_with_skipped_universes( + self.at, + ty, + vec![None; ty.outer_exclusive_binder().as_usize()], + ) + }) + .unwrap_or_else(|_: Vec>| ty.super_fold_with(self)) } fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { - deeply_normalize_with_skipped_universes( - self.at, - ct, - vec![None; ct.outer_exclusive_binder().as_usize()], - ) - .unwrap_or_else(|_: Vec>| ct.super_fold_with(self)) + let infcx = self.at.infcx; + infcx + .commit_if_ok(|_| { + deeply_normalize_with_skipped_universes( + self.at, + ct, + vec![None; ct.outer_exclusive_binder().as_usize()], + ) + }) + .unwrap_or_else(|_: Vec>| ct.super_fold_with(self)) } } diff --git a/compiler/rustc_trait_selection/src/solve/select.rs b/compiler/rustc_trait_selection/src/solve/select.rs index 4437fc5b0295..4fdaf740287b 100644 --- a/compiler/rustc_trait_selection/src/solve/select.rs +++ b/compiler/rustc_trait_selection/src/solve/select.rs @@ -177,7 +177,7 @@ fn to_selection<'tcx>( }, ProbeKind::NormalizedSelfTyAssembly | ProbeKind::UnsizeAssembly - | ProbeKind::UpcastProjectionCompatibility + | ProbeKind::ProjectionCompatibility | ProbeKind::OpaqueTypeStorageLookup { result: _ } | ProbeKind::Root { result: _ } | ProbeKind::ShadowedEnvProbing diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index 1fca2f4da7ee..02521c9453d9 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -382,7 +382,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { for (new_region, old_region) in iter::zip(new_args.regions(), old_args.regions()) { - match (*new_region, *old_region) { + match (new_region.kind(), old_region.kind()) { // If both predicates have an `ReBound` (a HRTB) in the // same spot, we do nothing. (ty::ReBound(_, _), ty::ReBound(_, _)) => {} diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index bcc247ba53c2..93c7dae9c5be 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -537,7 +537,7 @@ fn plug_infer_with_placeholders<'tcx>( } fn visit_region(&mut self, r: ty::Region<'tcx>) { - if let ty::ReVar(vid) = *r { + if let ty::ReVar(vid) = r.kind() { let r = self .infcx .inner diff --git a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs index fa6bbf1d6e57..519394685a8e 100644 --- a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs +++ b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs @@ -188,7 +188,7 @@ fn bounds_reference_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SmallVec<[Span tcx.associated_items(trait_def_id) .in_definition_order() // We're only looking at associated type bounds - .filter(|item| item.kind == ty::AssocKind::Type) + .filter(|item| item.is_type()) // Ignore GATs with `Self: Sized` .filter(|item| !tcx.generics_require_sized_self(item.def_id)) .flat_map(|item| tcx.explicit_item_bounds(item.def_id).iter_identity_copied()) @@ -298,31 +298,33 @@ pub fn dyn_compatibility_violations_for_assoc_item( match item.kind { // Associated consts are never dyn-compatible, as they can't have `where` bounds yet at all, // and associated const bounds in trait objects aren't a thing yet either. - ty::AssocKind::Const => { - vec![DynCompatibilityViolation::AssocConst(item.name, item.ident(tcx).span)] + ty::AssocKind::Const { name } => { + vec![DynCompatibilityViolation::AssocConst(name, item.ident(tcx).span)] } - ty::AssocKind::Fn => virtual_call_violations_for_method(tcx, trait_def_id, item) - .into_iter() - .map(|v| { - let node = tcx.hir_get_if_local(item.def_id); - // Get an accurate span depending on the violation. - let span = match (&v, node) { - (MethodViolationCode::ReferencesSelfInput(Some(span)), _) => *span, - (MethodViolationCode::UndispatchableReceiver(Some(span)), _) => *span, - (MethodViolationCode::ReferencesImplTraitInTrait(span), _) => *span, - (MethodViolationCode::ReferencesSelfOutput, Some(node)) => { - node.fn_decl().map_or(item.ident(tcx).span, |decl| decl.output.span()) - } - _ => item.ident(tcx).span, - }; + ty::AssocKind::Fn { name, .. } => { + virtual_call_violations_for_method(tcx, trait_def_id, item) + .into_iter() + .map(|v| { + let node = tcx.hir_get_if_local(item.def_id); + // Get an accurate span depending on the violation. + let span = match (&v, node) { + (MethodViolationCode::ReferencesSelfInput(Some(span)), _) => *span, + (MethodViolationCode::UndispatchableReceiver(Some(span)), _) => *span, + (MethodViolationCode::ReferencesImplTraitInTrait(span), _) => *span, + (MethodViolationCode::ReferencesSelfOutput, Some(node)) => { + node.fn_decl().map_or(item.ident(tcx).span, |decl| decl.output.span()) + } + _ => item.ident(tcx).span, + }; - DynCompatibilityViolation::Method(item.name, v, span) - }) - .collect(), + DynCompatibilityViolation::Method(name, v, span) + }) + .collect() + } // Associated types can only be dyn-compatible if they have `Self: Sized` bounds. - ty::AssocKind::Type => { + ty::AssocKind::Type { .. } => { if !tcx.generics_of(item.def_id).is_own_empty() && !item.is_impl_trait_in_trait() { - vec![DynCompatibilityViolation::GAT(item.name, item.ident(tcx).span)] + vec![DynCompatibilityViolation::GAT(item.name(), item.ident(tcx).span)] } else { // We will permit associated types if they are explicitly mentioned in the trait object. // We can't check this here, as here we only check if it is guaranteed to not be possible. @@ -344,7 +346,7 @@ fn virtual_call_violations_for_method<'tcx>( let sig = tcx.fn_sig(method.def_id).instantiate_identity(); // The method's first parameter must be named `self` - if !method.fn_has_self_parameter { + if !method.is_method() { let sugg = if let Some(hir::Node::TraitItem(hir::TraitItem { generics, kind: hir::TraitItemKind::Fn(sig, _), @@ -797,7 +799,7 @@ impl<'tcx> TypeFolder> for EraseEscapingBoundRegions<'tcx> { } fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { - if let ty::ReBound(debruijn, _) = *r + if let ty::ReBound(debruijn, _) = r.kind() && debruijn < self.binder { r diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index e98a240a53f5..1b76d48e4310 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -24,10 +24,10 @@ use super::{ }; use crate::error_reporting::InferCtxtErrorExt; use crate::infer::{InferCtxt, TyOrConstInferVar}; -use crate::traits::EvaluateConstErr; use crate::traits::normalize::normalize_with_depth_to; use crate::traits::project::{PolyProjectionObligation, ProjectionCacheKeyExt as _}; use crate::traits::query::evaluate_obligation::InferCtxtExt; +use crate::traits::{EvaluateConstErr, sizedness_fast_path}; pub(crate) type PendingPredicateObligations<'tcx> = ThinVec>; @@ -335,6 +335,10 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { let infcx = self.selcx.infcx; + if sizedness_fast_path(infcx.tcx, obligation.predicate) { + return ProcessResult::Changed(thin_vec::thin_vec![]); + } + if obligation.predicate.has_aliases() { let mut obligations = PredicateObligations::new(); let predicate = normalize_with_depth_to( diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index de337710b5ef..0987c5b42d88 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -65,8 +65,8 @@ pub use self::specialize::{ pub use self::structural_normalize::StructurallyNormalizeExt; pub use self::util::{ BoundVarReplacer, PlaceholderReplacer, elaborate, expand_trait_aliases, impl_item_is_final, - supertrait_def_ids, supertraits, transitive_bounds_that_define_assoc_item, upcast_choices, - with_replaced_escaping_bound_vars, + sizedness_fast_path, supertrait_def_ids, supertraits, transitive_bounds_that_define_assoc_item, + upcast_choices, with_replaced_escaping_bound_vars, }; use crate::error_reporting::InferCtxtErrorExt; use crate::infer::outlives::env::OutlivesEnvironment; @@ -643,7 +643,7 @@ fn replace_param_and_infer_args_with_placeholder<'tcx>( ) -> GenericArgsRef<'tcx> { struct ReplaceParamAndInferWithPlaceholder<'tcx> { tcx: TyCtxt<'tcx>, - idx: u32, + idx: ty::BoundVar, } impl<'tcx> TypeFolder> for ReplaceParamAndInferWithPlaceholder<'tcx> { @@ -653,19 +653,13 @@ fn replace_param_and_infer_args_with_placeholder<'tcx>( fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { if let ty::Infer(_) = t.kind() { - let idx = { - let idx = self.idx; - self.idx += 1; - idx - }; + let idx = self.idx; + self.idx += 1; Ty::new_placeholder( self.tcx, ty::PlaceholderType { universe: ty::UniverseIndex::ROOT, - bound: ty::BoundTy { - var: ty::BoundVar::from_u32(idx), - kind: ty::BoundTyKind::Anon, - }, + bound: ty::BoundTy { var: idx, kind: ty::BoundTyKind::Anon }, }, ) } else { @@ -675,16 +669,11 @@ fn replace_param_and_infer_args_with_placeholder<'tcx>( fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> { if let ty::ConstKind::Infer(_) = c.kind() { + let idx = self.idx; + self.idx += 1; ty::Const::new_placeholder( self.tcx, - ty::PlaceholderConst { - universe: ty::UniverseIndex::ROOT, - bound: ty::BoundVar::from_u32({ - let idx = self.idx; - self.idx += 1; - idx - }), - }, + ty::PlaceholderConst { universe: ty::UniverseIndex::ROOT, bound: idx }, ) } else { c.super_fold_with(self) @@ -692,7 +681,7 @@ fn replace_param_and_infer_args_with_placeholder<'tcx>( } } - args.fold_with(&mut ReplaceParamAndInferWithPlaceholder { tcx, idx: 0 }) + args.fold_with(&mut ReplaceParamAndInferWithPlaceholder { tcx, idx: ty::BoundVar::ZERO }) } /// Normalizes the predicates and checks whether they hold in an empty environment. If this diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 349569d750e0..0dce504903ca 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -669,30 +669,11 @@ fn project<'cx, 'tcx>( match candidates { ProjectionCandidateSet::Single(candidate) => { - Ok(Projected::Progress(confirm_candidate(selcx, obligation, candidate))) + confirm_candidate(selcx, obligation, candidate) } ProjectionCandidateSet::None => { let tcx = selcx.tcx(); - let term = match tcx.def_kind(obligation.predicate.def_id) { - DefKind::AssocTy => Ty::new_projection_from_args( - tcx, - obligation.predicate.def_id, - obligation.predicate.args, - ) - .into(), - DefKind::AssocConst => ty::Const::new_unevaluated( - tcx, - ty::UnevaluatedConst::new( - obligation.predicate.def_id, - obligation.predicate.args, - ), - ) - .into(), - kind => { - bug!("unknown projection def-id: {}", kind.descr(obligation.predicate.def_id)) - } - }; - + let term = obligation.predicate.to_term(tcx); Ok(Projected::NoProgress(term)) } // Error occurred while trying to processing impls. @@ -1244,18 +1225,16 @@ fn confirm_candidate<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionTermObligation<'tcx>, candidate: ProjectionCandidate<'tcx>, -) -> Progress<'tcx> { +) -> Result, ProjectionError<'tcx>> { debug!(?obligation, ?candidate, "confirm_candidate"); - let mut progress = match candidate { + let mut result = match candidate { ProjectionCandidate::ParamEnv(poly_projection) - | ProjectionCandidate::Object(poly_projection) => { - confirm_param_env_candidate(selcx, obligation, poly_projection, false) - } - - ProjectionCandidate::TraitDef(poly_projection) => { - confirm_param_env_candidate(selcx, obligation, poly_projection, true) - } - + | ProjectionCandidate::Object(poly_projection) => Ok(Projected::Progress( + confirm_param_env_candidate(selcx, obligation, poly_projection, false), + )), + ProjectionCandidate::TraitDef(poly_projection) => Ok(Projected::Progress( + confirm_param_env_candidate(selcx, obligation, poly_projection, true), + )), ProjectionCandidate::Select(impl_source) => { confirm_select_candidate(selcx, obligation, impl_source) } @@ -1266,23 +1245,26 @@ fn confirm_candidate<'cx, 'tcx>( // with new region variables, we need to resolve them to existing variables // when possible for this to work. See `auto-trait-projection-recursion.rs` // for a case where this matters. - if progress.term.has_infer_regions() { + if let Ok(Projected::Progress(progress)) = &mut result + && progress.term.has_infer_regions() + { progress.term = progress.term.fold_with(&mut OpportunisticRegionResolver::new(selcx.infcx)); } - progress + + result } fn confirm_select_candidate<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionTermObligation<'tcx>, impl_source: Selection<'tcx>, -) -> Progress<'tcx> { +) -> Result, ProjectionError<'tcx>> { match impl_source { ImplSource::UserDefined(data) => confirm_impl_candidate(selcx, obligation, data), ImplSource::Builtin(BuiltinImplSource::Misc | BuiltinImplSource::Trivial, data) => { let tcx = selcx.tcx(); let trait_def_id = obligation.predicate.trait_def_id(tcx); - if tcx.is_lang_item(trait_def_id, LangItem::Coroutine) { + let progress = if tcx.is_lang_item(trait_def_id, LangItem::Coroutine) { confirm_coroutine_candidate(selcx, obligation, data) } else if tcx.is_lang_item(trait_def_id, LangItem::Future) { confirm_future_candidate(selcx, obligation, data) @@ -1304,7 +1286,8 @@ fn confirm_select_candidate<'cx, 'tcx>( confirm_async_fn_kind_helper_candidate(selcx, obligation, data) } else { confirm_builtin_candidate(selcx, obligation, data) - } + }; + Ok(Projected::Progress(progress)) } ImplSource::Builtin(BuiltinImplSource::Object { .. }, _) | ImplSource::Param(..) @@ -1410,7 +1393,7 @@ fn confirm_future_candidate<'cx, 'tcx>( coroutine_sig, ); - debug_assert_eq!(tcx.associated_item(obligation.predicate.def_id).name, sym::Output); + debug_assert_eq!(tcx.associated_item(obligation.predicate.def_id).name(), sym::Output); let predicate = ty::ProjectionPredicate { projection_term: ty::AliasTerm::new_from_args( @@ -1456,7 +1439,7 @@ fn confirm_iterator_candidate<'cx, 'tcx>( gen_sig, ); - debug_assert_eq!(tcx.associated_item(obligation.predicate.def_id).name, sym::Item); + debug_assert_eq!(tcx.associated_item(obligation.predicate.def_id).name(), sym::Item); let predicate = ty::ProjectionPredicate { projection_term: ty::AliasTerm::new_from_args( @@ -1502,7 +1485,7 @@ fn confirm_async_iterator_candidate<'cx, 'tcx>( gen_sig, ); - debug_assert_eq!(tcx.associated_item(obligation.predicate.def_id).name, sym::Item); + debug_assert_eq!(tcx.associated_item(obligation.predicate.def_id).name(), sym::Item); let ty::Adt(_poll_adt, args) = *yield_ty.kind() else { bug!(); @@ -2000,7 +1983,7 @@ fn confirm_impl_candidate<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionTermObligation<'tcx>, impl_impl_source: ImplSourceUserDefinedData<'tcx, PredicateObligation<'tcx>>, -) -> Progress<'tcx> { +) -> Result, ProjectionError<'tcx>> { let tcx = selcx.tcx(); let ImplSourceUserDefinedData { impl_def_id, args, mut nested } = impl_impl_source; @@ -2011,19 +1994,34 @@ fn confirm_impl_candidate<'cx, 'tcx>( let param_env = obligation.param_env; let assoc_ty = match specialization_graph::assoc_def(tcx, impl_def_id, assoc_item_id) { Ok(assoc_ty) => assoc_ty, - Err(guar) => return Progress::error(tcx, guar), + Err(guar) => return Ok(Projected::Progress(Progress::error(tcx, guar))), }; + + // This means that the impl is missing a definition for the + // associated type. This is either because the associate item + // has impossible-to-satisfy predicates (since those were + // allowed in ), + // or because the impl is literally missing the definition. if !assoc_ty.item.defaultness(tcx).has_value() { - // This means that the impl is missing a definition for the - // associated type. This error will be reported by the type - // checker method `check_impl_items_against_trait`, so here we - // just return Error. debug!( "confirm_impl_candidate: no associated type {:?} for {:?}", - assoc_ty.item.name, obligation.predicate + assoc_ty.item.name(), + obligation.predicate ); - return Progress { term: Ty::new_misc_error(tcx).into(), obligations: nested }; + if tcx.impl_self_is_guaranteed_unsized(impl_def_id) { + // We treat this projection as rigid here, which is represented via + // `Projected::NoProgress`. This will ensure that the projection is + // checked for well-formedness, and it's either satisfied by a trivial + // where clause in its env or it results in an error. + return Ok(Projected::NoProgress(obligation.predicate.to_term(tcx))); + } else { + return Ok(Projected::Progress(Progress { + term: Ty::new_misc_error(tcx).into(), + obligations: nested, + })); + } } + // If we're trying to normalize ` as X>::A` using //`impl X for Vec { type A = Box; }`, then: // @@ -2033,6 +2031,7 @@ fn confirm_impl_candidate<'cx, 'tcx>( let args = obligation.predicate.args.rebase_onto(tcx, trait_def_id, args); let args = translate_args(selcx.infcx, param_env, impl_def_id, args, assoc_ty.defining_node); let is_const = matches!(tcx.def_kind(assoc_ty.item.def_id), DefKind::AssocConst); + let term: ty::EarlyBinder<'tcx, ty::Term<'tcx>> = if is_const { let did = assoc_ty.item.def_id; let identity_args = crate::traits::GenericArgs::identity_for_item(tcx, did); @@ -2041,7 +2040,8 @@ fn confirm_impl_candidate<'cx, 'tcx>( } else { tcx.type_of(assoc_ty.item.def_id).map_bound(|ty| ty.into()) }; - if !tcx.check_args_compatible(assoc_ty.item.def_id, args) { + + let progress = if !tcx.check_args_compatible(assoc_ty.item.def_id, args) { let err = Ty::new_error_with_message( tcx, obligation.cause.span, @@ -2051,7 +2051,8 @@ fn confirm_impl_candidate<'cx, 'tcx>( } else { assoc_ty_own_obligations(selcx, obligation, &mut nested); Progress { term: term.instantiate(tcx, args), obligations: nested } - } + }; + Ok(Projected::Progress(progress)) } // Get obligations corresponding to the predicates from the where-clause of the diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index 5dbb4382fd1b..507932699c7c 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -144,7 +144,7 @@ impl<'tcx> TypeVisitor> for MaxEscapingBoundVarVisitor { #[inline] fn visit_region(&mut self, r: ty::Region<'tcx>) { - match *r { + match r.kind() { ty::ReBound(debruijn, _) if debruijn > self.outer_index => { self.escaping = self.escaping.max(debruijn.as_usize() - self.outer_index.as_usize()); diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs index 4f9e2e79d624..87fc532adaf6 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs @@ -1,4 +1,3 @@ -use rustc_hir::LangItem; use rustc_infer::traits::Obligation; use rustc_middle::traits::ObligationCause; use rustc_middle::traits::query::NoSolution; @@ -7,7 +6,7 @@ use rustc_middle::ty::{self, ParamEnvAnd, TyCtxt}; use rustc_span::Span; use crate::infer::canonical::{CanonicalQueryInput, CanonicalQueryResponse}; -use crate::traits::ObligationCtxt; +use crate::traits::{ObligationCtxt, sizedness_fast_path}; impl<'tcx> super::QueryTypeOp<'tcx> for ProvePredicate<'tcx> { type QueryResponse = (); @@ -16,15 +15,7 @@ impl<'tcx> super::QueryTypeOp<'tcx> for ProvePredicate<'tcx> { tcx: TyCtxt<'tcx>, key: &ParamEnvAnd<'tcx, Self>, ) -> Option { - // Proving Sized, very often on "obviously sized" types like - // `&T`, accounts for about 60% percentage of the predicates - // we have to prove. No need to canonicalize and all that for - // such cases. - if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_ref)) = - key.value.predicate.kind().skip_binder() - && tcx.is_lang_item(trait_ref.def_id(), LangItem::Sized) - && trait_ref.self_ty().is_trivially_sized(tcx) - { + if sizedness_fast_path(tcx, key.value.predicate) { return Some(()); } diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 2cb7d2d89313..d71d1e9ae0fa 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -317,7 +317,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.cause.clone(), obligation.recursion_depth + 1, obligation.param_env, - obligation.predicate.rebind(trait_ref), + trait_ref, ) }; @@ -343,7 +343,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.cause.clone(), obligation.recursion_depth + 1, obligation.param_env, - obligation.predicate.rebind(outlives), + outlives, ) }; @@ -404,7 +404,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - let predicate = obligation.predicate.skip_binder(); + let predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate); let mut assume = predicate.trait_ref.args.const_at(2); // FIXME(mgca): We should shallowly normalize this. @@ -594,9 +594,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // Associated types that require `Self: Sized` do not show up in the built-in // implementation of `Trait for dyn Trait`, and can be dropped here. .filter(|item| !tcx.generics_require_sized_self(item.def_id)) - .filter_map( - |item| if item.kind == ty::AssocKind::Type { Some(item.def_id) } else { None }, - ) + .filter_map(|item| if item.is_type() { Some(item.def_id) } else { None }) .collect(); for assoc_type in assoc_types { @@ -1090,26 +1088,36 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { { // See `assemble_candidates_for_unsizing` for more info. // We already checked the compatibility of auto traits within `assemble_candidates_for_unsizing`. - let iter = data_a - .principal() - .filter(|_| { - // optionally drop the principal, if we're unsizing to no principal - data_b.principal().is_some() - }) - .map(|b| b.map_bound(ty::ExistentialPredicate::Trait)) - .into_iter() - .chain( + let existential_predicates = if data_b.principal().is_some() { + tcx.mk_poly_existential_predicates_from_iter( data_a - .projection_bounds() - .map(|b| b.map_bound(ty::ExistentialPredicate::Projection)), + .principal() + .map(|b| b.map_bound(ty::ExistentialPredicate::Trait)) + .into_iter() + .chain( + data_a + .projection_bounds() + .map(|b| b.map_bound(ty::ExistentialPredicate::Projection)), + ) + .chain( + data_b + .auto_traits() + .map(ty::ExistentialPredicate::AutoTrait) + .map(ty::Binder::dummy), + ), ) - .chain( + } else { + // If we're unsizing to a dyn type that has no principal, then drop + // the principal and projections from the type. We use the auto traits + // from the RHS type since as we noted that we've checked for auto + // trait compatibility during unsizing. + tcx.mk_poly_existential_predicates_from_iter( data_b .auto_traits() .map(ty::ExistentialPredicate::AutoTrait) .map(ty::Binder::dummy), - ); - let existential_predicates = tcx.mk_poly_existential_predicates_from_iter(iter); + ) + }; let source_trait = Ty::new_dynamic(tcx, existential_predicates, r_b, dyn_a); // Require that the traits involved in this upcast are **equal**; diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 56ff46e89e70..4d88a23250a7 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -49,7 +49,9 @@ use crate::infer::{InferCtxt, InferOk, TypeFreshener}; use crate::solve::InferCtxtSelectExt as _; use crate::traits::normalize::{normalize_with_depth, normalize_with_depth_to}; use crate::traits::project::{ProjectAndUnifyResult, ProjectionCacheKeyExt}; -use crate::traits::{EvaluateConstErr, ProjectionCacheKey, Unimplemented, effects}; +use crate::traits::{ + EvaluateConstErr, ProjectionCacheKey, Unimplemented, effects, sizedness_fast_path, +}; mod _match; mod candidate_assembly; @@ -603,6 +605,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { None => self.check_recursion_limit(&obligation, &obligation)?, } + if sizedness_fast_path(self.tcx(), obligation.predicate) { + return Ok(EvaluatedToOk); + } + ensure_sufficient_stack(|| { let bound_predicate = obligation.predicate.kind(); match bound_predicate.skip_binder() { diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index 15f5cf916a48..035fd38c48aa 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -1,6 +1,7 @@ use std::collections::{BTreeMap, VecDeque}; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; +use rustc_hir::LangItem; use rustc_hir::def_id::DefId; use rustc_infer::infer::InferCtxt; pub use rustc_infer::traits::util::*; @@ -289,7 +290,7 @@ impl<'tcx> TypeFolder> for BoundVarReplacer<'_, 'tcx> { } fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { - match *r { + match r.kind() { ty::ReBound(debruijn, _) if debruijn.as_usize() >= self.current_index.as_usize() + self.universe_indices.len() => @@ -407,7 +408,7 @@ impl<'tcx> TypeFolder> for PlaceholderReplacer<'_, 'tcx> { } fn fold_region(&mut self, r0: ty::Region<'tcx>) -> ty::Region<'tcx> { - let r1 = match *r0 { + let r1 = match r0.kind() { ty::ReVar(vid) => self .infcx .inner @@ -417,7 +418,7 @@ impl<'tcx> TypeFolder> for PlaceholderReplacer<'_, 'tcx> { _ => r0, }; - let r2 = match *r1 { + let r2 = match r1.kind() { ty::RePlaceholder(p) => { let replace_var = self.mapped_regions.get(&p); match replace_var { @@ -504,3 +505,21 @@ impl<'tcx> TypeFolder> for PlaceholderReplacer<'_, 'tcx> { } } } + +pub fn sizedness_fast_path<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tcx>) -> bool { + // Proving `Sized` very often on "obviously sized" types like `&T`, accounts for about 60% + // percentage of the predicates we have to prove. No need to canonicalize and all that for + // such cases. + if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_ref)) = + predicate.kind().skip_binder() + { + if tcx.is_lang_item(trait_ref.def_id(), LangItem::Sized) + && trait_ref.self_ty().is_trivially_sized(tcx) + { + debug!("fast path -- trivial sizedness"); + return true; + } + } + + false +} diff --git a/compiler/rustc_trait_selection/src/traits/vtable.rs b/compiler/rustc_trait_selection/src/traits/vtable.rs index 165174c0bcc1..3565c11249ad 100644 --- a/compiler/rustc_trait_selection/src/traits/vtable.rs +++ b/compiler/rustc_trait_selection/src/traits/vtable.rs @@ -197,10 +197,8 @@ fn own_existential_vtable_entries_iter( tcx: TyCtxt<'_>, trait_def_id: DefId, ) -> impl Iterator { - let trait_methods = tcx - .associated_items(trait_def_id) - .in_definition_order() - .filter(|item| item.kind == ty::AssocKind::Fn); + let trait_methods = + tcx.associated_items(trait_def_id).in_definition_order().filter(|item| item.is_fn()); // Now list each method's DefId (for within its trait). let own_entries = trait_methods.filter_map(move |&trait_method| { diff --git a/compiler/rustc_traits/src/codegen.rs b/compiler/rustc_traits/src/codegen.rs index 4a889abfc28f..88f02d16c7d5 100644 --- a/compiler/rustc_traits/src/codegen.rs +++ b/compiler/rustc_traits/src/codegen.rs @@ -6,11 +6,11 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::bug; use rustc_middle::traits::CodegenObligationError; -use rustc_middle::ty::{self, PseudoCanonicalInput, TyCtxt, TypeVisitableExt}; +use rustc_middle::ty::{self, PseudoCanonicalInput, TyCtxt, TypeVisitableExt, Upcast}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::traits::{ ImplSource, Obligation, ObligationCause, ObligationCtxt, ScrubbedTraitError, SelectionContext, - Unimplemented, + Unimplemented, sizedness_fast_path, }; use tracing::debug; @@ -34,6 +34,13 @@ pub(crate) fn codegen_select_candidate<'tcx>( let (infcx, param_env) = tcx.infer_ctxt().ignoring_regions().build_with_typing_env(typing_env); let mut selcx = SelectionContext::new(&infcx); + if sizedness_fast_path(tcx, trait_ref.upcast(tcx)) { + return Ok(&*tcx.arena.alloc(ImplSource::Builtin( + ty::solve::BuiltinImplSource::Trivial, + Default::default(), + ))); + } + let obligation_cause = ObligationCause::dummy(); let obligation = Obligation::new(tcx, obligation_cause, param_env, trait_ref); diff --git a/compiler/rustc_traits/src/evaluate_obligation.rs b/compiler/rustc_traits/src/evaluate_obligation.rs index c9ad096c6e9d..7771db855d70 100644 --- a/compiler/rustc_traits/src/evaluate_obligation.rs +++ b/compiler/rustc_traits/src/evaluate_obligation.rs @@ -5,6 +5,7 @@ use rustc_span::DUMMY_SP; use rustc_trait_selection::traits::query::CanonicalPredicateGoal; use rustc_trait_selection::traits::{ EvaluationResult, Obligation, ObligationCause, OverflowError, SelectionContext, TraitQueryMode, + sizedness_fast_path, }; use tracing::debug; @@ -23,6 +24,10 @@ fn evaluate_obligation<'tcx>( debug!("evaluate_obligation: goal={:#?}", goal); let ParamEnvAnd { param_env, value: predicate } = goal; + if sizedness_fast_path(tcx, predicate) { + return Ok(EvaluationResult::EvaluatedToOk); + } + let mut selcx = SelectionContext::with_query_mode(infcx, TraitQueryMode::Canonical); let obligation = Obligation::new(tcx, ObligationCause::dummy(), param_env, predicate); diff --git a/compiler/rustc_transmute/src/lib.rs b/compiler/rustc_transmute/src/lib.rs index 7d800e49ff45..00928137d297 100644 --- a/compiler/rustc_transmute/src/lib.rs +++ b/compiler/rustc_transmute/src/lib.rs @@ -1,5 +1,4 @@ // tidy-alphabetical-start -#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![feature(never_type)] // tidy-alphabetical-end diff --git a/compiler/rustc_transmute/src/maybe_transmutable/tests.rs b/compiler/rustc_transmute/src/maybe_transmutable/tests.rs index 4d81382eba02..69a6b1b77f4b 100644 --- a/compiler/rustc_transmute/src/maybe_transmutable/tests.rs +++ b/compiler/rustc_transmute/src/maybe_transmutable/tests.rs @@ -1,93 +1,115 @@ use itertools::Itertools; use super::query_context::test::{Def, UltraMinimal}; -use crate::maybe_transmutable::MaybeTransmutableQuery; -use crate::{Reason, layout}; +use crate::{Answer, Assume, Reason, layout}; + +type Tree = layout::Tree; +type Dfa = layout::Dfa; + +trait Representation { + fn is_transmutable(src: Self, dst: Self, assume: Assume) -> Answer; +} + +impl Representation for Tree { + fn is_transmutable(src: Self, dst: Self, assume: Assume) -> Answer { + crate::maybe_transmutable::MaybeTransmutableQuery::new(src, dst, assume, UltraMinimal) + .answer() + } +} + +impl Representation for Dfa { + fn is_transmutable(src: Self, dst: Self, assume: Assume) -> Answer { + crate::maybe_transmutable::MaybeTransmutableQuery::new(src, dst, assume, UltraMinimal) + .answer() + } +} + +fn is_transmutable( + src: &R, + dst: &R, + assume: Assume, +) -> crate::Answer { + let src = src.clone(); + let dst = dst.clone(); + // The only dimension of the transmutability analysis we want to test + // here is the safety analysis. To ensure this, we disable all other + // toggleable aspects of the transmutability analysis. + R::is_transmutable(src, dst, assume) +} mod safety { use super::*; use crate::Answer; - type Tree = layout::Tree; - const DST_HAS_SAFETY_INVARIANTS: Answer = Answer::No(crate::Reason::DstMayHaveSafetyInvariants); - fn is_transmutable(src: &Tree, dst: &Tree, assume_safety: bool) -> crate::Answer { - let src = src.clone(); - let dst = dst.clone(); - // The only dimension of the transmutability analysis we want to test - // here is the safety analysis. To ensure this, we disable all other - // toggleable aspects of the transmutability analysis. - let assume = crate::Assume { - alignment: true, - lifetimes: true, - validity: true, - safety: assume_safety, - }; - crate::maybe_transmutable::MaybeTransmutableQuery::new(src, dst, assume, UltraMinimal) - .answer() - } - #[test] fn src_safe_dst_safe() { let src = Tree::Def(Def::NoSafetyInvariants).then(Tree::u8()); let dst = Tree::Def(Def::NoSafetyInvariants).then(Tree::u8()); - assert_eq!(is_transmutable(&src, &dst, false), Answer::Yes); - assert_eq!(is_transmutable(&src, &dst, true), Answer::Yes); + assert_eq!(is_transmutable(&src, &dst, Assume::default()), Answer::Yes); + assert_eq!( + is_transmutable(&src, &dst, Assume { safety: true, ..Assume::default() }), + Answer::Yes + ); } #[test] fn src_safe_dst_unsafe() { let src = Tree::Def(Def::NoSafetyInvariants).then(Tree::u8()); let dst = Tree::Def(Def::HasSafetyInvariants).then(Tree::u8()); - assert_eq!(is_transmutable(&src, &dst, false), DST_HAS_SAFETY_INVARIANTS); - assert_eq!(is_transmutable(&src, &dst, true), Answer::Yes); + assert_eq!(is_transmutable(&src, &dst, Assume::default()), DST_HAS_SAFETY_INVARIANTS); + assert_eq!( + is_transmutable(&src, &dst, Assume { safety: true, ..Assume::default() }), + Answer::Yes + ); } #[test] fn src_unsafe_dst_safe() { let src = Tree::Def(Def::HasSafetyInvariants).then(Tree::u8()); let dst = Tree::Def(Def::NoSafetyInvariants).then(Tree::u8()); - assert_eq!(is_transmutable(&src, &dst, false), Answer::Yes); - assert_eq!(is_transmutable(&src, &dst, true), Answer::Yes); + assert_eq!(is_transmutable(&src, &dst, Assume::default()), Answer::Yes); + assert_eq!( + is_transmutable(&src, &dst, Assume { safety: true, ..Assume::default() }), + Answer::Yes + ); } #[test] fn src_unsafe_dst_unsafe() { let src = Tree::Def(Def::HasSafetyInvariants).then(Tree::u8()); let dst = Tree::Def(Def::HasSafetyInvariants).then(Tree::u8()); - assert_eq!(is_transmutable(&src, &dst, false), DST_HAS_SAFETY_INVARIANTS); - assert_eq!(is_transmutable(&src, &dst, true), Answer::Yes); + assert_eq!(is_transmutable(&src, &dst, Assume::default()), DST_HAS_SAFETY_INVARIANTS); + assert_eq!( + is_transmutable(&src, &dst, Assume { safety: true, ..Assume::default() }), + Answer::Yes + ); } } mod bool { use super::*; - use crate::Answer; #[test] fn should_permit_identity_transmutation_tree() { - let answer = crate::maybe_transmutable::MaybeTransmutableQuery::new( - layout::Tree::::bool(), - layout::Tree::::bool(), - crate::Assume { alignment: false, lifetimes: false, validity: true, safety: false }, - UltraMinimal, - ) - .answer(); - assert_eq!(answer, Answer::Yes); + let src = Tree::bool(); + assert_eq!(is_transmutable(&src, &src, Assume::default()), Answer::Yes); + assert_eq!( + is_transmutable(&src, &src, Assume { validity: true, ..Assume::default() }), + Answer::Yes + ); } #[test] fn should_permit_identity_transmutation_dfa() { - let answer = crate::maybe_transmutable::MaybeTransmutableQuery::new( - layout::Dfa::::bool(), - layout::Dfa::::bool(), - crate::Assume { alignment: false, lifetimes: false, validity: true, safety: false }, - UltraMinimal, - ) - .answer(); - assert_eq!(answer, Answer::Yes); + let src = Dfa::bool(); + assert_eq!(is_transmutable(&src, &src, Assume::default()), Answer::Yes); + assert_eq!( + is_transmutable(&src, &src, Assume { validity: true, ..Assume::default() }), + Answer::Yes + ); } #[test] @@ -122,13 +144,7 @@ mod bool { if src_set.is_subset(&dst_set) { assert_eq!( Answer::Yes, - MaybeTransmutableQuery::new( - src_layout.clone(), - dst_layout.clone(), - crate::Assume { validity: false, ..crate::Assume::default() }, - UltraMinimal, - ) - .answer(), + is_transmutable(&src_layout, &dst_layout, Assume::default()), "{:?} SHOULD be transmutable into {:?}", src_layout, dst_layout @@ -136,13 +152,11 @@ mod bool { } else if !src_set.is_disjoint(&dst_set) { assert_eq!( Answer::Yes, - MaybeTransmutableQuery::new( - src_layout.clone(), - dst_layout.clone(), - crate::Assume { validity: true, ..crate::Assume::default() }, - UltraMinimal, - ) - .answer(), + is_transmutable( + &src_layout, + &dst_layout, + Assume { validity: true, ..Assume::default() } + ), "{:?} SHOULD be transmutable (assuming validity) into {:?}", src_layout, dst_layout @@ -150,13 +164,7 @@ mod bool { } else { assert_eq!( Answer::No(Reason::DstIsBitIncompatible), - MaybeTransmutableQuery::new( - src_layout.clone(), - dst_layout.clone(), - crate::Assume { validity: false, ..crate::Assume::default() }, - UltraMinimal, - ) - .answer(), + is_transmutable(&src_layout, &dst_layout, Assume::default()), "{:?} should NOT be transmutable into {:?}", src_layout, dst_layout diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index 48d5a4a0fcb0..3d4ab33240af 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -244,7 +244,7 @@ fn fn_sig_for_fn_abi<'tcx>( fn conv_from_spec_abi(tcx: TyCtxt<'_>, abi: ExternAbi, c_variadic: bool) -> Conv { use rustc_abi::ExternAbi::*; match tcx.sess.target.adjust_abi(abi, c_variadic) { - RustIntrinsic | Rust | RustCall => Conv::Rust, + Rust | RustCall => Conv::Rust, // This is intentionally not using `Conv::Cold`, as that has to preserve // even SIMD registers, which is generally not a good trade-off. @@ -660,7 +660,7 @@ fn fn_abi_adjust_for_abi<'tcx>( let tcx = cx.tcx(); if abi.is_rustic_abi() { - fn_abi.adjust_for_rust_abi(cx, abi); + fn_abi.adjust_for_rust_abi(cx); // Look up the deduced parameter attributes for this function, if we have its def ID and // we're optimizing in non-incremental mode. We'll tag its parameters with those attributes diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs index b7684e85d412..6cb9fdc6f931 100644 --- a/compiler/rustc_ty_utils/src/assoc.rs +++ b/compiler/rustc_ty_utils/src/assoc.rs @@ -6,7 +6,6 @@ use rustc_hir::{self as hir, AmbigArg}; use rustc_middle::query::Providers; use rustc_middle::ty::{self, ImplTraitInTraitData, TyCtxt}; use rustc_middle::{bug, span_bug}; -use rustc_span::kw; pub(crate) fn provide(providers: &mut Providers) { *providers = Providers { @@ -129,39 +128,35 @@ fn associated_item(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AssocItem { fn associated_item_from_trait_item_ref(trait_item_ref: &hir::TraitItemRef) -> ty::AssocItem { let owner_id = trait_item_ref.id.owner_id; - let (kind, has_self) = match trait_item_ref.kind { - hir::AssocItemKind::Const => (ty::AssocKind::Const, false), - hir::AssocItemKind::Fn { has_self } => (ty::AssocKind::Fn, has_self), - hir::AssocItemKind::Type => (ty::AssocKind::Type, false), + let name = trait_item_ref.ident.name; + let kind = match trait_item_ref.kind { + hir::AssocItemKind::Const => ty::AssocKind::Const { name }, + hir::AssocItemKind::Fn { has_self } => ty::AssocKind::Fn { name, has_self }, + hir::AssocItemKind::Type => ty::AssocKind::Type { data: ty::AssocTypeData::Normal(name) }, }; ty::AssocItem { - name: trait_item_ref.ident.name, kind, def_id: owner_id.to_def_id(), trait_item_def_id: Some(owner_id.to_def_id()), container: ty::AssocItemContainer::Trait, - fn_has_self_parameter: has_self, - opt_rpitit_info: None, } } fn associated_item_from_impl_item_ref(impl_item_ref: &hir::ImplItemRef) -> ty::AssocItem { let def_id = impl_item_ref.id.owner_id; - let (kind, has_self) = match impl_item_ref.kind { - hir::AssocItemKind::Const => (ty::AssocKind::Const, false), - hir::AssocItemKind::Fn { has_self } => (ty::AssocKind::Fn, has_self), - hir::AssocItemKind::Type => (ty::AssocKind::Type, false), + let name = impl_item_ref.ident.name; + let kind = match impl_item_ref.kind { + hir::AssocItemKind::Const => ty::AssocKind::Const { name }, + hir::AssocItemKind::Fn { has_self } => ty::AssocKind::Fn { name, has_self }, + hir::AssocItemKind::Type => ty::AssocKind::Type { data: ty::AssocTypeData::Normal(name) }, }; ty::AssocItem { - name: impl_item_ref.ident.name, kind, def_id: def_id.to_def_id(), trait_item_def_id: impl_item_ref.trait_item_def_id, container: ty::AssocItemContainer::Impl, - fn_has_self_parameter: has_self, - opt_rpitit_info: None, } } @@ -252,7 +247,7 @@ fn associated_type_for_impl_trait_in_trait( assert_eq!(tcx.def_kind(trait_def_id), DefKind::Trait); let span = tcx.def_span(opaque_ty_def_id); - // No name because this is a synthetic associated type. + // No name because this is an anonymous associated type. let trait_assoc_ty = tcx.at(span).create_def(trait_def_id, None, DefKind::AssocTy); let local_def_id = trait_assoc_ty.def_id(); @@ -264,16 +259,15 @@ fn associated_type_for_impl_trait_in_trait( trait_assoc_ty.def_ident_span(Some(span)); trait_assoc_ty.associated_item(ty::AssocItem { - name: kw::Empty, - kind: ty::AssocKind::Type, + kind: ty::AssocKind::Type { + data: ty::AssocTypeData::Rpitit(ImplTraitInTraitData::Trait { + fn_def_id: fn_def_id.to_def_id(), + opaque_def_id: opaque_ty_def_id.to_def_id(), + }), + }, def_id, trait_item_def_id: None, container: ty::AssocItemContainer::Trait, - fn_has_self_parameter: false, - opt_rpitit_info: Some(ImplTraitInTraitData::Trait { - fn_def_id: fn_def_id.to_def_id(), - opaque_def_id: opaque_ty_def_id.to_def_id(), - }), }); // Copy visility of the containing function. @@ -305,7 +299,7 @@ fn associated_type_for_impl_trait_in_impl( hir::FnRetTy::DefaultReturn(_) => tcx.def_span(impl_fn_def_id), hir::FnRetTy::Return(ty) => ty.span, }; - // No name because this is a synthetic associated type. + // No name because this is an anonymous associated type. let impl_assoc_ty = tcx.at(span).create_def(impl_local_def_id, None, DefKind::AssocTy); let local_def_id = impl_assoc_ty.def_id(); @@ -317,13 +311,14 @@ fn associated_type_for_impl_trait_in_impl( impl_assoc_ty.def_ident_span(Some(span)); impl_assoc_ty.associated_item(ty::AssocItem { - name: kw::Empty, - kind: ty::AssocKind::Type, + kind: ty::AssocKind::Type { + data: ty::AssocTypeData::Rpitit(ImplTraitInTraitData::Impl { + fn_def_id: impl_fn_def_id.to_def_id(), + }), + }, def_id, trait_item_def_id: Some(trait_assoc_def_id), container: ty::AssocItemContainer::Impl, - fn_has_self_parameter: false, - opt_rpitit_info: Some(ImplTraitInTraitData::Impl { fn_def_id: impl_fn_def_id.to_def_id() }), }); // Copy visility of the containing function. diff --git a/compiler/rustc_ty_utils/src/implied_bounds.rs b/compiler/rustc_ty_utils/src/implied_bounds.rs index 088d5e76b868..6fa763f18ef1 100644 --- a/compiler/rustc_ty_utils/src/implied_bounds.rs +++ b/compiler/rustc_ty_utils/src/implied_bounds.rs @@ -4,9 +4,9 @@ use rustc_data_structures::fx::FxHashMap; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; -use rustc_middle::bug; use rustc_middle::query::Providers; use rustc_middle::ty::{self, Ty, TyCtxt, fold_regions}; +use rustc_middle::{bug, span_bug}; use rustc_span::Span; pub(crate) fn provide(providers: &mut Providers) { @@ -21,7 +21,8 @@ pub(crate) fn provide(providers: &mut Providers) { } fn assumed_wf_types<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx [(Ty<'tcx>, Span)] { - match tcx.def_kind(def_id) { + let kind = tcx.def_kind(def_id); + match kind { DefKind::Fn => { let sig = tcx.fn_sig(def_id).instantiate_identity(); let liberated_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), sig); @@ -75,7 +76,7 @@ fn assumed_wf_types<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx [(Ty<' { let orig_lt = tcx.map_opaque_lifetime_to_parent_lifetime(param.def_id.expect_local()); - if matches!(*orig_lt, ty::ReLateParam(..)) { + if matches!(orig_lt.kind(), ty::ReLateParam(..)) { mapping.insert( orig_lt, ty::Region::new_early_param( @@ -121,32 +122,38 @@ fn assumed_wf_types<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx [(Ty<' } } DefKind::AssocConst | DefKind::AssocTy => tcx.assumed_wf_types(tcx.local_parent(def_id)), - DefKind::OpaqueTy => bug!("implied bounds are not defined for opaques"), - DefKind::Mod + DefKind::Static { .. } + | DefKind::Const + | DefKind::AnonConst + | DefKind::InlineConst | DefKind::Struct | DefKind::Union | DefKind::Enum - | DefKind::Variant | DefKind::Trait - | DefKind::TyAlias - | DefKind::ForeignTy | DefKind::TraitAlias + | DefKind::TyAlias => ty::List::empty(), + DefKind::OpaqueTy + | DefKind::Mod + | DefKind::Variant + | DefKind::ForeignTy | DefKind::TyParam - | DefKind::Const | DefKind::ConstParam - | DefKind::Static { .. } | DefKind::Ctor(_, _) | DefKind::Macro(_) | DefKind::ExternCrate | DefKind::Use | DefKind::ForeignMod - | DefKind::AnonConst - | DefKind::InlineConst | DefKind::Field | DefKind::LifetimeParam | DefKind::GlobalAsm | DefKind::Closure - | DefKind::SyntheticCoroutineBody => ty::List::empty(), + | DefKind::SyntheticCoroutineBody => { + span_bug!( + tcx.def_span(def_id), + "`assumed_wf_types` not defined for {} `{def_id:?}`", + kind.descr(def_id.to_def_id()) + ); + } } } diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index 0017186c1b08..1915ba623cb2 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -514,6 +514,9 @@ fn layout_of_uncached<'tcx>( return map_layout(cx.calc.layout_of_union(&def.repr(), &variants)); } + // UnsafeCell and UnsafePinned both disable niche optimizations + let is_special_no_niche = def.is_unsafe_cell() || def.is_unsafe_pinned(); + let get_discriminant_type = |min, max| abi::Integer::repr_discr(tcx, ty, &def.repr(), min, max); @@ -542,7 +545,7 @@ fn layout_of_uncached<'tcx>( &def.repr(), &variants, def.is_enum(), - def.is_unsafe_cell(), + is_special_no_niche, tcx.layout_scalar_valid_range(def.did()), get_discriminant_type, discriminants_iter(), @@ -568,7 +571,7 @@ fn layout_of_uncached<'tcx>( &def.repr(), &variants, def.is_enum(), - def.is_unsafe_cell(), + is_special_no_niche, tcx.layout_scalar_valid_range(def.did()), get_discriminant_type, discriminants_iter(), diff --git a/compiler/rustc_ty_utils/src/lib.rs b/compiler/rustc_ty_utils/src/lib.rs index 143b7d538801..35cc6f398565 100644 --- a/compiler/rustc_ty_utils/src/lib.rs +++ b/compiler/rustc_ty_utils/src/lib.rs @@ -6,7 +6,6 @@ // tidy-alphabetical-start #![allow(internal_features)] -#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(assert_matches)] diff --git a/compiler/rustc_ty_utils/src/opaque_types.rs b/compiler/rustc_ty_utils/src/opaque_types.rs index 3aad97d86cca..cd730aeeea90 100644 --- a/compiler/rustc_ty_utils/src/opaque_types.rs +++ b/compiler/rustc_ty_utils/src/opaque_types.rs @@ -3,10 +3,10 @@ use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit; use rustc_hir::intravisit::Visitor; -use rustc_middle::bug; use rustc_middle::query::Providers; use rustc_middle::ty::util::{CheckRegions, NotUniqueParam}; use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor}; +use rustc_middle::{bug, span_bug}; use rustc_span::Span; use tracing::{instrument, trace}; @@ -320,9 +320,12 @@ fn opaque_types_defined_by<'tcx>( | DefKind::AnonConst => { collector.collect_taits_declared_in_body(); } + // Closures and coroutines are type checked with their parent + DefKind::Closure | DefKind::InlineConst => { + collector.opaques.extend(tcx.opaque_types_defined_by(tcx.local_parent(item))); + } + DefKind::AssocTy | DefKind::TyAlias | DefKind::GlobalAsm => {} DefKind::OpaqueTy - | DefKind::TyAlias - | DefKind::AssocTy | DefKind::Mod | DefKind::Struct | DefKind::Union @@ -340,12 +343,13 @@ fn opaque_types_defined_by<'tcx>( | DefKind::ForeignMod | DefKind::Field | DefKind::LifetimeParam - | DefKind::GlobalAsm | DefKind::Impl { .. } - | DefKind::SyntheticCoroutineBody => {} - // Closures and coroutines are type checked with their parent - DefKind::Closure | DefKind::InlineConst => { - collector.opaques.extend(tcx.opaque_types_defined_by(tcx.local_parent(item))); + | DefKind::SyntheticCoroutineBody => { + span_bug!( + tcx.def_span(item), + "`opaque_types_defined_by` not defined for {} `{item:?}`", + kind.descr(item.to_def_id()) + ); } } tcx.mk_local_def_ids(&collector.opaques) diff --git a/compiler/rustc_ty_utils/src/sig_types.rs b/compiler/rustc_ty_utils/src/sig_types.rs index 5bb96f90029a..dc6009116ac5 100644 --- a/compiler/rustc_ty_utils/src/sig_types.rs +++ b/compiler/rustc_ty_utils/src/sig_types.rs @@ -116,7 +116,7 @@ pub fn walk_types<'tcx, V: SpannedTypeVisitor<'tcx>>( "{kind:?} has not seen any uses of `walk_types` yet, ping oli-obk if you'd like any help" ) } - // These don't have any types. + // These don't have any types, but are visited during privacy checking. | DefKind::ExternCrate | DefKind::ForeignMod | DefKind::ForeignTy diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index 9dc4f11e456e..31d69eef5ecf 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -3,6 +3,7 @@ use rustc_hir as hir; use rustc_hir::LangItem; use rustc_hir::def::DefKind; use rustc_index::bit_set::DenseBitSet; +use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::bug; use rustc_middle::query::Providers; use rustc_middle::ty::{ @@ -312,6 +313,61 @@ fn unsizing_params_for_adt<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> DenseBitSe unsizing_params } +fn impl_self_is_guaranteed_unsized<'tcx>(tcx: TyCtxt<'tcx>, impl_def_id: DefId) -> bool { + debug_assert_eq!(tcx.def_kind(impl_def_id), DefKind::Impl { of_trait: true }); + + let infcx = tcx.infer_ctxt().ignoring_regions().build(ty::TypingMode::non_body_analysis()); + + let ocx = traits::ObligationCtxt::new_with_diagnostics(&infcx); + let cause = traits::ObligationCause::dummy(); + let param_env = tcx.param_env(impl_def_id); + + let tail = tcx.struct_tail_raw( + tcx.type_of(impl_def_id).instantiate_identity(), + |ty| { + ocx.structurally_normalize_ty(&cause, param_env, ty).unwrap_or_else(|_| { + Ty::new_error_with_message( + tcx, + tcx.def_span(impl_def_id), + "struct tail should be computable", + ) + }) + }, + || (), + ); + + match tail.kind() { + ty::Dynamic(_, _, ty::Dyn) | ty::Slice(_) | ty::Str => true, + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Adt(_, _) + | ty::Foreign(_) + | ty::Array(_, _) + | ty::Pat(_, _) + | ty::RawPtr(_, _) + | ty::Ref(_, _, _) + | ty::FnDef(_, _) + | ty::FnPtr(_, _) + | ty::UnsafeBinder(_) + | ty::Closure(_, _) + | ty::CoroutineClosure(_, _) + | ty::Coroutine(_, _) + | ty::CoroutineWitness(_, _) + | ty::Never + | ty::Tuple(_) + | ty::Alias(_, _) + | ty::Param(_) + | ty::Bound(_, _) + | ty::Placeholder(_) + | ty::Infer(_) + | ty::Error(_) + | ty::Dynamic(_, _, ty::DynStar) => false, + } +} + pub(crate) fn provide(providers: &mut Providers) { *providers = Providers { asyncness, @@ -320,6 +376,7 @@ pub(crate) fn provide(providers: &mut Providers) { param_env_normalized_for_post_analysis, defaultness, unsizing_params_for_adt, + impl_self_is_guaranteed_unsized, ..*providers }; } diff --git a/compiler/rustc_type_ir/Cargo.toml b/compiler/rustc_type_ir/Cargo.toml index 4adf71579266..83d3d78298e6 100644 --- a/compiler/rustc_type_ir/Cargo.toml +++ b/compiler/rustc_type_ir/Cargo.toml @@ -7,6 +7,7 @@ edition = "2024" # tidy-alphabetical-start bitflags = "2.4.1" derive-where = "1.2.7" +ena = "0.14.3" indexmap = "2.0.0" rustc-hash = "1.1.0" rustc_ast_ir = { path = "../rustc_ast_ir", default-features = false } diff --git a/compiler/rustc_type_ir/src/binder.rs b/compiler/rustc_type_ir/src/binder.rs index e9055940310d..27ea4e211fef 100644 --- a/compiler/rustc_type_ir/src/binder.rs +++ b/compiler/rustc_type_ir/src/binder.rs @@ -122,6 +122,10 @@ impl> TypeFoldable for Binder { fn try_fold_with>(self, folder: &mut F) -> Result { folder.try_fold_binder(self) } + + fn fold_with>(self, folder: &mut F) -> Self { + folder.fold_binder(self) + } } impl> TypeVisitable for Binder { @@ -135,7 +139,11 @@ impl> TypeSuperFoldable for Binder { self, folder: &mut F, ) -> Result { - self.try_map_bound(|ty| ty.try_fold_with(folder)) + self.try_map_bound(|t| t.try_fold_with(folder)) + } + + fn super_fold_with>(self, folder: &mut F) -> Self { + self.map_bound(|t| t.fold_with(folder)) } } diff --git a/compiler/rustc_type_ir/src/data_structures/mod.rs b/compiler/rustc_type_ir/src/data_structures/mod.rs index 30c67d10d0e8..a72669cbd189 100644 --- a/compiler/rustc_type_ir/src/data_structures/mod.rs +++ b/compiler/rustc_type_ir/src/data_structures/mod.rs @@ -1,5 +1,6 @@ use std::hash::BuildHasherDefault; +pub use ena::unify::{NoError, UnifyKey, UnifyValue}; use rustc_hash::FxHasher; pub use rustc_hash::{FxHashMap as HashMap, FxHashSet as HashSet}; diff --git a/compiler/rustc_type_ir/src/flags.rs b/compiler/rustc_type_ir/src/flags.rs index 6a2498242fee..e9d3a149a730 100644 --- a/compiler/rustc_type_ir/src/flags.rs +++ b/compiler/rustc_type_ir/src/flags.rs @@ -1,3 +1,9 @@ +use std::slice; + +use crate::inherent::*; +use crate::visit::Flags; +use crate::{self as ty, Interner}; + bitflags::bitflags! { /// Flags that we track on types. These flags are propagated upwards /// through the type during type construction, so that we can quickly check @@ -128,3 +134,362 @@ bitflags::bitflags! { const HAS_BINDER_VARS = 1 << 23; } } + +#[derive(Debug)] +pub struct FlagComputation { + pub flags: TypeFlags, + + /// see `Ty::outer_exclusive_binder` for details + pub outer_exclusive_binder: ty::DebruijnIndex, + + interner: std::marker::PhantomData, +} + +impl FlagComputation { + fn new() -> FlagComputation { + FlagComputation { + flags: TypeFlags::empty(), + outer_exclusive_binder: ty::INNERMOST, + interner: std::marker::PhantomData, + } + } + + #[allow(rustc::usage_of_ty_tykind)] + pub fn for_kind(kind: &ty::TyKind) -> FlagComputation { + let mut result = FlagComputation::new(); + result.add_kind(kind); + result + } + + pub fn for_predicate(binder: ty::Binder>) -> FlagComputation { + let mut result = FlagComputation::new(); + result.add_predicate(binder); + result + } + + pub fn for_const_kind(kind: &ty::ConstKind) -> FlagComputation { + let mut result = FlagComputation::new(); + result.add_const_kind(kind); + result + } + + pub fn for_clauses(clauses: &[I::Clause]) -> FlagComputation { + let mut result = FlagComputation::new(); + for c in clauses { + result.add_flags(c.as_predicate().flags()); + result.add_exclusive_binder(c.as_predicate().outer_exclusive_binder()); + } + result + } + + fn add_flags(&mut self, flags: TypeFlags) { + self.flags = self.flags | flags; + } + + /// indicates that `self` refers to something at binding level `binder` + fn add_bound_var(&mut self, binder: ty::DebruijnIndex) { + let exclusive_binder = binder.shifted_in(1); + self.add_exclusive_binder(exclusive_binder); + } + + /// indicates that `self` refers to something *inside* binding + /// level `binder` -- not bound by `binder`, but bound by the next + /// binder internal to it + fn add_exclusive_binder(&mut self, exclusive_binder: ty::DebruijnIndex) { + self.outer_exclusive_binder = self.outer_exclusive_binder.max(exclusive_binder); + } + + /// Adds the flags/depth from a set of types that appear within the current type, but within a + /// region binder. + fn bound_computation(&mut self, value: ty::Binder, f: F) + where + F: FnOnce(&mut Self, T), + { + let mut computation = FlagComputation::new(); + + if !value.bound_vars().is_empty() { + computation.add_flags(TypeFlags::HAS_BINDER_VARS); + } + + f(&mut computation, value.skip_binder()); + + self.add_flags(computation.flags); + + // The types that contributed to `computation` occurred within + // a region binder, so subtract one from the region depth + // within when adding the depth to `self`. + let outer_exclusive_binder = computation.outer_exclusive_binder; + if outer_exclusive_binder > ty::INNERMOST { + self.add_exclusive_binder(outer_exclusive_binder.shifted_out(1)); + } // otherwise, this binder captures nothing + } + + #[allow(rustc::usage_of_ty_tykind)] + fn add_kind(&mut self, kind: &ty::TyKind) { + match *kind { + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Float(_) + | ty::Uint(_) + | ty::Never + | ty::Str + | ty::Foreign(..) => {} + + ty::Error(_) => self.add_flags(TypeFlags::HAS_ERROR), + + ty::Param(_) => { + self.add_flags(TypeFlags::HAS_TY_PARAM); + } + + ty::Closure(_, args) + | ty::Coroutine(_, args) + | ty::CoroutineClosure(_, args) + | ty::CoroutineWitness(_, args) => { + self.add_args(args.as_slice()); + } + + ty::Bound(debruijn, _) => { + self.add_bound_var(debruijn); + self.add_flags(TypeFlags::HAS_TY_BOUND); + } + + ty::Placeholder(..) => { + self.add_flags(TypeFlags::HAS_TY_PLACEHOLDER); + } + + ty::Infer(infer) => match infer { + ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_) => { + self.add_flags(TypeFlags::HAS_TY_FRESH) + } + + ty::TyVar(_) | ty::IntVar(_) | ty::FloatVar(_) => { + self.add_flags(TypeFlags::HAS_TY_INFER) + } + }, + + ty::Adt(_, args) => { + self.add_args(args.as_slice()); + } + + ty::Alias(kind, data) => { + self.add_flags(match kind { + ty::Projection => TypeFlags::HAS_TY_PROJECTION, + ty::Weak => TypeFlags::HAS_TY_WEAK, + ty::Opaque => TypeFlags::HAS_TY_OPAQUE, + ty::Inherent => TypeFlags::HAS_TY_INHERENT, + }); + + self.add_alias_ty(data); + } + + ty::Dynamic(obj, r, _) => { + for predicate in obj.iter() { + self.bound_computation(predicate, |computation, predicate| match predicate { + ty::ExistentialPredicate::Trait(tr) => { + computation.add_args(tr.args.as_slice()) + } + ty::ExistentialPredicate::Projection(p) => { + computation.add_existential_projection(&p); + } + ty::ExistentialPredicate::AutoTrait(_) => {} + }); + } + + self.add_region(r); + } + + ty::Array(tt, len) => { + self.add_ty(tt); + self.add_const(len); + } + + ty::Pat(ty, pat) => { + self.add_ty(ty); + self.add_flags(pat.flags()); + } + + ty::Slice(tt) => self.add_ty(tt), + + ty::RawPtr(ty, _) => { + self.add_ty(ty); + } + + ty::Ref(r, ty, _) => { + self.add_region(r); + self.add_ty(ty); + } + + ty::Tuple(types) => { + self.add_tys(types); + } + + ty::FnDef(_, args) => { + self.add_args(args.as_slice()); + } + + ty::FnPtr(sig_tys, _) => self.bound_computation(sig_tys, |computation, sig_tys| { + computation.add_tys(sig_tys.inputs_and_output); + }), + + ty::UnsafeBinder(bound_ty) => { + self.bound_computation(bound_ty.into(), |computation, ty| { + computation.add_ty(ty); + }) + } + } + } + + fn add_predicate(&mut self, binder: ty::Binder>) { + self.bound_computation(binder, |computation, atom| computation.add_predicate_atom(atom)); + } + + fn add_predicate_atom(&mut self, atom: ty::PredicateKind) { + match atom { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) => { + self.add_args(trait_pred.trait_ref.args.as_slice()); + } + ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(ty::HostEffectPredicate { + trait_ref, + constness: _, + })) => { + self.add_args(trait_ref.args.as_slice()); + } + ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate( + a, + b, + ))) => { + self.add_region(a); + self.add_region(b); + } + ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate( + ty, + region, + ))) => { + self.add_ty(ty); + self.add_region(region); + } + ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => { + self.add_const(ct); + self.add_ty(ty); + } + ty::PredicateKind::Subtype(ty::SubtypePredicate { a_is_expected: _, a, b }) => { + self.add_ty(a); + self.add_ty(b); + } + ty::PredicateKind::Coerce(ty::CoercePredicate { a, b }) => { + self.add_ty(a); + self.add_ty(b); + } + ty::PredicateKind::Clause(ty::ClauseKind::Projection(ty::ProjectionPredicate { + projection_term, + term, + })) => { + self.add_alias_term(projection_term); + self.add_term(term); + } + ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => { + self.add_args(slice::from_ref(&arg)); + } + ty::PredicateKind::DynCompatible(_def_id) => {} + ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(uv)) => { + self.add_const(uv); + } + ty::PredicateKind::ConstEquate(expected, found) => { + self.add_const(expected); + self.add_const(found); + } + ty::PredicateKind::Ambiguous => {} + ty::PredicateKind::NormalizesTo(ty::NormalizesTo { alias, term }) => { + self.add_alias_term(alias); + self.add_term(term); + } + ty::PredicateKind::AliasRelate(t1, t2, _) => { + self.add_term(t1); + self.add_term(t2); + } + } + } + + fn add_ty(&mut self, ty: I::Ty) { + self.add_flags(ty.flags()); + self.add_exclusive_binder(ty.outer_exclusive_binder()); + } + + fn add_tys(&mut self, tys: I::Tys) { + for ty in tys.iter() { + self.add_ty(ty); + } + } + + fn add_region(&mut self, r: I::Region) { + self.add_flags(r.flags()); + if let ty::ReBound(debruijn, _) = r.kind() { + self.add_bound_var(debruijn); + } + } + + fn add_const(&mut self, c: I::Const) { + self.add_flags(c.flags()); + self.add_exclusive_binder(c.outer_exclusive_binder()); + } + + fn add_const_kind(&mut self, c: &ty::ConstKind) { + match *c { + ty::ConstKind::Unevaluated(uv) => { + self.add_args(uv.args.as_slice()); + self.add_flags(TypeFlags::HAS_CT_PROJECTION); + } + ty::ConstKind::Infer(infer) => match infer { + ty::InferConst::Fresh(_) => self.add_flags(TypeFlags::HAS_CT_FRESH), + ty::InferConst::Var(_) => self.add_flags(TypeFlags::HAS_CT_INFER), + }, + ty::ConstKind::Bound(debruijn, _) => { + self.add_bound_var(debruijn); + self.add_flags(TypeFlags::HAS_CT_BOUND); + } + ty::ConstKind::Param(_) => { + self.add_flags(TypeFlags::HAS_CT_PARAM); + } + ty::ConstKind::Placeholder(_) => { + self.add_flags(TypeFlags::HAS_CT_PLACEHOLDER); + } + ty::ConstKind::Value(cv) => self.add_ty(cv.ty()), + ty::ConstKind::Expr(e) => self.add_args(e.args().as_slice()), + ty::ConstKind::Error(_) => self.add_flags(TypeFlags::HAS_ERROR), + } + } + + fn add_existential_projection(&mut self, projection: &ty::ExistentialProjection) { + self.add_args(projection.args.as_slice()); + match projection.term.kind() { + ty::TermKind::Ty(ty) => self.add_ty(ty), + ty::TermKind::Const(ct) => self.add_const(ct), + } + } + + fn add_alias_ty(&mut self, alias_ty: ty::AliasTy) { + self.add_args(alias_ty.args.as_slice()); + } + + fn add_alias_term(&mut self, alias_term: ty::AliasTerm) { + self.add_args(alias_term.args.as_slice()); + } + + fn add_args(&mut self, args: &[I::GenericArg]) { + for kind in args { + match kind.kind() { + ty::GenericArgKind::Type(ty) => self.add_ty(ty), + ty::GenericArgKind::Lifetime(lt) => self.add_region(lt), + ty::GenericArgKind::Const(ct) => self.add_const(ct), + } + } + } + + fn add_term(&mut self, term: I::Term) { + match term.kind() { + ty::TermKind::Ty(ty) => self.add_ty(ty), + ty::TermKind::Const(ct) => self.add_const(ct), + } + } +} diff --git a/compiler/rustc_type_ir/src/fold.rs b/compiler/rustc_type_ir/src/fold.rs index e58f25f4ce78..ce1188070ca7 100644 --- a/compiler/rustc_type_ir/src/fold.rs +++ b/compiler/rustc_type_ir/src/fold.rs @@ -45,6 +45,7 @@ //! - u.fold_with(folder) //! ``` +use std::convert::Infallible; use std::mem; use std::sync::Arc; @@ -56,12 +57,6 @@ use crate::inherent::*; use crate::visit::{TypeVisitable, TypeVisitableExt as _}; use crate::{self as ty, Interner, TypeFlags}; -#[cfg(feature = "nightly")] -type Never = !; - -#[cfg(not(feature = "nightly"))] -type Never = std::convert::Infallible; - /// This trait is implemented for every type that can be folded, /// providing the skeleton of the traversal. /// @@ -82,18 +77,24 @@ pub trait TypeFoldable: TypeVisitable + Clone { /// /// For types of interest (such as `Ty`), the implementation of this method /// calls a folder method specifically for that type (such as - /// `F::try_fold_ty`). This is where control transfers from `TypeFoldable` - /// to `TypeFolder`. + /// `F::try_fold_ty`). This is where control transfers from [`TypeFoldable`] + /// to [`FallibleTypeFolder`]. fn try_fold_with>(self, folder: &mut F) -> Result; - /// 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>(self, folder: &mut F) -> Self { - match self.try_fold_with(folder) { - Ok(t) => t, - } - } + /// The entry point for folding. To fold a value `t` with a folder `f` + /// call: `t.fold_with(f)`. + /// + /// For most types, this just traverses the value, calling `fold_with` + /// on each field/element. + /// + /// For types of interest (such as `Ty`), the implementation of this method + /// calls a folder method specifically for that type (such as + /// `F::fold_ty`). This is where control transfers from `TypeFoldable` + /// to `TypeFolder`. + /// + /// Same as [`TypeFoldable::try_fold_with`], but not fallible. Make sure to keep + /// the behavior in sync across functions. + fn fold_with>(self, folder: &mut F) -> Self; } // This trait is implemented for types of interest. @@ -112,11 +113,7 @@ pub trait TypeSuperFoldable: TypeFoldable { /// 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>(self, folder: &mut F) -> Self { - match self.try_super_fold_with(folder) { - Ok(t) => t, - } - } + fn super_fold_with>(self, folder: &mut F) -> Self; } /// This trait is implemented for every infallible folding traversal. There is @@ -128,7 +125,7 @@ pub trait TypeSuperFoldable: TypeFoldable { /// 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: FallibleTypeFolder { +pub trait TypeFolder: Sized { fn cx(&self) -> I; fn fold_binder(&mut self, t: ty::Binder) -> ty::Binder @@ -195,42 +192,6 @@ pub trait FallibleTypeFolder: Sized { } } -// This blanket implementation of the fallible trait for infallible folders -// delegates to infallible methods to ensure coherence. -impl FallibleTypeFolder for F -where - F: TypeFolder, -{ - type Error = Never; - - fn cx(&self) -> I { - TypeFolder::cx(self) - } - - fn try_fold_binder(&mut self, t: ty::Binder) -> Result, Never> - where - T: TypeFoldable, - { - Ok(self.fold_binder(t)) - } - - fn try_fold_ty(&mut self, t: I::Ty) -> Result { - Ok(self.fold_ty(t)) - } - - fn try_fold_region(&mut self, r: I::Region) -> Result { - Ok(self.fold_region(r)) - } - - fn try_fold_const(&mut self, c: I::Const) -> Result { - Ok(self.fold_const(c)) - } - - fn try_fold_predicate(&mut self, p: I::Predicate) -> Result { - Ok(self.fold_predicate(p)) - } -} - /////////////////////////////////////////////////////////////////////////// // Traversal implementations. @@ -238,6 +199,10 @@ impl, U: TypeFoldable> TypeFoldable for (T fn try_fold_with>(self, folder: &mut F) -> Result<(T, U), F::Error> { Ok((self.0.try_fold_with(folder)?, self.1.try_fold_with(folder)?)) } + + fn fold_with>(self, folder: &mut F) -> Self { + (self.0.fold_with(folder), self.1.fold_with(folder)) + } } impl, B: TypeFoldable, C: TypeFoldable> TypeFoldable @@ -253,6 +218,10 @@ impl, B: TypeFoldable, C: TypeFoldable> Ty self.2.try_fold_with(folder)?, )) } + + fn fold_with>(self, folder: &mut F) -> Self { + (self.0.fold_with(folder), self.1.fold_with(folder), self.2.fold_with(folder)) + } } impl> TypeFoldable for Option { @@ -262,6 +231,10 @@ impl> TypeFoldable for Option { None => None, }) } + + fn fold_with>(self, folder: &mut F) -> Self { + Some(self?.fold_with(folder)) + } } impl, E: TypeFoldable> TypeFoldable for Result { @@ -271,41 +244,61 @@ impl, E: TypeFoldable> TypeFoldable for Re Err(e) => Err(e.try_fold_with(folder)?), }) } + + fn fold_with>(self, folder: &mut F) -> Self { + match self { + Ok(v) => Ok(v.fold_with(folder)), + Err(e) => Err(e.fold_with(folder)), + } + } +} + +fn fold_arc( + mut arc: Arc, + fold: impl FnOnce(T) -> Result, +) -> Result, E> { + // We merely want to replace the contained `T`, if at all possible, + // so that we don't needlessly allocate a new `Arc` or indeed clone + // the contained type. + unsafe { + // First step is to ensure that we have a unique reference to + // the contained type, which `Arc::make_mut` will accomplish (by + // allocating a new `Arc` and cloning the `T` only if required). + // This is done *before* casting to `Arc>` so that + // panicking during `make_mut` does not leak the `T`. + Arc::make_mut(&mut arc); + + // Casting to `Arc>` is safe because `ManuallyDrop` + // is `repr(transparent)`. + let ptr = Arc::into_raw(arc).cast::>(); + let mut unique = Arc::from_raw(ptr); + + // Call to `Arc::make_mut` above guarantees that `unique` is the + // sole reference to the contained value, so we can avoid doing + // a checked `get_mut` here. + let slot = Arc::get_mut(&mut unique).unwrap_unchecked(); + + // Semantically move the contained type out from `unique`, fold + // it, then move the folded value back into `unique`. Should + // folding fail, `ManuallyDrop` ensures that the "moved-out" + // value is not re-dropped. + let owned = mem::ManuallyDrop::take(slot); + let folded = fold(owned)?; + *slot = mem::ManuallyDrop::new(folded); + + // Cast back to `Arc`. + Ok(Arc::from_raw(Arc::into_raw(unique).cast())) + } } impl> TypeFoldable for Arc { - fn try_fold_with>(mut self, folder: &mut F) -> Result { - // We merely want to replace the contained `T`, if at all possible, - // so that we don't needlessly allocate a new `Arc` or indeed clone - // the contained type. - unsafe { - // First step is to ensure that we have a unique reference to - // the contained type, which `Arc::make_mut` will accomplish (by - // allocating a new `Arc` and cloning the `T` only if required). - // This is done *before* casting to `Arc>` so that - // panicking during `make_mut` does not leak the `T`. - Arc::make_mut(&mut self); + fn try_fold_with>(self, folder: &mut F) -> Result { + fold_arc(self, |t| t.try_fold_with(folder)) + } - // Casting to `Arc>` is safe because `ManuallyDrop` - // is `repr(transparent)`. - let ptr = Arc::into_raw(self).cast::>(); - let mut unique = Arc::from_raw(ptr); - - // Call to `Arc::make_mut` above guarantees that `unique` is the - // sole reference to the contained value, so we can avoid doing - // a checked `get_mut` here. - let slot = Arc::get_mut(&mut unique).unwrap_unchecked(); - - // Semantically move the contained type out from `unique`, fold - // it, then move the folded value back into `unique`. Should - // folding fail, `ManuallyDrop` ensures that the "moved-out" - // value is not re-dropped. - let owned = mem::ManuallyDrop::take(slot); - let folded = owned.try_fold_with(folder)?; - *slot = mem::ManuallyDrop::new(folded); - - // Cast back to `Arc`. - Ok(Arc::from_raw(Arc::into_raw(unique).cast())) + fn fold_with>(self, folder: &mut F) -> Self { + match fold_arc::(self, |t| Ok(t.fold_with(folder))) { + Ok(t) => t, } } } @@ -315,30 +308,51 @@ impl> TypeFoldable for Box { *self = (*self).try_fold_with(folder)?; Ok(self) } + + fn fold_with>(mut self, folder: &mut F) -> Self { + *self = (*self).fold_with(folder); + self + } } impl> TypeFoldable for Vec { fn try_fold_with>(self, folder: &mut F) -> Result { self.into_iter().map(|t| t.try_fold_with(folder)).collect() } + + fn fold_with>(self, folder: &mut F) -> Self { + self.into_iter().map(|t| t.fold_with(folder)).collect() + } } impl> TypeFoldable for ThinVec { fn try_fold_with>(self, folder: &mut F) -> Result { self.into_iter().map(|t| t.try_fold_with(folder)).collect() } + + fn fold_with>(self, folder: &mut F) -> Self { + self.into_iter().map(|t| t.fold_with(folder)).collect() + } } impl> TypeFoldable for Box<[T]> { fn try_fold_with>(self, folder: &mut F) -> Result { Vec::from(self).try_fold_with(folder).map(Vec::into_boxed_slice) } + + fn fold_with>(self, folder: &mut F) -> Self { + Vec::into_boxed_slice(Vec::from(self).fold_with(folder)) + } } impl, Ix: Idx> TypeFoldable for IndexVec { fn try_fold_with>(self, folder: &mut F) -> Result { self.raw.try_fold_with(folder).map(IndexVec::from_raw) } + + fn fold_with>(self, folder: &mut F) -> Self { + IndexVec::from_raw(self.raw.fold_with(folder)) + } } /////////////////////////////////////////////////////////////////////////// diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index 59c2d3c2fc8d..417803e75ead 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -155,6 +155,39 @@ pub trait Ty>: fn is_known_rigid(self) -> bool { self.kind().is_known_rigid() } + + fn is_guaranteed_unsized_raw(self) -> bool { + match self.kind() { + ty::Dynamic(_, _, ty::Dyn) | ty::Slice(_) | ty::Str => true, + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Adt(_, _) + | ty::Foreign(_) + | ty::Array(_, _) + | ty::Pat(_, _) + | ty::RawPtr(_, _) + | ty::Ref(_, _, _) + | ty::FnDef(_, _) + | ty::FnPtr(_, _) + | ty::UnsafeBinder(_) + | ty::Closure(_, _) + | ty::CoroutineClosure(_, _) + | ty::Coroutine(_, _) + | ty::CoroutineWitness(_, _) + | ty::Never + | ty::Tuple(_) + | ty::Alias(_, _) + | ty::Param(_) + | ty::Bound(_, _) + | ty::Placeholder(_) + | ty::Infer(_) + | ty::Error(_) + | ty::Dynamic(_, _, ty::DynStar) => false, + } + } } pub trait Tys>: @@ -550,7 +583,7 @@ pub trait Span: Copy + Debug + Hash + Eq + TypeFoldable { pub trait SliceLike: Sized + Copy { type Item: Copy; - type IntoIter: Iterator; + type IntoIter: Iterator + DoubleEndedIterator; fn iter(self) -> Self::IntoIter; diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index fce93b735d79..71bfeabfda87 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -31,6 +31,7 @@ pub trait Interner: + IrPrint> + IrPrint> + IrPrint> + + IrPrint> { type DefId: DefId; type LocalDefId: Copy + Debug + Hash + Eq + Into + TypeFoldable; @@ -104,7 +105,14 @@ pub trait Interner: type ErrorGuaranteed: Copy + Debug + Hash + Eq; type BoundExistentialPredicates: BoundExistentialPredicates; type AllocId: Copy + Debug + Hash + Eq; - type Pat: Copy + Debug + Hash + Eq + Debug + Relate; + type Pat: Copy + + Debug + + Hash + + Eq + + Debug + + Relate + + Flags + + IntoKind>; type Safety: Safety; type Abi: Abi; @@ -255,6 +263,8 @@ pub trait Interner: def_id: Self::DefId, ) -> ty::EarlyBinder>>>; + fn impl_self_is_guaranteed_unsized(self, def_id: Self::DefId) -> bool; + fn has_target_features(self, def_id: Self::DefId) -> bool; fn require_lang_item(self, lang_item: TraitSolverLangItem) -> Self::DefId; diff --git a/compiler/rustc_type_ir/src/ir_print.rs b/compiler/rustc_type_ir/src/ir_print.rs index 0c71f3a3df2a..388ad09cb200 100644 --- a/compiler/rustc_type_ir/src/ir_print.rs +++ b/compiler/rustc_type_ir/src/ir_print.rs @@ -2,8 +2,8 @@ use std::fmt; use crate::{ AliasTerm, AliasTy, Binder, CoercePredicate, ExistentialProjection, ExistentialTraitRef, FnSig, - HostEffectPredicate, Interner, NormalizesTo, OutlivesPredicate, ProjectionPredicate, - SubtypePredicate, TraitPredicate, TraitRef, + HostEffectPredicate, Interner, NormalizesTo, OutlivesPredicate, PatternKind, + ProjectionPredicate, SubtypePredicate, TraitPredicate, TraitRef, }; pub trait IrPrint { @@ -57,9 +57,10 @@ define_display_via_print!( AliasTy, AliasTerm, FnSig, + PatternKind, ); -define_debug_via_print!(TraitRef, ExistentialTraitRef, ExistentialProjection); +define_debug_via_print!(TraitRef, ExistentialTraitRef, PatternKind); impl fmt::Display for OutlivesPredicate where diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index 4e2baca27854..792090effcff 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -1,12 +1,12 @@ // tidy-alphabetical-start #![allow(rustc::usage_of_ty_tykind)] #![allow(rustc::usage_of_type_ir_inherent)] +#![allow(rustc::usage_of_type_ir_traits)] #![cfg_attr( feature = "nightly", feature(associated_type_defaults, never_type, rustc_attrs, negative_impls) )] #![cfg_attr(feature = "nightly", allow(internal_features))] -#![cfg_attr(not(bootstrap), allow(rustc::usage_of_type_ir_traits))] // tidy-alphabetical-end extern crate self as rustc_type_ir; @@ -31,6 +31,7 @@ pub mod outlives; pub mod relate; pub mod search_graph; pub mod solve; +pub mod walk; // These modules are not `pub` since they are glob-imported. #[macro_use] @@ -44,6 +45,7 @@ mod generic_arg; mod infer_ctxt; mod interner; mod opaque_ty; +mod pattern; mod predicate; mod predicate_kind; mod region_kind; @@ -67,6 +69,7 @@ pub use generic_arg::*; pub use infer_ctxt::*; pub use interner::*; pub use opaque_ty::*; +pub use pattern::*; pub use predicate::*; pub use predicate_kind::*; pub use region_kind::*; diff --git a/compiler/rustc_type_ir/src/pattern.rs b/compiler/rustc_type_ir/src/pattern.rs new file mode 100644 index 000000000000..d74a82da1f92 --- /dev/null +++ b/compiler/rustc_type_ir/src/pattern.rs @@ -0,0 +1,16 @@ +use derive_where::derive_where; +#[cfg(feature = "nightly")] +use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext}; +use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic}; + +use crate::Interner; + +#[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)] +#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] +#[cfg_attr( + feature = "nightly", + derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext) +)] +pub enum PatternKind { + Range { start: I::Const, end: I::Const }, +} diff --git a/compiler/rustc_type_ir/src/predicate.rs b/compiler/rustc_type_ir/src/predicate.rs index 22d0fa23d0c5..8e10636ff657 100644 --- a/compiler/rustc_type_ir/src/predicate.rs +++ b/compiler/rustc_type_ir/src/predicate.rs @@ -374,7 +374,7 @@ impl ty::Binder> { } /// A `ProjectionPredicate` for an `ExistentialTraitRef`. -#[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)] +#[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] #[cfg_attr( feature = "nightly", diff --git a/compiler/rustc_type_ir/src/solve/inspect.rs b/compiler/rustc_type_ir/src/solve/inspect.rs index 18fb71dd290e..b10641b287d4 100644 --- a/compiler/rustc_type_ir/src/solve/inspect.rs +++ b/compiler/rustc_type_ir/src/solve/inspect.rs @@ -118,10 +118,12 @@ pub enum ProbeKind { /// Used in the probe that wraps normalizing the non-self type for the unsize /// trait, which is also structurally matched on. UnsizeAssembly, - /// During upcasting from some source object to target object type, used to - /// do a probe to find out what projection type(s) may be used to prove that - /// the source type upholds all of the target type's object bounds. - UpcastProjectionCompatibility, + /// Used to do a probe to find out what projection type(s) match a given + /// alias bound or projection predicate. For trait upcasting, this is used + /// to prove that the source type upholds all of the target type's object + /// bounds. For object type bounds, this is used when eagerly replacing + /// supertrait aliases. + ProjectionCompatibility, /// Looking for param-env candidates that satisfy the trait ref for a projection. ShadowedEnvProbing, /// Try to unify an opaque type with an existing key in the storage. diff --git a/compiler/rustc_type_ir/src/solve/mod.rs b/compiler/rustc_type_ir/src/solve/mod.rs index 3aec4804b279..4e9b87fdf74d 100644 --- a/compiler/rustc_type_ir/src/solve/mod.rs +++ b/compiler/rustc_type_ir/src/solve/mod.rs @@ -83,8 +83,11 @@ pub enum GoalSource { /// Instantiating a higher-ranked goal and re-proving it. InstantiateHigherRanked, /// Predicate required for an alias projection to be well-formed. - /// This is used in two places: projecting to an opaque whose hidden type - /// is already registered in the opaque type storage, and for rigid projections. + /// This is used in three places: + /// 1. projecting to an opaque whose hidden type is already registered in + /// the opaque type storage, + /// 2. for rigid projections's trait goal, + /// 3. for GAT where clauses. AliasWellFormed, /// In case normalizing aliases in nested goals cycles, eagerly normalizing these /// aliases in the context of the parent may incorrectly change the cycle kind. diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs index d35b22d517c5..753a72a051ad 100644 --- a/compiler/rustc_type_ir/src/ty_kind.rs +++ b/compiler/rustc_type_ir/src/ty_kind.rs @@ -6,9 +6,8 @@ use rustc_ast_ir::Mutability; #[cfg(feature = "nightly")] use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; #[cfg(feature = "nightly")] -use rustc_data_structures::unify::{NoError, UnifyKey, UnifyValue}; -#[cfg(feature = "nightly")] use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext}; +use rustc_type_ir::data_structures::{NoError, UnifyKey, UnifyValue}; use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic}; use self::TyKind::*; @@ -796,7 +795,6 @@ pub enum InferTy { /// Raw `TyVid` are used as the unification key for `sub_relations`; /// they carry no values. -#[cfg(feature = "nightly")] impl UnifyKey for TyVid { type Value = (); #[inline] @@ -812,7 +810,6 @@ impl UnifyKey for TyVid { } } -#[cfg(feature = "nightly")] impl UnifyValue for IntVarValue { type Error = NoError; @@ -832,7 +829,6 @@ impl UnifyValue for IntVarValue { } } -#[cfg(feature = "nightly")] impl UnifyKey for IntVid { type Value = IntVarValue; #[inline] // make this function eligible for inlining - it is quite hot. @@ -848,7 +844,6 @@ impl UnifyKey for IntVid { } } -#[cfg(feature = "nightly")] impl UnifyValue for FloatVarValue { type Error = NoError; @@ -866,7 +861,6 @@ impl UnifyValue for FloatVarValue { } } -#[cfg(feature = "nightly")] impl UnifyKey for FloatVid { type Value = FloatVarValue; #[inline] diff --git a/compiler/rustc_middle/src/ty/walk.rs b/compiler/rustc_type_ir/src/walk.rs similarity index 55% rename from compiler/rustc_middle/src/ty/walk.rs rename to compiler/rustc_type_ir/src/walk.rs index a23316ae6fc8..5683e1f1712c 100644 --- a/compiler/rustc_middle/src/ty/walk.rs +++ b/compiler/rustc_type_ir/src/walk.rs @@ -1,20 +1,21 @@ //! An iterator over the type substructure. //! WARNING: this does not keep track of the region depth. -use rustc_data_structures::sso::SsoHashSet; use smallvec::{SmallVec, smallvec}; use tracing::debug; -use crate::ty::{self, GenericArg, GenericArgKind, Ty}; +use crate::data_structures::SsoHashSet; +use crate::inherent::*; +use crate::{self as ty, Interner}; // The TypeWalker's stack is hot enough that it's worth going to some effort to // avoid heap allocations. -type TypeWalkerStack<'tcx> = SmallVec<[GenericArg<'tcx>; 8]>; +type TypeWalkerStack = SmallVec<[::GenericArg; 8]>; -pub struct TypeWalker<'tcx> { - stack: TypeWalkerStack<'tcx>, +pub struct TypeWalker { + stack: TypeWalkerStack, last_subtree: usize, - pub visited: SsoHashSet>, + pub visited: SsoHashSet, } /// An iterator for walking the type tree. @@ -25,8 +26,8 @@ pub struct TypeWalker<'tcx> { /// in this situation walker only visits each type once. /// It maintains a set of visited types and /// skips any types that are already there. -impl<'tcx> TypeWalker<'tcx> { - pub fn new(root: GenericArg<'tcx>) -> Self { +impl TypeWalker { + pub fn new(root: I::GenericArg) -> Self { Self { stack: smallvec![root], last_subtree: 1, visited: SsoHashSet::new() } } @@ -47,16 +48,16 @@ impl<'tcx> TypeWalker<'tcx> { } } -impl<'tcx> Iterator for TypeWalker<'tcx> { - type Item = GenericArg<'tcx>; +impl Iterator for TypeWalker { + type Item = I::GenericArg; - fn next(&mut self) -> Option> { + fn next(&mut self) -> Option { debug!("next(): stack={:?}", self.stack); loop { let next = self.stack.pop()?; self.last_subtree = self.stack.len(); if self.visited.insert(next) { - push_inner(&mut self.stack, next); + push_inner::(&mut self.stack, next); debug!("next: stack={:?}", self.stack); return Some(next); } @@ -64,63 +65,15 @@ impl<'tcx> Iterator for TypeWalker<'tcx> { } } -impl<'tcx> GenericArg<'tcx> { - /// Iterator that walks `self` and any types reachable from - /// `self`, in depth-first order. Note that just walks the types - /// that appear in `self`, it does not descend into the fields of - /// structs or variants. For example: - /// - /// ```text - /// isize => { isize } - /// Foo> => { Foo>, Bar, isize } - /// [isize] => { [isize], isize } - /// ``` - pub fn walk(self) -> TypeWalker<'tcx> { - TypeWalker::new(self) - } -} - -impl<'tcx> Ty<'tcx> { - /// Iterator that walks `self` and any types reachable from - /// `self`, in depth-first order. Note that just walks the types - /// that appear in `self`, it does not descend into the fields of - /// structs or variants. For example: - /// - /// ```text - /// isize => { isize } - /// Foo> => { Foo>, Bar, isize } - /// [isize] => { [isize], isize } - /// ``` - pub fn walk(self) -> TypeWalker<'tcx> { - TypeWalker::new(self.into()) - } -} - -impl<'tcx> ty::Const<'tcx> { - /// Iterator that walks `self` and any types reachable from - /// `self`, in depth-first order. Note that just walks the types - /// that appear in `self`, it does not descend into the fields of - /// structs or variants. For example: - /// - /// ```text - /// isize => { isize } - /// Foo> => { Foo>, Bar, isize } - /// [isize] => { [isize], isize } - /// ``` - pub fn walk(self) -> TypeWalker<'tcx> { - TypeWalker::new(self.into()) - } -} - /// We push `GenericArg`s on the stack in reverse order so as to /// maintain a pre-order traversal. As of the time of this /// writing, the fact that the traversal is pre-order is not /// known to be significant to any code, but it seems like the /// natural order one would expect (basically, the order of the /// types as they are written). -fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>) { - match parent.unpack() { - GenericArgKind::Type(parent_ty) => match *parent_ty.kind() { +fn push_inner(stack: &mut TypeWalkerStack, parent: I::GenericArg) { + match parent.kind() { + ty::GenericArgKind::Type(parent_ty) => match parent_ty.kind() { ty::Bool | ty::Char | ty::Int(_) @@ -136,7 +89,7 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>) | ty::Foreign(..) => {} ty::Pat(ty, pat) => { - match *pat { + match pat.kind() { ty::PatternKind::Range { start, end } => { stack.push(end.into()); stack.push(start.into()); @@ -163,22 +116,25 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>) } ty::Dynamic(obj, lt, _) => { stack.push(lt.into()); - stack.extend(obj.iter().rev().flat_map(|predicate| { - let (args, opt_ty) = match predicate.skip_binder() { - ty::ExistentialPredicate::Trait(tr) => (tr.args, None), - ty::ExistentialPredicate::Projection(p) => (p.args, Some(p.term)), - ty::ExistentialPredicate::AutoTrait(_) => - // Empty iterator - { - (ty::GenericArgs::empty(), None) - } - }; + stack.extend( + obj.iter() + .rev() + .filter_map(|predicate| { + let (args, opt_ty) = match predicate.skip_binder() { + ty::ExistentialPredicate::Trait(tr) => (tr.args, None), + ty::ExistentialPredicate::Projection(p) => (p.args, Some(p.term)), + ty::ExistentialPredicate::AutoTrait(_) => { + return None; + } + }; - args.iter().rev().chain(opt_ty.map(|term| match term.unpack() { - ty::TermKind::Ty(ty) => ty.into(), - ty::TermKind::Const(ct) => ct.into(), - })) - })); + Some(args.iter().rev().chain(opt_ty.map(|term| match term.kind() { + ty::TermKind::Ty(ty) => ty.into(), + ty::TermKind::Const(ct) => ct.into(), + }))) + }) + .flatten(), + ); } ty::Adt(_, args) | ty::Closure(_, args) @@ -188,7 +144,7 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>) | ty::FnDef(_, args) => { stack.extend(args.iter().rev()); } - ty::Tuple(ts) => stack.extend(ts.iter().rev().map(GenericArg::from)), + ty::Tuple(ts) => stack.extend(ts.iter().rev().map(|ty| ty.into())), ty::FnPtr(sig_tys, _hdr) => { stack.extend( sig_tys.skip_binder().inputs_and_output.iter().rev().map(|ty| ty.into()), @@ -198,15 +154,15 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>) stack.push(bound_ty.skip_binder().into()); } }, - GenericArgKind::Lifetime(_) => {} - GenericArgKind::Const(parent_ct) => match parent_ct.kind() { + ty::GenericArgKind::Lifetime(_) => {} + ty::GenericArgKind::Const(parent_ct) => match parent_ct.kind() { ty::ConstKind::Infer(_) | ty::ConstKind::Param(_) | ty::ConstKind::Placeholder(_) | ty::ConstKind::Bound(..) | ty::ConstKind::Error(_) => {} - ty::ConstKind::Value(cv) => stack.push(cv.ty.into()), + ty::ConstKind::Value(cv) => stack.push(cv.ty().into()), ty::ConstKind::Expr(expr) => stack.extend(expr.args().iter().rev()), ty::ConstKind::Unevaluated(ct) => { diff --git a/compiler/rustc_type_ir_macros/src/lib.rs b/compiler/rustc_type_ir_macros/src/lib.rs index 8eefecdc980e..3a10d0d41ef3 100644 --- a/compiler/rustc_type_ir_macros/src/lib.rs +++ b/compiler/rustc_type_ir_macros/src/lib.rs @@ -83,7 +83,7 @@ fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::Toke s.add_where_predicate(parse_quote! { I: Interner }); s.add_bounds(synstructure::AddBounds::Fields); s.bind_with(|_| synstructure::BindStyle::Move); - let body_fold = s.each_variant(|vi| { + let body_try_fold = s.each_variant(|vi| { let bindings = vi.bindings(); vi.construct(|_, index| { let bind = &bindings[index]; @@ -99,6 +99,22 @@ fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::Toke }) }); + let body_fold = s.each_variant(|vi| { + let bindings = vi.bindings(); + vi.construct(|_, index| { + let bind = &bindings[index]; + + // retain value of fields with #[type_foldable(identity)] + if has_ignore_attr(&bind.ast().attrs, "type_foldable", "identity") { + bind.to_token_stream() + } else { + quote! { + ::rustc_type_ir::TypeFoldable::fold_with(#bind, __folder) + } + } + }) + }); + // We filter fields which get ignored and don't require them to implement // `TypeFoldable`. We do so after generating `body_fold` as we still need // to generate code for them. @@ -111,7 +127,14 @@ fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::Toke self, __folder: &mut __F ) -> Result { - Ok(match self { #body_fold }) + Ok(match self { #body_try_fold }) + } + + fn fold_with<__F: ::rustc_type_ir::TypeFolder>( + self, + __folder: &mut __F + ) -> Self { + match self { #body_fold } } }, ) diff --git a/library/Cargo.lock b/library/Cargo.lock index ad634e9f794a..e4f1c4ec96a3 100644 --- a/library/Cargo.lock +++ b/library/Cargo.lock @@ -67,9 +67,9 @@ dependencies = [ [[package]] name = "compiler_builtins" -version = "0.1.152" +version = "0.1.155" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2153cf213eb259361567720ce55f6446f17acd0ccca87fb6dc05360578228a58" +checksum = "341e0830ca6170a4fcf02e92e57daf4b6f10142d48da32a547023867a6c8b35e" dependencies = [ "cc", "rustc-std-workspace-core", @@ -176,9 +176,9 @@ dependencies = [ [[package]] name = "miniz_oxide" -version = "0.8.7" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff70ce3e48ae43fa075863cef62e8b43b71a4f2382229920e0df362592919430" +checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" dependencies = [ "adler2", "compiler_builtins", diff --git a/library/alloc/Cargo.toml b/library/alloc/Cargo.toml index 1d2dd1e60819..cedbd330cbde 100644 --- a/library/alloc/Cargo.toml +++ b/library/alloc/Cargo.toml @@ -16,7 +16,7 @@ bench = false [dependencies] core = { path = "../core", public = true } -compiler_builtins = { version = "=0.1.152", features = ['rustc-dep-of-std'] } +compiler_builtins = { version = "=0.1.155", features = ['rustc-dep-of-std'] } [features] compiler-builtins-mem = ['compiler_builtins/mem'] diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs index 1e03a191276c..e1cc4ba25c4e 100644 --- a/library/alloc/src/alloc.rs +++ b/library/alloc/src/alloc.rs @@ -16,22 +16,22 @@ unsafe extern "Rust" { // otherwise. #[rustc_allocator] #[rustc_nounwind] - #[cfg_attr(not(bootstrap), rustc_std_internal_symbol)] + #[rustc_std_internal_symbol] fn __rust_alloc(size: usize, align: usize) -> *mut u8; #[rustc_deallocator] #[rustc_nounwind] - #[cfg_attr(not(bootstrap), rustc_std_internal_symbol)] + #[rustc_std_internal_symbol] fn __rust_dealloc(ptr: *mut u8, size: usize, align: usize); #[rustc_reallocator] #[rustc_nounwind] - #[cfg_attr(not(bootstrap), rustc_std_internal_symbol)] + #[rustc_std_internal_symbol] fn __rust_realloc(ptr: *mut u8, old_size: usize, align: usize, new_size: usize) -> *mut u8; #[rustc_allocator_zeroed] #[rustc_nounwind] - #[cfg_attr(not(bootstrap), rustc_std_internal_symbol)] + #[rustc_std_internal_symbol] fn __rust_alloc_zeroed(size: usize, align: usize) -> *mut u8; - #[cfg_attr(not(bootstrap), rustc_std_internal_symbol)] + #[rustc_std_internal_symbol] static __rust_no_alloc_shim_is_unstable: u8; } @@ -360,7 +360,7 @@ unsafe extern "Rust" { // This is the magic symbol to call the global alloc error handler. rustc generates // it to call `__rg_oom` if there is a `#[alloc_error_handler]`, or to call the // default implementations below (`__rdl_oom`) otherwise. - #[cfg_attr(not(bootstrap), rustc_std_internal_symbol)] + #[rustc_std_internal_symbol] fn __rust_alloc_error_handler(size: usize, align: usize) -> !; } @@ -427,7 +427,7 @@ pub mod __alloc_error_handler { unsafe extern "Rust" { // This symbol is emitted by rustc next to __rust_alloc_error_handler. // Its value depends on the -Zoom={panic,abort} compiler option. - #[cfg_attr(not(bootstrap), rustc_std_internal_symbol)] + #[rustc_std_internal_symbol] static __rust_alloc_error_handler_should_panic: u8; } diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index 4644e37f809c..4536f5554435 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -952,7 +952,7 @@ impl Box, A> { /// assert_eq!(*x, i); /// } /// ``` - #[stable(feature = "box_uninit_write", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "box_uninit_write", since = "1.87.0")] #[inline] pub fn write(mut boxed: Self, value: T) -> Box { unsafe { diff --git a/library/alloc/src/collections/btree/set_val.rs b/library/alloc/src/collections/btree/set_val.rs index cf30160bfbbc..5037b6578e80 100644 --- a/library/alloc/src/collections/btree/set_val.rs +++ b/library/alloc/src/collections/btree/set_val.rs @@ -9,7 +9,7 @@ pub(super) struct SetValZST; /// Returns `true` only for type `SetValZST`, `false` for all other types (blanket implementation). /// `TypeId` requires a `'static` lifetime, use of this trait avoids that restriction. /// -/// [`TypeId`]: std::any::TypeId +/// [`TypeId`]: core::any::TypeId pub(super) trait IsSetVal { fn is_set_val() -> bool; } diff --git a/library/alloc/src/collections/linked_list.rs b/library/alloc/src/collections/linked_list.rs index 3183268b4b32..cc42a120e4fa 100644 --- a/library/alloc/src/collections/linked_list.rs +++ b/library/alloc/src/collections/linked_list.rs @@ -1151,7 +1151,7 @@ impl LinkedList { /// assert_eq!(evens.into_iter().collect::>(), vec![2, 4, 6, 8, 14]); /// assert_eq!(odds.into_iter().collect::>(), vec![1, 3, 5, 9, 11, 13, 15]); /// ``` - #[stable(feature = "extract_if", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "extract_if", since = "1.87.0")] pub fn extract_if(&mut self, filter: F) -> ExtractIf<'_, T, F, A> where F: FnMut(&mut T) -> bool, @@ -1931,7 +1931,7 @@ impl<'a, T, A: Allocator> CursorMut<'a, T, A> { } /// An iterator produced by calling `extract_if` on LinkedList. -#[stable(feature = "extract_if", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "extract_if", since = "1.87.0")] #[must_use = "iterators are lazy and do nothing unless consumed"] pub struct ExtractIf< 'a, @@ -1946,7 +1946,7 @@ pub struct ExtractIf< old_len: usize, } -#[stable(feature = "extract_if", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "extract_if", since = "1.87.0")] impl Iterator for ExtractIf<'_, T, F, A> where F: FnMut(&mut T) -> bool, @@ -1975,7 +1975,7 @@ where } } -#[stable(feature = "extract_if", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "extract_if", since = "1.87.0")] impl fmt::Debug for ExtractIf<'_, T, F> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("ExtractIf").field(&self.list).finish() diff --git a/library/alloc/src/fmt.rs b/library/alloc/src/fmt.rs index e40de13f3d4a..30f42050ac8a 100644 --- a/library/alloc/src/fmt.rs +++ b/library/alloc/src/fmt.rs @@ -109,7 +109,7 @@ //! parameters (corresponding to `format_spec` in [the syntax](#syntax)). These //! parameters affect the string representation of what's being formatted. //! -//! The colon `:` in format syntax divides indentifier of the input data and +//! The colon `:` in format syntax divides identifier of the input data and //! the formatting options, the colon itself does not change anything, only //! introduces the options. //! diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 04858667230b..e70e6ca0d55d 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -104,6 +104,7 @@ #![feature(async_iterator)] #![feature(bstr)] #![feature(bstr_internals)] +#![feature(char_internals)] #![feature(char_max_len)] #![feature(clone_to_uninit)] #![feature(coerce_unsized)] diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 9236f5cb8d1f..9a161d057db0 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -1043,7 +1043,7 @@ impl String { #[inline] #[must_use = "`self` will be dropped if the result is not used"] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_vec_string_slice", since = "1.87.0")] #[rustc_allow_const_fn_unstable(const_precise_live_drops)] pub const fn into_bytes(self) -> Vec { self.vec @@ -1062,7 +1062,7 @@ impl String { #[must_use] #[stable(feature = "string_as_str", since = "1.7.0")] #[rustc_diagnostic_item = "string_as_str"] - #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_vec_string_slice", since = "1.87.0")] pub const fn as_str(&self) -> &str { // SAFETY: String contents are stipulated to be valid UTF-8, invalid contents are an error // at construction. @@ -1085,7 +1085,7 @@ impl String { #[must_use] #[stable(feature = "string_as_str", since = "1.7.0")] #[rustc_diagnostic_item = "string_as_mut_str"] - #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_vec_string_slice", since = "1.87.0")] pub const fn as_mut_str(&mut self) -> &mut str { // SAFETY: String contents are stipulated to be valid UTF-8, invalid contents are an error // at construction. @@ -1134,7 +1134,7 @@ impl String { /// assert_eq!(string, "abcdecdeabecde"); /// ``` #[cfg(not(no_global_oom_handling))] - #[stable(feature = "string_extend_from_within", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "string_extend_from_within", since = "1.87.0")] pub fn extend_from_within(&mut self, src: R) where R: RangeBounds, @@ -1159,7 +1159,7 @@ impl String { #[inline] #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_vec_string_slice", since = "1.87.0")] pub const fn capacity(&self) -> usize { self.vec.capacity() } @@ -1401,11 +1401,14 @@ impl String { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn push(&mut self, ch: char) { - match ch.len_utf8() { - 1 => self.vec.push(ch as u8), - _ => { - self.vec.extend_from_slice(ch.encode_utf8(&mut [0; char::MAX_LEN_UTF8]).as_bytes()) - } + let len = self.len(); + let ch_len = ch.len_utf8(); + self.reserve(ch_len); + + // SAFETY: Just reserved capacity for at least the length needed to encode `ch`. + unsafe { + core::char::encode_utf8_raw_unchecked(ch as u32, self.vec.as_mut_ptr().add(self.len())); + self.vec.set_len(len + ch_len); } } @@ -1425,7 +1428,7 @@ impl String { #[inline] #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_vec_string_slice", since = "1.87.0")] pub const fn as_bytes(&self) -> &[u8] { self.vec.as_slice() } @@ -1702,24 +1705,31 @@ impl String { #[rustc_confusables("set")] pub fn insert(&mut self, idx: usize, ch: char) { assert!(self.is_char_boundary(idx)); - let mut bits = [0; char::MAX_LEN_UTF8]; - let bits = ch.encode_utf8(&mut bits).as_bytes(); - unsafe { - self.insert_bytes(idx, bits); - } - } - - #[cfg(not(no_global_oom_handling))] - unsafe fn insert_bytes(&mut self, idx: usize, bytes: &[u8]) { let len = self.len(); - let amt = bytes.len(); - self.vec.reserve(amt); + let ch_len = ch.len_utf8(); + self.reserve(ch_len); + // SAFETY: Move the bytes starting from `idx` to their new location `ch_len` + // bytes ahead. This is safe because sufficient capacity was reserved, and `idx` + // is a char boundary. unsafe { - ptr::copy(self.vec.as_ptr().add(idx), self.vec.as_mut_ptr().add(idx + amt), len - idx); - ptr::copy_nonoverlapping(bytes.as_ptr(), self.vec.as_mut_ptr().add(idx), amt); - self.vec.set_len(len + amt); + ptr::copy( + self.vec.as_ptr().add(idx), + self.vec.as_mut_ptr().add(idx + ch_len), + len - idx, + ); + } + + // SAFETY: Encode the character into the vacated region if `idx != len`, + // or into the uninitialized spare capacity otherwise. + unsafe { + core::char::encode_utf8_raw_unchecked(ch as u32, self.vec.as_mut_ptr().add(idx)); + } + + // SAFETY: Update the length to include the newly added bytes. + unsafe { + self.vec.set_len(len + ch_len); } } @@ -1749,8 +1759,27 @@ impl String { pub fn insert_str(&mut self, idx: usize, string: &str) { assert!(self.is_char_boundary(idx)); + let len = self.len(); + let amt = string.len(); + self.reserve(amt); + + // SAFETY: Move the bytes starting from `idx` to their new location `amt` bytes + // ahead. This is safe because sufficient capacity was just reserved, and `idx` + // is a char boundary. unsafe { - self.insert_bytes(idx, string.as_bytes()); + ptr::copy(self.vec.as_ptr().add(idx), self.vec.as_mut_ptr().add(idx + amt), len - idx); + } + + // SAFETY: Copy the new string slice into the vacated region if `idx != len`, + // or into the uninitialized spare capacity otherwise. The borrow checker + // ensures that the source and destination do not overlap. + unsafe { + ptr::copy_nonoverlapping(string.as_ptr(), self.vec.as_mut_ptr().add(idx), amt); + } + + // SAFETY: Update the length to include the newly added bytes. + unsafe { + self.vec.set_len(len + amt); } } @@ -1779,7 +1808,7 @@ impl String { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_vec_string_slice", since = "1.87.0")] pub const unsafe fn as_mut_vec(&mut self) -> &mut Vec { &mut self.vec } @@ -1801,7 +1830,7 @@ impl String { #[inline] #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_vec_string_slice", since = "1.87.0")] #[rustc_confusables("length", "size")] pub const fn len(&self) -> usize { self.vec.len() @@ -1821,7 +1850,7 @@ impl String { #[inline] #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_vec_string_slice", since = "1.87.0")] pub const fn is_empty(&self) -> bool { self.len() == 0 } @@ -3140,7 +3169,7 @@ impl From for Vec { } } -#[stable(feature = "try_from_vec_u8_for_string", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "try_from_vec_u8_for_string", since = "1.87.0")] impl TryFrom> for String { type Error = FromUtf8Error; /// Converts the given [`Vec`] into a [`String`] if it contains valid UTF-8 data. diff --git a/library/alloc/src/vec/extract_if.rs b/library/alloc/src/vec/extract_if.rs index be869553ef4e..8a591a877964 100644 --- a/library/alloc/src/vec/extract_if.rs +++ b/library/alloc/src/vec/extract_if.rs @@ -15,7 +15,7 @@ use crate::alloc::{Allocator, Global}; /// let mut v = vec![0, 1, 2]; /// let iter: std::vec::ExtractIf<'_, _, _> = v.extract_if(.., |x| *x % 2 == 0); /// ``` -#[stable(feature = "extract_if", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "extract_if", since = "1.87.0")] #[derive(Debug)] #[must_use = "iterators are lazy and do nothing unless consumed"] pub struct ExtractIf< @@ -57,7 +57,7 @@ impl<'a, T, F, A: Allocator> ExtractIf<'a, T, F, A> { } } -#[stable(feature = "extract_if", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "extract_if", since = "1.87.0")] impl Iterator for ExtractIf<'_, T, F, A> where F: FnMut(&mut T) -> bool, @@ -93,7 +93,7 @@ where } } -#[stable(feature = "extract_if", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "extract_if", since = "1.87.0")] impl Drop for ExtractIf<'_, T, F, A> { fn drop(&mut self) { unsafe { diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 633ef717e04d..68e4add30e5d 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -66,7 +66,7 @@ use core::ptr::{self, NonNull}; use core::slice::{self, SliceIndex}; use core::{fmt, intrinsics}; -#[stable(feature = "extract_if", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "extract_if", since = "1.87.0")] pub use self::extract_if::ExtractIf; use crate::alloc::{Allocator, Global}; use crate::borrow::{Cow, ToOwned}; @@ -1267,7 +1267,7 @@ impl Vec { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_vec_string_slice", since = "1.87.0")] pub const fn capacity(&self) -> usize { self.buf.capacity() } @@ -1582,7 +1582,7 @@ impl Vec { #[inline] #[stable(feature = "vec_as_slice", since = "1.7.0")] #[rustc_diagnostic_item = "vec_as_slice"] - #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_vec_string_slice", since = "1.87.0")] pub const fn as_slice(&self) -> &[T] { // SAFETY: `slice::from_raw_parts` requires pointee is a contiguous, aligned buffer of size // `len` containing properly-initialized `T`s. Data must not be mutated for the returned @@ -1614,7 +1614,7 @@ impl Vec { #[inline] #[stable(feature = "vec_as_slice", since = "1.7.0")] #[rustc_diagnostic_item = "vec_as_mut_slice"] - #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_vec_string_slice", since = "1.87.0")] pub const fn as_mut_slice(&mut self) -> &mut [T] { // SAFETY: `slice::from_raw_parts_mut` requires pointee is a contiguous, aligned buffer of // size `len` containing properly-initialized `T`s. Data must not be accessed through any @@ -1686,7 +1686,7 @@ impl Vec { /// [`as_ptr`]: Vec::as_ptr /// [`as_non_null`]: Vec::as_non_null #[stable(feature = "vec_as_ptr", since = "1.37.0")] - #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_vec_string_slice", since = "1.87.0")] #[rustc_never_returns_null_ptr] #[rustc_as_ptr] #[inline] @@ -1749,7 +1749,7 @@ impl Vec { /// [`as_ptr`]: Vec::as_ptr /// [`as_non_null`]: Vec::as_non_null #[stable(feature = "vec_as_ptr", since = "1.37.0")] - #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_vec_string_slice", since = "1.87.0")] #[rustc_never_returns_null_ptr] #[rustc_as_ptr] #[inline] @@ -2700,7 +2700,7 @@ impl Vec { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_vec_string_slice", since = "1.87.0")] #[rustc_confusables("length", "size")] pub const fn len(&self) -> usize { let len = self.len; @@ -2726,7 +2726,7 @@ impl Vec { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_diagnostic_item = "vec_is_empty"] - #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_vec_string_slice", since = "1.87.0")] pub const fn is_empty(&self) -> bool { self.len() == 0 } @@ -2803,6 +2803,10 @@ impl Vec { /// want to use the [`Default`] trait to generate values, you can /// pass [`Default::default`] as the second argument. /// + /// # Panics + /// + /// Panics if the new capacity exceeds `isize::MAX` _bytes_. + /// /// # Examples /// /// ``` @@ -3010,6 +3014,10 @@ impl Vec { /// [`Clone`]), use [`Vec::resize_with`]. /// If you only need to resize to a smaller size, use [`Vec::truncate`]. /// + /// # Panics + /// + /// Panics if the new capacity exceeds `isize::MAX` _bytes_. + /// /// # Examples /// /// ``` @@ -3707,7 +3715,7 @@ impl Vec { /// assert_eq!(items, vec![0, 0, 0, 0, 0, 0, 0, 2, 2, 2]); /// assert_eq!(ones.len(), 3); /// ``` - #[stable(feature = "extract_if", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "extract_if", since = "1.87.0")] pub fn extract_if(&mut self, range: R, filter: F) -> ExtractIf<'_, T, F, A> where F: FnMut(&mut T) -> bool, diff --git a/library/alloctests/benches/string.rs b/library/alloctests/benches/string.rs index 3d79ab78c695..0bbec12e4fdc 100644 --- a/library/alloctests/benches/string.rs +++ b/library/alloctests/benches/string.rs @@ -4,7 +4,7 @@ use test::{Bencher, black_box}; #[bench] fn bench_with_capacity(b: &mut Bencher) { - b.iter(|| String::with_capacity(100)); + b.iter(|| String::with_capacity(black_box(100))); } #[bench] @@ -12,7 +12,8 @@ fn bench_push_str(b: &mut Bencher) { let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb"; b.iter(|| { let mut r = String::new(); - r.push_str(s); + black_box(&mut r).push_str(black_box(s)); + r }); } @@ -24,8 +25,9 @@ fn bench_push_str_one_byte(b: &mut Bencher) { b.iter(|| { let mut r = String::new(); for _ in 0..REPETITIONS { - r.push_str("a") + black_box(&mut r).push_str(black_box("a")); } + r }); } @@ -35,8 +37,9 @@ fn bench_push_char_one_byte(b: &mut Bencher) { b.iter(|| { let mut r = String::new(); for _ in 0..REPETITIONS { - r.push('a') + black_box(&mut r).push(black_box('a')); } + r }); } @@ -46,8 +49,9 @@ fn bench_push_char_two_bytes(b: &mut Bencher) { b.iter(|| { let mut r = String::new(); for _ in 0..REPETITIONS { - r.push('â') + black_box(&mut r).push(black_box('â')); } + r }); } @@ -57,34 +61,26 @@ fn from_utf8_lossy_100_ascii(b: &mut Bencher) { Lorem ipsum dolor sit amet, consectetur. "; assert_eq!(100, s.len()); - b.iter(|| { - let _ = String::from_utf8_lossy(s); - }); + b.iter(|| String::from_utf8_lossy(black_box(s))); } #[bench] fn from_utf8_lossy_100_multibyte(b: &mut Bencher) { let s = "𐌀𐌖𐌋𐌄𐌑𐌉ปรدولة الكويتทศไทย中华𐍅𐌿𐌻𐍆𐌹𐌻𐌰".as_bytes(); assert_eq!(100, s.len()); - b.iter(|| { - let _ = String::from_utf8_lossy(s); - }); + b.iter(|| String::from_utf8_lossy(black_box(s))); } #[bench] fn from_utf8_lossy_invalid(b: &mut Bencher) { let s = b"Hello\xC0\x80 There\xE6\x83 Goodbye"; - b.iter(|| { - let _ = String::from_utf8_lossy(s); - }); + b.iter(|| String::from_utf8_lossy(black_box(s))); } #[bench] fn from_utf8_lossy_100_invalid(b: &mut Bencher) { let s = repeat(0xf5).take(100).collect::>(); - b.iter(|| { - let _ = String::from_utf8_lossy(&s); - }); + b.iter(|| String::from_utf8_lossy(black_box(&s))); } #[bench] @@ -96,8 +92,8 @@ fn bench_exact_size_shrink_to_fit(b: &mut Bencher) { r.push_str(s); assert_eq!(r.len(), r.capacity()); b.iter(|| { - let mut r = String::with_capacity(s.len()); - r.push_str(s); + let mut r = String::with_capacity(black_box(s.len())); + r.push_str(black_box(s)); r.shrink_to_fit(); r }); @@ -107,21 +103,21 @@ fn bench_exact_size_shrink_to_fit(b: &mut Bencher) { fn bench_from_str(b: &mut Bencher) { let s = "Hello there, the quick brown fox jumped over the lazy dog! \ Lorem ipsum dolor sit amet, consectetur. "; - b.iter(|| String::from(s)) + b.iter(|| String::from(black_box(s))) } #[bench] fn bench_from(b: &mut Bencher) { let s = "Hello there, the quick brown fox jumped over the lazy dog! \ Lorem ipsum dolor sit amet, consectetur. "; - b.iter(|| String::from(s)) + b.iter(|| String::from(black_box(s))) } #[bench] fn bench_to_string(b: &mut Bencher) { let s = "Hello there, the quick brown fox jumped over the lazy dog! \ Lorem ipsum dolor sit amet, consectetur. "; - b.iter(|| s.to_string()) + b.iter(|| black_box(s).to_string()) } #[bench] @@ -129,7 +125,7 @@ fn bench_insert_char_short(b: &mut Bencher) { let s = "Hello, World!"; b.iter(|| { let mut x = String::from(s); - black_box(&mut x).insert(6, black_box(' ')); + black_box(&mut x).insert(black_box(6), black_box(' ')); x }) } @@ -139,7 +135,7 @@ fn bench_insert_char_long(b: &mut Bencher) { let s = "Hello, World!"; b.iter(|| { let mut x = String::from(s); - black_box(&mut x).insert(6, black_box('❤')); + black_box(&mut x).insert(black_box(6), black_box('❤')); x }) } @@ -149,7 +145,7 @@ fn bench_insert_str_short(b: &mut Bencher) { let s = "Hello, World!"; b.iter(|| { let mut x = String::from(s); - black_box(&mut x).insert_str(6, black_box(" ")); + black_box(&mut x).insert_str(black_box(6), black_box(" ")); x }) } @@ -159,7 +155,7 @@ fn bench_insert_str_long(b: &mut Bencher) { let s = "Hello, World!"; b.iter(|| { let mut x = String::from(s); - black_box(&mut x).insert_str(6, black_box(" rustic ")); + black_box(&mut x).insert_str(black_box(6), black_box(" rustic ")); x }) } diff --git a/library/core/Cargo.toml b/library/core/Cargo.toml index b60826ee4e6c..fe61f552a49d 100644 --- a/library/core/Cargo.toml +++ b/library/core/Cargo.toml @@ -32,8 +32,6 @@ check-cfg = [ 'cfg(bootstrap)', 'cfg(no_fp_fmt_parse)', 'cfg(stdarch_intel_sde)', - # #[cfg(bootstrap)] - 'cfg(target_feature, values("vector-enhancements-1"))', # core use #[path] imports to portable-simd `core_simd` crate # and to stdarch `core_arch` crate which messes-up with Cargo list # of declared features, we therefor expect any feature cfg diff --git a/library/core/src/array/iter.rs b/library/core/src/array/iter.rs index 1edade41597f..90f76d6d4c7b 100644 --- a/library/core/src/array/iter.rs +++ b/library/core/src/array/iter.rs @@ -1,38 +1,35 @@ //! Defines the `IntoIter` owned iterator for arrays. use crate::intrinsics::transmute_unchecked; -use crate::iter::{self, FusedIterator, TrustedLen, TrustedRandomAccessNoCoerce}; +use crate::iter::{FusedIterator, TrustedLen, TrustedRandomAccessNoCoerce}; use crate::mem::MaybeUninit; use crate::num::NonZero; -use crate::ops::{IndexRange, Range}; +use crate::ops::{IndexRange, Range, Try}; use crate::{fmt, ptr}; +mod iter_inner; + +type InnerSized = iter_inner::PolymorphicIter<[MaybeUninit; N]>; +type InnerUnsized = iter_inner::PolymorphicIter<[MaybeUninit]>; + /// A by-value [array] iterator. #[stable(feature = "array_value_iter", since = "1.51.0")] #[rustc_insignificant_dtor] #[rustc_diagnostic_item = "ArrayIntoIter"] +#[derive(Clone)] pub struct IntoIter { - /// This is the array we are iterating over. - /// - /// Elements with index `i` where `alive.start <= i < alive.end` have not - /// been yielded yet and are valid array entries. Elements with indices `i - /// < alive.start` or `i >= alive.end` have been yielded already and must - /// not be accessed anymore! Those dead elements might even be in a - /// completely uninitialized state! - /// - /// So the invariants are: - /// - `data[alive]` is alive (i.e. contains valid elements) - /// - `data[..alive.start]` and `data[alive.end..]` are dead (i.e. the - /// elements were already read and must not be touched anymore!) - data: [MaybeUninit; N], + inner: InnerSized, +} - /// The elements in `data` that have not been yielded yet. - /// - /// Invariants: - /// - `alive.end <= N` - /// - /// (And the `IndexRange` type requires `alive.start <= alive.end`.) - alive: IndexRange, +impl IntoIter { + #[inline] + fn unsize(&self) -> &InnerUnsized { + &self.inner + } + #[inline] + fn unsize_mut(&mut self) -> &mut InnerUnsized { + &mut self.inner + } } // Note: the `#[rustc_skip_during_method_dispatch(array)]` on `trait IntoIterator` @@ -53,6 +50,7 @@ impl IntoIterator for [T; N] { /// 2021 edition -- see the [array] Editions section for more information. /// /// [array]: prim@array + #[inline] fn into_iter(self) -> Self::IntoIter { // SAFETY: The transmute here is actually safe. The docs of `MaybeUninit` // promise: @@ -68,7 +66,10 @@ impl IntoIterator for [T; N] { // FIXME: If normal `transmute` ever gets smart enough to allow this // directly, use it instead of `transmute_unchecked`. let data: [MaybeUninit; N] = unsafe { transmute_unchecked(self) }; - IntoIter { data, alive: IndexRange::zero_to(N) } + // SAFETY: The original array was entirely initialized and the the alive + // range we're passing here represents that fact. + let inner = unsafe { InnerSized::new_unchecked(IndexRange::zero_to(N), data) }; + IntoIter { inner } } } @@ -136,13 +137,16 @@ impl IntoIter { /// assert_eq!(r.collect::>(), vec![10, 11, 12, 13, 14, 15]); /// ``` #[unstable(feature = "array_into_iter_constructors", issue = "91583")] + #[inline] pub const unsafe fn new_unchecked( buffer: [MaybeUninit; N], initialized: Range, ) -> Self { // SAFETY: one of our safety conditions is that the range is canonical. let alive = unsafe { IndexRange::new_unchecked(initialized.start, initialized.end) }; - Self { data: buffer, alive } + // SAFETY: one of our safety condition is that these items are initialized. + let inner = unsafe { InnerSized::new_unchecked(alive, buffer) }; + IntoIter { inner } } /// Creates an iterator over `T` which returns no elements. @@ -198,172 +202,134 @@ impl IntoIter { /// assert_eq!(get_bytes(false).collect::>(), vec![]); /// ``` #[unstable(feature = "array_into_iter_constructors", issue = "91583")] + #[inline] pub const fn empty() -> Self { - let buffer = [const { MaybeUninit::uninit() }; N]; - let initialized = 0..0; - - // SAFETY: We're telling it that none of the elements are initialized, - // which is trivially true. And ∀N: usize, 0 <= N. - unsafe { Self::new_unchecked(buffer, initialized) } + let inner = InnerSized::empty(); + IntoIter { inner } } /// Returns an immutable slice of all elements that have not been yielded /// yet. #[stable(feature = "array_value_iter", since = "1.51.0")] + #[inline] pub fn as_slice(&self) -> &[T] { - // SAFETY: We know that all elements within `alive` are properly initialized. - unsafe { - let slice = self.data.get_unchecked(self.alive.clone()); - slice.assume_init_ref() - } + self.unsize().as_slice() } /// Returns a mutable slice of all elements that have not been yielded yet. #[stable(feature = "array_value_iter", since = "1.51.0")] + #[inline] pub fn as_mut_slice(&mut self) -> &mut [T] { - // SAFETY: We know that all elements within `alive` are properly initialized. - unsafe { - let slice = self.data.get_unchecked_mut(self.alive.clone()); - slice.assume_init_mut() - } + self.unsize_mut().as_mut_slice() } } #[stable(feature = "array_value_iter_impls", since = "1.40.0")] impl Iterator for IntoIter { type Item = T; - fn next(&mut self) -> Option { - // Get the next index from the front. - // - // Increasing `alive.start` by 1 maintains the invariant regarding - // `alive`. However, due to this change, for a short time, the alive - // zone is not `data[alive]` anymore, but `data[idx..alive.end]`. - self.alive.next().map(|idx| { - // Read the element from the array. - // SAFETY: `idx` is an index into the former "alive" region of the - // array. Reading this element means that `data[idx]` is regarded as - // dead now (i.e. do not touch). As `idx` was the start of the - // alive-zone, the alive zone is now `data[alive]` again, restoring - // all invariants. - unsafe { self.data.get_unchecked(idx).assume_init_read() } - }) - } - fn size_hint(&self) -> (usize, Option) { - let len = self.len(); - (len, Some(len)) + #[inline] + fn next(&mut self) -> Option { + self.unsize_mut().next() } #[inline] - fn fold(mut self, init: Acc, mut fold: Fold) -> Acc + fn size_hint(&self) -> (usize, Option) { + self.unsize().size_hint() + } + + #[inline] + fn fold(mut self, init: Acc, fold: Fold) -> Acc where Fold: FnMut(Acc, Self::Item) -> Acc, { - let data = &mut self.data; - iter::ByRefSized(&mut self.alive).fold(init, |acc, idx| { - // SAFETY: idx is obtained by folding over the `alive` range, which implies the - // value is currently considered alive but as the range is being consumed each value - // we read here will only be read once and then considered dead. - fold(acc, unsafe { data.get_unchecked(idx).assume_init_read() }) - }) + self.unsize_mut().fold(init, fold) } + #[inline] + fn try_fold(&mut self, init: B, f: F) -> R + where + Self: Sized, + F: FnMut(B, Self::Item) -> R, + R: Try, + { + self.unsize_mut().try_fold(init, f) + } + + #[inline] fn count(self) -> usize { self.len() } + #[inline] fn last(mut self) -> Option { self.next_back() } + #[inline] fn advance_by(&mut self, n: usize) -> Result<(), NonZero> { - // This also moves the start, which marks them as conceptually "dropped", - // so if anything goes bad then our drop impl won't double-free them. - let range_to_drop = self.alive.take_prefix(n); - let remaining = n - range_to_drop.len(); - - // SAFETY: These elements are currently initialized, so it's fine to drop them. - unsafe { - let slice = self.data.get_unchecked_mut(range_to_drop); - slice.assume_init_drop(); - } - - NonZero::new(remaining).map_or(Ok(()), Err) + self.unsize_mut().advance_by(n) } #[inline] unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { // SAFETY: The caller must provide an idx that is in bound of the remainder. - unsafe { self.data.as_ptr().add(self.alive.start()).add(idx).cast::().read() } + let elem_ref = unsafe { self.as_mut_slice().get_unchecked_mut(idx) }; + // SAFETY: We only implement `TrustedRandomAccessNoCoerce` for types + // which are actually `Copy`, so cannot have multiple-drop issues. + unsafe { ptr::read(elem_ref) } } } #[stable(feature = "array_value_iter_impls", since = "1.40.0")] impl DoubleEndedIterator for IntoIter { + #[inline] fn next_back(&mut self) -> Option { - // Get the next index from the back. - // - // Decreasing `alive.end` by 1 maintains the invariant regarding - // `alive`. However, due to this change, for a short time, the alive - // zone is not `data[alive]` anymore, but `data[alive.start..=idx]`. - self.alive.next_back().map(|idx| { - // Read the element from the array. - // SAFETY: `idx` is an index into the former "alive" region of the - // array. Reading this element means that `data[idx]` is regarded as - // dead now (i.e. do not touch). As `idx` was the end of the - // alive-zone, the alive zone is now `data[alive]` again, restoring - // all invariants. - unsafe { self.data.get_unchecked(idx).assume_init_read() } - }) + self.unsize_mut().next_back() } #[inline] - fn rfold(mut self, init: Acc, mut rfold: Fold) -> Acc + fn rfold(mut self, init: Acc, rfold: Fold) -> Acc where Fold: FnMut(Acc, Self::Item) -> Acc, { - let data = &mut self.data; - iter::ByRefSized(&mut self.alive).rfold(init, |acc, idx| { - // SAFETY: idx is obtained by folding over the `alive` range, which implies the - // value is currently considered alive but as the range is being consumed each value - // we read here will only be read once and then considered dead. - rfold(acc, unsafe { data.get_unchecked(idx).assume_init_read() }) - }) + self.unsize_mut().rfold(init, rfold) } + #[inline] + fn try_rfold(&mut self, init: B, f: F) -> R + where + Self: Sized, + F: FnMut(B, Self::Item) -> R, + R: Try, + { + self.unsize_mut().try_rfold(init, f) + } + + #[inline] fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero> { - // This also moves the end, which marks them as conceptually "dropped", - // so if anything goes bad then our drop impl won't double-free them. - let range_to_drop = self.alive.take_suffix(n); - let remaining = n - range_to_drop.len(); - - // SAFETY: These elements are currently initialized, so it's fine to drop them. - unsafe { - let slice = self.data.get_unchecked_mut(range_to_drop); - slice.assume_init_drop(); - } - - NonZero::new(remaining).map_or(Ok(()), Err) + self.unsize_mut().advance_back_by(n) } } #[stable(feature = "array_value_iter_impls", since = "1.40.0")] impl Drop for IntoIter { + #[inline] fn drop(&mut self) { - // SAFETY: This is safe: `as_mut_slice` returns exactly the sub-slice - // of elements that have not been moved out yet and that remain - // to be dropped. - unsafe { ptr::drop_in_place(self.as_mut_slice()) } + // `inner` now handles this, but it'd technically be a breaking change + // to remove this `impl`, even though it's useless. } } #[stable(feature = "array_value_iter_impls", since = "1.40.0")] impl ExactSizeIterator for IntoIter { + #[inline] fn len(&self) -> usize { - self.alive.len() + self.inner.len() } + #[inline] fn is_empty(&self) -> bool { - self.alive.is_empty() + self.inner.len() == 0 } } @@ -396,32 +362,9 @@ where const MAY_HAVE_SIDE_EFFECT: bool = false; } -#[stable(feature = "array_value_iter_impls", since = "1.40.0")] -impl Clone for IntoIter { - fn clone(&self) -> Self { - // Note, we don't really need to match the exact same alive range, so - // we can just clone into offset 0 regardless of where `self` is. - let mut new = - Self { data: [const { MaybeUninit::uninit() }; N], alive: IndexRange::zero_to(0) }; - - // Clone all alive elements. - for (src, dst) in iter::zip(self.as_slice(), &mut new.data) { - // Write a clone into the new array, then update its alive range. - // If cloning panics, we'll correctly drop the previous items. - dst.write(src.clone()); - // This addition cannot overflow as we're iterating a slice - new.alive = IndexRange::zero_to(new.alive.end() + 1); - } - - new - } -} - #[stable(feature = "array_value_iter_impls", since = "1.40.0")] impl fmt::Debug for IntoIter { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - // Only print the elements that were not yielded yet: we cannot - // access the yielded elements anymore. - f.debug_tuple("IntoIter").field(&self.as_slice()).finish() + self.unsize().fmt(f) } } diff --git a/library/core/src/array/iter/iter_inner.rs b/library/core/src/array/iter/iter_inner.rs new file mode 100644 index 000000000000..3c2343591f8c --- /dev/null +++ b/library/core/src/array/iter/iter_inner.rs @@ -0,0 +1,281 @@ +//! Defines the `IntoIter` owned iterator for arrays. + +use crate::mem::MaybeUninit; +use crate::num::NonZero; +use crate::ops::{IndexRange, NeverShortCircuit, Try}; +use crate::{fmt, iter}; + +#[allow(private_bounds)] +trait PartialDrop { + /// # Safety + /// `self[alive]` are all initialized before the call, + /// then are never used (without reinitializing them) after it. + unsafe fn partial_drop(&mut self, alive: IndexRange); +} +impl PartialDrop for [MaybeUninit] { + unsafe fn partial_drop(&mut self, alive: IndexRange) { + // SAFETY: We know that all elements within `alive` are properly initialized. + unsafe { self.get_unchecked_mut(alive).assume_init_drop() } + } +} +impl PartialDrop for [MaybeUninit; N] { + unsafe fn partial_drop(&mut self, alive: IndexRange) { + let slice: &mut [MaybeUninit] = self; + // SAFETY: Initialized elements in the array are also initialized in the slice. + unsafe { slice.partial_drop(alive) } + } +} + +/// The internals of a by-value array iterator. +/// +/// The real `array::IntoIter` stores a `PolymorphicIter<[MaybeUninit, N]>` +/// which it unsizes to `PolymorphicIter<[MaybeUninit]>` to iterate. +#[allow(private_bounds)] +pub(super) struct PolymorphicIter +where + DATA: PartialDrop, +{ + /// The elements in `data` that have not been yielded yet. + /// + /// Invariants: + /// - `alive.end <= N` + /// + /// (And the `IndexRange` type requires `alive.start <= alive.end`.) + alive: IndexRange, + + /// This is the array we are iterating over. + /// + /// Elements with index `i` where `alive.start <= i < alive.end` have not + /// been yielded yet and are valid array entries. Elements with indices `i + /// < alive.start` or `i >= alive.end` have been yielded already and must + /// not be accessed anymore! Those dead elements might even be in a + /// completely uninitialized state! + /// + /// So the invariants are: + /// - `data[alive]` is alive (i.e. contains valid elements) + /// - `data[..alive.start]` and `data[alive.end..]` are dead (i.e. the + /// elements were already read and must not be touched anymore!) + data: DATA, +} + +#[allow(private_bounds)] +impl PolymorphicIter +where + DATA: PartialDrop, +{ + #[inline] + pub(super) const fn len(&self) -> usize { + self.alive.len() + } +} + +#[allow(private_bounds)] +impl Drop for PolymorphicIter +where + DATA: PartialDrop, +{ + #[inline] + fn drop(&mut self) { + // SAFETY: by our type invariant `self.alive` is exactly the initialized + // items, and this is drop so nothing can use the items afterwards. + unsafe { self.data.partial_drop(self.alive.clone()) } + } +} + +impl PolymorphicIter<[MaybeUninit; N]> { + #[inline] + pub(super) const fn empty() -> Self { + Self { alive: IndexRange::zero_to(0), data: [const { MaybeUninit::uninit() }; N] } + } + + /// # Safety + /// `data[alive]` are all initialized. + #[inline] + pub(super) const unsafe fn new_unchecked(alive: IndexRange, data: [MaybeUninit; N]) -> Self { + Self { alive, data } + } +} + +impl Clone for PolymorphicIter<[MaybeUninit; N]> { + #[inline] + fn clone(&self) -> Self { + // Note, we don't really need to match the exact same alive range, so + // we can just clone into offset 0 regardless of where `self` is. + let mut new = Self::empty(); + + fn clone_into_new( + source: &PolymorphicIter<[MaybeUninit]>, + target: &mut PolymorphicIter<[MaybeUninit]>, + ) { + // Clone all alive elements. + for (src, dst) in iter::zip(source.as_slice(), &mut target.data) { + // Write a clone into the new array, then update its alive range. + // If cloning panics, we'll correctly drop the previous items. + dst.write(src.clone()); + // This addition cannot overflow as we're iterating a slice, + // the length of which always fits in usize. + target.alive = IndexRange::zero_to(target.alive.end() + 1); + } + } + + clone_into_new(self, &mut new); + new + } +} + +impl PolymorphicIter<[MaybeUninit]> { + #[inline] + pub(super) fn as_slice(&self) -> &[T] { + // SAFETY: We know that all elements within `alive` are properly initialized. + unsafe { + let slice = self.data.get_unchecked(self.alive.clone()); + slice.assume_init_ref() + } + } + + #[inline] + pub(super) fn as_mut_slice(&mut self) -> &mut [T] { + // SAFETY: We know that all elements within `alive` are properly initialized. + unsafe { + let slice = self.data.get_unchecked_mut(self.alive.clone()); + slice.assume_init_mut() + } + } +} + +impl fmt::Debug for PolymorphicIter<[MaybeUninit]> { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // Only print the elements that were not yielded yet: we cannot + // access the yielded elements anymore. + f.debug_tuple("IntoIter").field(&self.as_slice()).finish() + } +} + +/// Iterator-equivalent methods. +/// +/// We don't implement the actual iterator traits because we want to implement +/// things like `try_fold` that require `Self: Sized` (which we're not). +impl PolymorphicIter<[MaybeUninit]> { + #[inline] + pub(super) fn next(&mut self) -> Option { + // Get the next index from the front. + // + // Increasing `alive.start` by 1 maintains the invariant regarding + // `alive`. However, due to this change, for a short time, the alive + // zone is not `data[alive]` anymore, but `data[idx..alive.end]`. + self.alive.next().map(|idx| { + // Read the element from the array. + // SAFETY: `idx` is an index into the former "alive" region of the + // array. Reading this element means that `data[idx]` is regarded as + // dead now (i.e. do not touch). As `idx` was the start of the + // alive-zone, the alive zone is now `data[alive]` again, restoring + // all invariants. + unsafe { self.data.get_unchecked(idx).assume_init_read() } + }) + } + + #[inline] + pub(super) fn size_hint(&self) -> (usize, Option) { + let len = self.len(); + (len, Some(len)) + } + + #[inline] + pub(super) fn advance_by(&mut self, n: usize) -> Result<(), NonZero> { + // This also moves the start, which marks them as conceptually "dropped", + // so if anything goes bad then our drop impl won't double-free them. + let range_to_drop = self.alive.take_prefix(n); + let remaining = n - range_to_drop.len(); + + // SAFETY: These elements are currently initialized, so it's fine to drop them. + unsafe { + let slice = self.data.get_unchecked_mut(range_to_drop); + slice.assume_init_drop(); + } + + NonZero::new(remaining).map_or(Ok(()), Err) + } + + #[inline] + pub(super) fn fold(&mut self, init: B, f: impl FnMut(B, T) -> B) -> B { + self.try_fold(init, NeverShortCircuit::wrap_mut_2(f)).0 + } + + #[inline] + pub(super) fn try_fold(&mut self, init: B, mut f: F) -> R + where + F: FnMut(B, T) -> R, + R: Try, + { + // `alive` is an `IndexRange`, not an arbitrary iterator, so we can + // trust that its `try_fold` isn't going to do something weird like + // call the fold-er multiple times for the same index. + let data = &mut self.data; + self.alive.try_fold(init, move |accum, idx| { + // SAFETY: `idx` has been removed from the alive range, so we're not + // going to drop it (even if `f` panics) and thus its ok to give + // out ownership of that item to `f` to handle. + let elem = unsafe { data.get_unchecked(idx).assume_init_read() }; + f(accum, elem) + }) + } + + #[inline] + pub(super) fn next_back(&mut self) -> Option { + // Get the next index from the back. + // + // Decreasing `alive.end` by 1 maintains the invariant regarding + // `alive`. However, due to this change, for a short time, the alive + // zone is not `data[alive]` anymore, but `data[alive.start..=idx]`. + self.alive.next_back().map(|idx| { + // Read the element from the array. + // SAFETY: `idx` is an index into the former "alive" region of the + // array. Reading this element means that `data[idx]` is regarded as + // dead now (i.e. do not touch). As `idx` was the end of the + // alive-zone, the alive zone is now `data[alive]` again, restoring + // all invariants. + unsafe { self.data.get_unchecked(idx).assume_init_read() } + }) + } + + #[inline] + pub(super) fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero> { + // This also moves the end, which marks them as conceptually "dropped", + // so if anything goes bad then our drop impl won't double-free them. + let range_to_drop = self.alive.take_suffix(n); + let remaining = n - range_to_drop.len(); + + // SAFETY: These elements are currently initialized, so it's fine to drop them. + unsafe { + let slice = self.data.get_unchecked_mut(range_to_drop); + slice.assume_init_drop(); + } + + NonZero::new(remaining).map_or(Ok(()), Err) + } + + #[inline] + pub(super) fn rfold(&mut self, init: B, f: impl FnMut(B, T) -> B) -> B { + self.try_rfold(init, NeverShortCircuit::wrap_mut_2(f)).0 + } + + #[inline] + pub(super) fn try_rfold(&mut self, init: B, mut f: F) -> R + where + F: FnMut(B, T) -> R, + R: Try, + { + // `alive` is an `IndexRange`, not an arbitrary iterator, so we can + // trust that its `try_rfold` isn't going to do something weird like + // call the fold-er multiple times for the same index. + let data = &mut self.data; + self.alive.try_rfold(init, move |accum, idx| { + // SAFETY: `idx` has been removed from the alive range, so we're not + // going to drop it (even if `f` panics) and thus its ok to give + // out ownership of that item to `f` to handle. + let elem = unsafe { data.get_unchecked(idx).assume_init_read() }; + f(accum, elem) + }) + } +} diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index 28329bb09084..efa7bed7c8e1 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -55,12 +55,16 @@ pub fn repeat(val: T) -> [T; N] { from_trusted_iterator(repeat_n(val, N)) } -/// Creates an array of type [T; N], where each element `T` is the returned value from `cb` -/// using that element's index. +/// Creates an array where each element is produced by calling `f` with +/// that element's index while walking forward through the array. /// -/// # Arguments +/// This is essentially the same as writing +/// ```text +/// [f(0), f(1), f(2), …, f(N - 2), f(N - 1)] +/// ``` +/// and is similar to `(0..i).map(f)`, just for arrays not iterators. /// -/// * `cb`: Callback where the passed argument is the current array index. +/// If `N == 0`, this produces an empty array without ever calling `f`. /// /// # Example /// @@ -82,13 +86,30 @@ pub fn repeat(val: T) -> [T; N] { /// // indexes are: 0 1 2 3 4 /// assert_eq!(bool_arr, [true, false, true, false, true]); /// ``` +/// +/// You can also capture things, for example to create an array full of clones +/// where you can't just use `[item; N]` because it's not `Copy`: +/// ``` +/// # // TBH `array::repeat` would be better for this, but it's not stable yet. +/// let my_string = String::from("Hello"); +/// let clones: [String; 42] = std::array::from_fn(|_| my_string.clone()); +/// assert!(clones.iter().all(|x| *x == my_string)); +/// ``` +/// +/// The array is generated in ascending index order, starting from the front +/// and going towards the back, so you can use closures with mutable state: +/// ``` +/// let mut state = 1; +/// let a = std::array::from_fn(|_| { let x = state; state *= 2; x }); +/// assert_eq!(a, [1, 2, 4, 8, 16, 32]); +/// ``` #[inline] #[stable(feature = "array_from_fn", since = "1.63.0")] -pub fn from_fn(cb: F) -> [T; N] +pub fn from_fn(f: F) -> [T; N] where F: FnMut(usize) -> T, { - try_from_fn(NeverShortCircuit::wrap_mut_1(cb)).0 + try_from_fn(NeverShortCircuit::wrap_mut_1(f)).0 } /// Creates an array `[T; N]` where each fallible array element `T` is returned by the `cb` call. diff --git a/library/core/src/bool.rs b/library/core/src/bool.rs index d525ab425e60..2016ece007eb 100644 --- a/library/core/src/bool.rs +++ b/library/core/src/bool.rs @@ -61,52 +61,4 @@ impl bool { pub fn then T>(self, f: F) -> Option { if self { Some(f()) } else { None } } - - /// Returns either `true_val` or `false_val` depending on the value of - /// `self`, with a hint to the compiler that `self` is unlikely - /// to be correctly predicted by a CPU’s branch predictor. - /// - /// This method is functionally equivalent to - /// ```ignore (this is just for illustrative purposes) - /// fn select_unpredictable(b: bool, true_val: T, false_val: T) -> T { - /// if b { true_val } else { false_val } - /// } - /// ``` - /// but might generate different assembly. In particular, on platforms with - /// a conditional move or select instruction (like `cmov` on x86 or `csel` - /// on ARM) the optimizer might use these instructions to avoid branches, - /// which can benefit performance if the branch predictor is struggling - /// with predicting `condition`, such as in an implementation of binary - /// search. - /// - /// Note however that this lowering is not guaranteed (on any platform) and - /// should not be relied upon when trying to write constant-time code. Also - /// be aware that this lowering might *decrease* performance if `condition` - /// is well-predictable. It is advisable to perform benchmarks to tell if - /// this function is useful. - /// - /// # Examples - /// - /// Distribute values evenly between two buckets: - /// ``` - /// #![feature(select_unpredictable)] - /// - /// use std::hash::BuildHasher; - /// - /// fn append(hasher: &H, v: i32, bucket_one: &mut Vec, bucket_two: &mut Vec) { - /// let hash = hasher.hash_one(&v); - /// let bucket = (hash % 2 == 0).select_unpredictable(bucket_one, bucket_two); - /// bucket.push(v); - /// } - /// # let hasher = std::collections::hash_map::RandomState::new(); - /// # let mut bucket_one = Vec::new(); - /// # let mut bucket_two = Vec::new(); - /// # append(&hasher, 42, &mut bucket_one, &mut bucket_two); - /// # assert_eq!(bucket_one.len() + bucket_two.len(), 1); - /// ``` - #[inline(always)] - #[unstable(feature = "select_unpredictable", issue = "133962")] - pub fn select_unpredictable(self, true_val: T, false_val: T) -> T { - crate::intrinsics::select_unpredictable(self, true_val, false_val) - } } diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index 09117e4968db..17231df731d1 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -1156,7 +1156,9 @@ impl RefCell { /// Since this method borrows `RefCell` mutably, it is statically guaranteed /// that no borrows to the underlying data exist. The dynamic checks inherent /// in [`borrow_mut`] and most other methods of `RefCell` are therefore - /// unnecessary. + /// unnecessary. Note that this method does not reset the borrowing state if borrows were previously leaked + /// (e.g., via [`forget()`] on a [`Ref`] or [`RefMut`]). For that purpose, + /// consider using the unstable [`undo_leak`] method. /// /// This method can only be called if `RefCell` can be mutably borrowed, /// which in general is only the case directly after the `RefCell` has @@ -1167,6 +1169,8 @@ impl RefCell { /// Use [`borrow_mut`] to get mutable access to the underlying data then. /// /// [`borrow_mut`]: RefCell::borrow_mut() + /// [`forget()`]: mem::forget + /// [`undo_leak`]: RefCell::undo_leak() /// /// # Examples /// diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs index fa584953bed5..042925a352f3 100644 --- a/library/core/src/char/methods.rs +++ b/library/core/src/char/methods.rs @@ -337,7 +337,7 @@ impl char { /// '1'.is_digit(1); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_char_classify", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_char_classify", since = "1.87.0")] #[inline] pub const fn is_digit(self, radix: u32) -> bool { self.to_digit(radix).is_some() @@ -886,7 +886,7 @@ impl char { /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_char_classify", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_char_classify", since = "1.87.0")] #[inline] pub const fn is_whitespace(self) -> bool { match self { @@ -1806,39 +1806,71 @@ const fn len_utf16(code: u32) -> usize { #[inline] pub const fn encode_utf8_raw(code: u32, dst: &mut [u8]) -> &mut [u8] { let len = len_utf8(code); - match (len, &mut *dst) { - (1, [a, ..]) => { - *a = code as u8; - } - (2, [a, b, ..]) => { - *a = (code >> 6 & 0x1F) as u8 | TAG_TWO_B; - *b = (code & 0x3F) as u8 | TAG_CONT; - } - (3, [a, b, c, ..]) => { - *a = (code >> 12 & 0x0F) as u8 | TAG_THREE_B; - *b = (code >> 6 & 0x3F) as u8 | TAG_CONT; - *c = (code & 0x3F) as u8 | TAG_CONT; - } - (4, [a, b, c, d, ..]) => { - *a = (code >> 18 & 0x07) as u8 | TAG_FOUR_B; - *b = (code >> 12 & 0x3F) as u8 | TAG_CONT; - *c = (code >> 6 & 0x3F) as u8 | TAG_CONT; - *d = (code & 0x3F) as u8 | TAG_CONT; - } - _ => { - const_panic!( - "encode_utf8: buffer does not have enough bytes to encode code point", - "encode_utf8: need {len} bytes to encode U+{code:04X} but buffer has just {dst_len}", - code: u32 = code, - len: usize = len, - dst_len: usize = dst.len(), - ) - } - }; + if dst.len() < len { + const_panic!( + "encode_utf8: buffer does not have enough bytes to encode code point", + "encode_utf8: need {len} bytes to encode U+{code:04X} but buffer has just {dst_len}", + code: u32 = code, + len: usize = len, + dst_len: usize = dst.len(), + ); + } + + // SAFETY: `dst` is checked to be at least the length needed to encode the codepoint. + unsafe { encode_utf8_raw_unchecked(code, dst.as_mut_ptr()) }; + // SAFETY: `<&mut [u8]>::as_mut_ptr` is guaranteed to return a valid pointer and `len` has been tested to be within bounds. unsafe { slice::from_raw_parts_mut(dst.as_mut_ptr(), len) } } +/// Encodes a raw `u32` value as UTF-8 into the byte buffer pointed to by `dst`. +/// +/// Unlike `char::encode_utf8`, this method also handles codepoints in the surrogate range. +/// (Creating a `char` in the surrogate range is UB.) +/// The result is valid [generalized UTF-8] but not valid UTF-8. +/// +/// [generalized UTF-8]: https://simonsapin.github.io/wtf-8/#generalized-utf8 +/// +/// # Safety +/// +/// The behavior is undefined if the buffer pointed to by `dst` is not +/// large enough to hold the encoded codepoint. A buffer of length four +/// is large enough to encode any `char`. +/// +/// For a safe version of this function, see the [`encode_utf8_raw`] function. +#[unstable(feature = "char_internals", reason = "exposed only for libstd", issue = "none")] +#[doc(hidden)] +#[inline] +pub const unsafe fn encode_utf8_raw_unchecked(code: u32, dst: *mut u8) { + let len = len_utf8(code); + // SAFETY: The caller must guarantee that the buffer pointed to by `dst` + // is at least `len` bytes long. + unsafe { + match len { + 1 => { + *dst = code as u8; + } + 2 => { + *dst = (code >> 6 & 0x1F) as u8 | TAG_TWO_B; + *dst.add(1) = (code & 0x3F) as u8 | TAG_CONT; + } + 3 => { + *dst = (code >> 12 & 0x0F) as u8 | TAG_THREE_B; + *dst.add(1) = (code >> 6 & 0x3F) as u8 | TAG_CONT; + *dst.add(2) = (code & 0x3F) as u8 | TAG_CONT; + } + 4 => { + *dst = (code >> 18 & 0x07) as u8 | TAG_FOUR_B; + *dst.add(1) = (code >> 12 & 0x3F) as u8 | TAG_CONT; + *dst.add(2) = (code >> 6 & 0x3F) as u8 | TAG_CONT; + *dst.add(3) = (code & 0x3F) as u8 | TAG_CONT; + } + // SAFETY: `char` always takes between 1 and 4 bytes to encode in UTF-8. + _ => crate::hint::unreachable_unchecked(), + } + } +} + /// Encodes a raw `u32` value as native endian UTF-16 into the provided `u16` buffer, /// and then returns the subslice of the buffer that contains the encoded character. /// diff --git a/library/core/src/char/mod.rs b/library/core/src/char/mod.rs index 088c709f1a2a..5b9f0e2143f5 100644 --- a/library/core/src/char/mod.rs +++ b/library/core/src/char/mod.rs @@ -38,7 +38,7 @@ pub use self::decode::{DecodeUtf16, DecodeUtf16Error}; #[unstable(feature = "char_internals", reason = "exposed only for libstd", issue = "none")] pub use self::methods::encode_utf16_raw; // perma-unstable #[unstable(feature = "char_internals", reason = "exposed only for libstd", issue = "none")] -pub use self::methods::encode_utf8_raw; // perma-unstable +pub use self::methods::{encode_utf8_raw, encode_utf8_raw_unchecked}; // perma-unstable #[rustfmt::skip] use crate::ascii; diff --git a/library/core/src/clone.rs b/library/core/src/clone.rs index e0ac0bfc5289..c237ac84cf40 100644 --- a/library/core/src/clone.rs +++ b/library/core/src/clone.rs @@ -216,7 +216,7 @@ pub macro Clone($item:item) { /// Use closures allow captured values to be automatically used. /// This is similar to have a closure that you would call `.use` over each captured value. #[unstable(feature = "ergonomic_clones", issue = "132290")] -#[cfg_attr(not(bootstrap), lang = "use_cloned")] +#[lang = "use_cloned"] pub trait UseCloned: Clone { // Empty. } @@ -427,7 +427,7 @@ pub unsafe trait CloneToUninit { /// read or dropped, because even if it was previously valid, it may have been partially /// overwritten. /// - /// The caller may wish to to take care to deallocate the allocation pointed to by `dest`, + /// The caller may wish to take care to deallocate the allocation pointed to by `dest`, /// if applicable, to avoid a memory leak (but this is not a requirement). /// /// Implementors should avoid leaking values by, upon unwinding, dropping all component values diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index 0dc2cc72e06c..c315131f4136 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -2053,6 +2053,22 @@ mod impls { fn ge(&self, other: &&B) -> bool { PartialOrd::ge(*self, *other) } + #[inline] + fn __chaining_lt(&self, other: &&B) -> ControlFlow { + PartialOrd::__chaining_lt(*self, *other) + } + #[inline] + fn __chaining_le(&self, other: &&B) -> ControlFlow { + PartialOrd::__chaining_le(*self, *other) + } + #[inline] + fn __chaining_gt(&self, other: &&B) -> ControlFlow { + PartialOrd::__chaining_gt(*self, *other) + } + #[inline] + fn __chaining_ge(&self, other: &&B) -> ControlFlow { + PartialOrd::__chaining_ge(*self, *other) + } } #[stable(feature = "rust1", since = "1.0.0")] impl Ord for &A @@ -2108,6 +2124,22 @@ mod impls { fn ge(&self, other: &&mut B) -> bool { PartialOrd::ge(*self, *other) } + #[inline] + fn __chaining_lt(&self, other: &&mut B) -> ControlFlow { + PartialOrd::__chaining_lt(*self, *other) + } + #[inline] + fn __chaining_le(&self, other: &&mut B) -> ControlFlow { + PartialOrd::__chaining_le(*self, *other) + } + #[inline] + fn __chaining_gt(&self, other: &&mut B) -> ControlFlow { + PartialOrd::__chaining_gt(*self, *other) + } + #[inline] + fn __chaining_ge(&self, other: &&mut B) -> ControlFlow { + PartialOrd::__chaining_ge(*self, *other) + } } #[stable(feature = "rust1", since = "1.0.0")] impl Ord for &mut A diff --git a/library/core/src/contracts.rs b/library/core/src/contracts.rs index 8b79a3a7eba8..495f84bce4bf 100644 --- a/library/core/src/contracts.rs +++ b/library/core/src/contracts.rs @@ -2,19 +2,23 @@ pub use crate::macros::builtin::{contracts_ensures as ensures, contracts_requires as requires}; -/// Emitted by rustc as a desugaring of `#[ensures(PRED)] fn foo() -> R { ... [return R;] ... }` -/// into: `fn foo() { let _check = build_check_ensures(|ret| PRED) ... [return _check(R);] ... }` -/// (including the implicit return of the tail expression, if any). +/// This is an identity function used as part of the desugaring of the `#[ensures]` attribute. +/// +/// This is an existing hack to allow users to omit the type of the return value in their ensures +/// attribute. +/// +/// Ideally, rustc should be able to generate the type annotation. +/// The existing lowering logic makes it rather hard to add the explicit type annotation, +/// while the function call is fairly straight forward. #[unstable(feature = "contracts_internals", issue = "128044" /* compiler-team#759 */)] +// Similar to `contract_check_requires`, we need to use the user-facing +// `contracts` feature rather than the perma-unstable `contracts_internals`. +// Const-checking doesn't honor allow_internal_unstable logic used by contract expansion. +#[rustc_const_unstable(feature = "contracts", issue = "128044")] #[lang = "contract_build_check_ensures"] -#[track_caller] -pub fn build_check_ensures(cond: C) -> impl (Fn(Ret) -> Ret) + Copy +pub const fn build_check_ensures(cond: C) -> C where - C: for<'a> Fn(&'a Ret) -> bool + Copy + 'static, + C: Fn(&Ret) -> bool + Copy + 'static, { - #[track_caller] - move |ret| { - crate::intrinsics::contract_check_ensures(&ret, cond); - ret - } + cond } diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index ec7c1705fb86..580f95eddce7 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -7,7 +7,7 @@ use crate::char::{EscapeDebugExtArgs, MAX_LEN_UTF8}; use crate::marker::PhantomData; use crate::num::fmt as numfmt; use crate::ops::Deref; -use crate::{iter, mem, result, str}; +use crate::{iter, result, str}; mod builders; #[cfg(not(no_fp_fmt_parse))] @@ -1515,19 +1515,6 @@ unsafe fn run(fmt: &mut Formatter<'_>, arg: &rt::Placeholder, args: &[rt::Argume // which guarantees the indexes are always within bounds. unsafe { (getcount(args, &arg.width), getcount(args, &arg.precision)) }; - #[cfg(bootstrap)] - let options = - *FormattingOptions { flags: flags::ALWAYS_SET | arg.flags << 21, width: 0, precision: 0 } - .align(match arg.align { - rt::Alignment::Left => Some(Alignment::Left), - rt::Alignment::Right => Some(Alignment::Right), - rt::Alignment::Center => Some(Alignment::Center), - rt::Alignment::Unknown => None, - }) - .fill(arg.fill) - .width(width) - .precision(precision); - #[cfg(not(bootstrap))] let options = FormattingOptions { flags: arg.flags, width, precision }; // Extract the correct argument @@ -1544,21 +1531,6 @@ unsafe fn run(fmt: &mut Formatter<'_>, arg: &rt::Placeholder, args: &[rt::Argume unsafe { value.fmt(fmt) } } -#[cfg(bootstrap)] -unsafe fn getcount(args: &[rt::Argument<'_>], cnt: &rt::Count) -> Option { - match *cnt { - rt::Count::Is(n) => Some(n as u16), - rt::Count::Implied => None, - rt::Count::Param(i) => { - debug_assert!(i < args.len()); - // SAFETY: cnt and args come from the same Arguments, - // which guarantees this index is always within bounds. - unsafe { args.get_unchecked(i).as_u16() } - } - } -} - -#[cfg(not(bootstrap))] unsafe fn getcount(args: &[rt::Argument<'_>], cnt: &rt::Count) -> u16 { match *cnt { rt::Count::Is(n) => n, diff --git a/library/core/src/fmt/rt.rs b/library/core/src/fmt/rt.rs index 0b04ebccae2b..adcfdd309b7e 100644 --- a/library/core/src/fmt/rt.rs +++ b/library/core/src/fmt/rt.rs @@ -11,10 +11,6 @@ use crate::ptr::NonNull; #[derive(Copy, Clone)] pub struct Placeholder { pub position: usize, - #[cfg(bootstrap)] - pub fill: char, - #[cfg(bootstrap)] - pub align: Alignment, pub flags: u32, pub precision: Count, pub width: Count, @@ -23,38 +19,17 @@ pub struct Placeholder { #[cfg(bootstrap)] impl Placeholder { #[inline] - pub const fn new( - position: usize, - fill: char, - align: Alignment, - flags: u32, - precision: Count, - width: Count, - ) -> Self { - Self { position, fill, align, flags, precision, width } + pub const fn new(position: usize, flags: u32, precision: Count, width: Count) -> Self { + Self { position, flags, precision, width } } } -#[cfg(bootstrap)] -#[lang = "format_alignment"] -#[derive(Copy, Clone, PartialEq, Eq)] -pub enum Alignment { - Left, - Right, - Center, - Unknown, -} - /// Used by [width](https://doc.rust-lang.org/std/fmt/#width) /// and [precision](https://doc.rust-lang.org/std/fmt/#precision) specifiers. #[lang = "format_count"] #[derive(Copy, Clone)] pub enum Count { /// Specified with a literal number, stores the value - #[cfg(bootstrap)] - Is(usize), - /// Specified with a literal number, stores the value - #[cfg(not(bootstrap))] Is(u16), /// Specified using `$` and `*` syntaxes, stores the index into `args` Param(usize), @@ -90,61 +65,92 @@ pub struct Argument<'a> { ty: ArgumentType<'a>, } -#[rustc_diagnostic_item = "ArgumentMethods"] -impl Argument<'_> { - #[inline] - const fn new<'a, T>(x: &'a T, f: fn(&T, &mut Formatter<'_>) -> Result) -> Argument<'a> { +macro_rules! argument_new { + ($t:ty, $x:expr, $f:expr) => { Argument { // INVARIANT: this creates an `ArgumentType<'a>` from a `&'a T` and // a `fn(&T, ...)`, so the invariant is maintained. ty: ArgumentType::Placeholder { - value: NonNull::from_ref(x).cast(), - // SAFETY: function pointers always have the same layout. - formatter: unsafe { mem::transmute(f) }, + value: NonNull::<$t>::from_ref($x).cast(), + // The Rust ABI considers all pointers to be equivalent, so transmuting a fn(&T) to + // fn(NonNull<()>) and calling it with a NonNull<()> that points at a T is allowed. + // However, the CFI sanitizer does not allow this, and triggers a crash when it + // happens. + // + // To avoid this crash, we use a helper function when CFI is enabled. To avoid the + // cost of this helper function (mainly code-size) when it is not needed, we + // transmute the function pointer otherwise. + // + // This is similar to what the Rust compiler does internally with vtables when KCFI + // is enabled, where it generates trampoline functions that only serve to adjust the + // expected type of the argument. `ArgumentType::Placeholder` is a bit like a + // manually constructed trait object, so it is not surprising that the same approach + // has to be applied here as well. + // + // It is still considered problematic (from the Rust side) that CFI rejects entirely + // legal Rust programs, so we do not consider anything done here a stable guarantee, + // but meanwhile we carry this work-around to keep Rust compatible with CFI and + // KCFI. + #[cfg(not(any(sanitize = "cfi", sanitize = "kcfi")))] + formatter: { + let f: fn(&$t, &mut Formatter<'_>) -> Result = $f; + // SAFETY: This is only called with `value`, which has the right type. + unsafe { core::mem::transmute(f) } + }, + #[cfg(any(sanitize = "cfi", sanitize = "kcfi"))] + formatter: |ptr: NonNull<()>, fmt: &mut Formatter<'_>| { + let func = $f; + // SAFETY: This is the same type as the `value` field. + let r = unsafe { ptr.cast::<$t>().as_ref() }; + (func)(r, fmt) + }, _lifetime: PhantomData, }, } - } + }; +} +#[rustc_diagnostic_item = "ArgumentMethods"] +impl Argument<'_> { #[inline] pub fn new_display(x: &T) -> Argument<'_> { - Self::new(x, Display::fmt) + argument_new!(T, x, ::fmt) } #[inline] pub fn new_debug(x: &T) -> Argument<'_> { - Self::new(x, Debug::fmt) + argument_new!(T, x, ::fmt) } #[inline] pub fn new_debug_noop(x: &T) -> Argument<'_> { - Self::new(x, |_, _| Ok(())) + argument_new!(T, x, |_: &T, _| Ok(())) } #[inline] pub fn new_octal(x: &T) -> Argument<'_> { - Self::new(x, Octal::fmt) + argument_new!(T, x, ::fmt) } #[inline] pub fn new_lower_hex(x: &T) -> Argument<'_> { - Self::new(x, LowerHex::fmt) + argument_new!(T, x, ::fmt) } #[inline] pub fn new_upper_hex(x: &T) -> Argument<'_> { - Self::new(x, UpperHex::fmt) + argument_new!(T, x, ::fmt) } #[inline] pub fn new_pointer(x: &T) -> Argument<'_> { - Self::new(x, Pointer::fmt) + argument_new!(T, x, ::fmt) } #[inline] pub fn new_binary(x: &T) -> Argument<'_> { - Self::new(x, Binary::fmt) + argument_new!(T, x, ::fmt) } #[inline] pub fn new_lower_exp(x: &T) -> Argument<'_> { - Self::new(x, LowerExp::fmt) + argument_new!(T, x, ::fmt) } #[inline] pub fn new_upper_exp(x: &T) -> Argument<'_> { - Self::new(x, UpperExp::fmt) + argument_new!(T, x, ::fmt) } #[inline] #[track_caller] @@ -160,11 +166,6 @@ impl Argument<'_> { /// # Safety /// /// This argument must actually be a placeholder argument. - /// - // FIXME: Transmuting formatter in new and indirectly branching to/calling - // it here is an explicit CFI violation. - #[allow(inline_no_sanitize)] - #[no_sanitize(cfi, kcfi)] #[inline] pub(super) unsafe fn fmt(&self, f: &mut Formatter<'_>) -> Result { match self.ty { diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs index 5ce282b05de7..1ca23ab6eea6 100644 --- a/library/core/src/hint.rs +++ b/library/core/src/hint.rs @@ -4,6 +4,7 @@ //! //! Hints may be compile time or runtime. +use crate::mem::MaybeUninit; use crate::{intrinsics, ub_checks}; /// Informs the compiler that the site which is calling this function is not @@ -734,3 +735,63 @@ pub const fn unlikely(b: bool) -> bool { pub const fn cold_path() { crate::intrinsics::cold_path() } + +/// Returns either `true_val` or `false_val` depending on the value of +/// `condition`, with a hint to the compiler that `condition` is unlikely to be +/// correctly predicted by a CPU’s branch predictor. +/// +/// This method is functionally equivalent to +/// ```ignore (this is just for illustrative purposes) +/// fn select_unpredictable(b: bool, true_val: T, false_val: T) -> T { +/// if b { true_val } else { false_val } +/// } +/// ``` +/// but might generate different assembly. In particular, on platforms with +/// a conditional move or select instruction (like `cmov` on x86 or `csel` +/// on ARM) the optimizer might use these instructions to avoid branches, +/// which can benefit performance if the branch predictor is struggling +/// with predicting `condition`, such as in an implementation of binary +/// search. +/// +/// Note however that this lowering is not guaranteed (on any platform) and +/// should not be relied upon when trying to write cryptographic constant-time +/// code. Also be aware that this lowering might *decrease* performance if +/// `condition` is well-predictable. It is advisable to perform benchmarks to +/// tell if this function is useful. +/// +/// # Examples +/// +/// Distribute values evenly between two buckets: +/// ``` +/// #![feature(select_unpredictable)] +/// +/// use std::hash::BuildHasher; +/// use std::hint; +/// +/// fn append(hasher: &H, v: i32, bucket_one: &mut Vec, bucket_two: &mut Vec) { +/// let hash = hasher.hash_one(&v); +/// let bucket = hint::select_unpredictable(hash % 2 == 0, bucket_one, bucket_two); +/// bucket.push(v); +/// } +/// # let hasher = std::collections::hash_map::RandomState::new(); +/// # let mut bucket_one = Vec::new(); +/// # let mut bucket_two = Vec::new(); +/// # append(&hasher, 42, &mut bucket_one, &mut bucket_two); +/// # assert_eq!(bucket_one.len() + bucket_two.len(), 1); +/// ``` +#[inline(always)] +#[unstable(feature = "select_unpredictable", issue = "133962")] +pub fn select_unpredictable(condition: bool, true_val: T, false_val: T) -> T { + // FIXME(https://github.com/rust-lang/unsafe-code-guidelines/issues/245): + // Change this to use ManuallyDrop instead. + let mut true_val = MaybeUninit::new(true_val); + let mut false_val = MaybeUninit::new(false_val); + // SAFETY: The value that is not selected is dropped, and the selected one + // is returned. This is necessary because the intrinsic doesn't drop the + // value that is not selected. + unsafe { + crate::intrinsics::select_unpredictable(!condition, &mut true_val, &mut false_val) + .assume_init_drop(); + crate::intrinsics::select_unpredictable(condition, true_val, false_val).assume_init() + } +} diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index afd6192d7c47..a01efb2adebe 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -5,14 +5,11 @@ //! //! # Const intrinsics //! -//! Note: any changes to the constness of intrinsics should be discussed with the language team. -//! This includes changes in the stability of the constness. -//! -//! In order to make an intrinsic usable at compile-time, it needs to be declared in the "new" -//! style, i.e. as a `#[rustc_intrinsic]` function, not inside an `extern` block. Then copy the -//! implementation from to +//! In order to make an intrinsic unstable usable at compile-time, copy the implementation from +//! to //! -//! and make the intrinsic declaration a `const fn`. +//! and make the intrinsic declaration below a `const fn`. This should be done in coordination with +//! wg-const-eval. //! //! If an intrinsic is supposed to be used from a `const fn` with a `rustc_const_stable` attribute, //! `#[rustc_intrinsic_const_stable_indirect]` needs to be added to the intrinsic. Such a change requires @@ -1329,7 +1326,9 @@ pub const fn unlikely(b: bool) -> bool { /// Therefore, implementations must not require the user to uphold /// any safety invariants. /// -/// The public form of this instrinsic is [`bool::select_unpredictable`]. +/// The public form of this instrinsic is [`core::hint::select_unpredictable`]. +/// However unlike the public form, the intrinsic will not drop the value that +/// is not selected. #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_intrinsic] #[rustc_nounwind] @@ -2307,20 +2306,8 @@ pub unsafe fn truncf128(x: f128) -> f128; /// [`f16::round_ties_even`](../../std/primitive.f16.html#method.round_ties_even) #[rustc_intrinsic] #[rustc_nounwind] -#[cfg(not(bootstrap))] pub fn round_ties_even_f16(x: f16) -> f16; -/// To be removed on next bootstrap bump. -#[cfg(bootstrap)] -pub fn round_ties_even_f16(x: f16) -> f16 { - #[rustc_intrinsic] - #[rustc_nounwind] - unsafe fn rintf16(x: f16) -> f16; - - // SAFETY: this intrinsic isn't actually unsafe - unsafe { rintf16(x) } -} - /// Returns the nearest integer to an `f32`. Rounds half-way cases to the number with an even /// least significant digit. /// @@ -2328,20 +2315,8 @@ pub fn round_ties_even_f16(x: f16) -> f16 { /// [`f32::round_ties_even`](../../std/primitive.f32.html#method.round_ties_even) #[rustc_intrinsic] #[rustc_nounwind] -#[cfg(not(bootstrap))] pub fn round_ties_even_f32(x: f32) -> f32; -/// To be removed on next bootstrap bump. -#[cfg(bootstrap)] -pub fn round_ties_even_f32(x: f32) -> f32 { - #[rustc_intrinsic] - #[rustc_nounwind] - unsafe fn rintf32(x: f32) -> f32; - - // SAFETY: this intrinsic isn't actually unsafe - unsafe { rintf32(x) } -} - /// Provided for compatibility with stdarch. DO NOT USE. #[inline(always)] pub unsafe fn rintf32(x: f32) -> f32 { @@ -2355,20 +2330,8 @@ pub unsafe fn rintf32(x: f32) -> f32 { /// [`f64::round_ties_even`](../../std/primitive.f64.html#method.round_ties_even) #[rustc_intrinsic] #[rustc_nounwind] -#[cfg(not(bootstrap))] pub fn round_ties_even_f64(x: f64) -> f64; -/// To be removed on next bootstrap bump. -#[cfg(bootstrap)] -pub fn round_ties_even_f64(x: f64) -> f64 { - #[rustc_intrinsic] - #[rustc_nounwind] - unsafe fn rintf64(x: f64) -> f64; - - // SAFETY: this intrinsic isn't actually unsafe - unsafe { rintf64(x) } -} - /// Provided for compatibility with stdarch. DO NOT USE. #[inline(always)] pub unsafe fn rintf64(x: f64) -> f64 { @@ -2382,20 +2345,8 @@ pub unsafe fn rintf64(x: f64) -> f64 { /// [`f128::round_ties_even`](../../std/primitive.f128.html#method.round_ties_even) #[rustc_intrinsic] #[rustc_nounwind] -#[cfg(not(bootstrap))] pub fn round_ties_even_f128(x: f128) -> f128; -/// To be removed on next bootstrap bump. -#[cfg(bootstrap)] -pub fn round_ties_even_f128(x: f128) -> f128 { - #[rustc_intrinsic] - #[rustc_nounwind] - unsafe fn rintf128(x: f128) -> f128; - - // SAFETY: this intrinsic isn't actually unsafe - unsafe { rintf128(x) } -} - /// Returns the nearest integer to an `f16`. Rounds half-way cases away from zero. /// /// The stabilized version of this intrinsic is @@ -2679,13 +2630,15 @@ pub const fn bswap(x: T) -> T; #[rustc_intrinsic] pub const fn bitreverse(x: T) -> T; -/// Does a three-way comparison between the two integer arguments. +/// Does a three-way comparison between the two arguments, +/// which must be of character or integer (signed or unsigned) type. /// -/// This is included as an intrinsic as it's useful to let it be one thing -/// in MIR, rather than the multiple checks and switches that make its IR -/// large and difficult to optimize. +/// This was originally added because it greatly simplified the MIR in `cmp` +/// implementations, and then LLVM 20 added a backend intrinsic for it too. /// /// The stabilized version of this intrinsic is [`Ord::cmp`]. +#[rustc_intrinsic_const_stable_indirect] +#[rustc_nounwind] #[rustc_intrinsic] pub const fn three_way_compare(lhs: T, rhss: T) -> crate::cmp::Ordering; @@ -2786,6 +2739,7 @@ pub const fn carrying_mul_add, /// `x % y != 0` or `y == 0` or `x == T::MIN && y == -1` /// /// This intrinsic does not have a stable counterpart. +#[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] pub const unsafe fn exact_div(x: T, y: T) -> T; @@ -3450,20 +3404,62 @@ pub const fn contract_checks() -> bool { /// /// By default, if `contract_checks` is enabled, this will panic with no unwind if the condition /// returns false. -#[unstable(feature = "contracts_internals", issue = "128044" /* compiler-team#759 */)] +/// +/// Note that this function is a no-op during constant evaluation. +#[unstable(feature = "contracts_internals", issue = "128044")] +// Calls to this function get inserted by an AST expansion pass, which uses the equivalent of +// `#[allow_internal_unstable]` to allow using `contracts_internals` functions. Const-checking +// doesn't honor `#[allow_internal_unstable]`, so for the const feature gate we use the user-facing +// `contracts` feature rather than the perma-unstable `contracts_internals` +#[rustc_const_unstable(feature = "contracts", issue = "128044")] #[lang = "contract_check_requires"] #[rustc_intrinsic] -pub fn contract_check_requires bool>(cond: C) { - if contract_checks() && !cond() { - // Emit no unwind panic in case this was a safety requirement. - crate::panicking::panic_nounwind("failed requires check"); - } +pub const fn contract_check_requires bool + Copy>(cond: C) { + const_eval_select!( + @capture[C: Fn() -> bool + Copy] { cond: C } : + if const { + // Do nothing + } else { + if contract_checks() && !cond() { + // Emit no unwind panic in case this was a safety requirement. + crate::panicking::panic_nounwind("failed requires check"); + } + } + ) } /// Check if the post-condition `cond` has been met. /// /// By default, if `contract_checks` is enabled, this will panic with no unwind if the condition /// returns false. +/// +/// Note that this function is a no-op during constant evaluation. +#[cfg(not(bootstrap))] +#[unstable(feature = "contracts_internals", issue = "128044")] +// Similar to `contract_check_requires`, we need to use the user-facing +// `contracts` feature rather than the perma-unstable `contracts_internals`. +// Const-checking doesn't honor allow_internal_unstable logic used by contract expansion. +#[rustc_const_unstable(feature = "contracts", issue = "128044")] +#[lang = "contract_check_ensures"] +#[rustc_intrinsic] +pub const fn contract_check_ensures bool + Copy, Ret>(cond: C, ret: Ret) -> Ret { + const_eval_select!( + @capture[C: Fn(&Ret) -> bool + Copy, Ret] { cond: C, ret: Ret } -> Ret : + if const { + // Do nothing + ret + } else { + if contract_checks() && !cond(&ret) { + // Emit no unwind panic in case this was a safety requirement. + crate::panicking::panic_nounwind("failed ensures check"); + } + ret + } + ) +} + +/// This is the old version of contract_check_ensures kept here for bootstrap only. +#[cfg(bootstrap)] #[unstable(feature = "contracts_internals", issue = "128044" /* compiler-team#759 */)] #[rustc_intrinsic] pub fn contract_check_ensures<'a, Ret, C: Fn(&'a Ret) -> bool>(ret: &'a Ret, cond: C) { @@ -3723,7 +3719,7 @@ pub const fn ptr_metadata + ?Sized, M>(ptr: *const /// [`Vec::append`]: ../../std/vec/struct.Vec.html#method.append #[doc(alias = "memcpy")] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_allowed_through_unstable_modules = "import this function via `std::mem` instead"] +#[rustc_allowed_through_unstable_modules = "import this function via `std::ptr` instead"] #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0")] #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces @@ -3826,7 +3822,7 @@ pub const unsafe fn copy_nonoverlapping(src: *const T, dst: *mut T, count: us /// ``` #[doc(alias = "memmove")] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_allowed_through_unstable_modules = "import this function via `std::mem` instead"] +#[rustc_allowed_through_unstable_modules = "import this function via `std::ptr` instead"] #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0")] #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces @@ -3906,7 +3902,7 @@ pub const unsafe fn copy(src: *const T, dst: *mut T, count: usize) { /// ``` #[doc(alias = "memset")] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_allowed_through_unstable_modules = "import this function via `std::mem` instead"] +#[rustc_allowed_through_unstable_modules = "import this function via `std::ptr` instead"] #[rustc_const_stable(feature = "const_ptr_write", since = "1.83.0")] #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces diff --git a/library/core/src/intrinsics/simd.rs b/library/core/src/intrinsics/simd.rs index ae6e1a779ed5..9ac6ee855355 100644 --- a/library/core/src/intrinsics/simd.rs +++ b/library/core/src/intrinsics/simd.rs @@ -4,7 +4,7 @@ /// Inserts an element into a vector, returning the updated vector. /// -/// `T` must be a vector with element type `U`. +/// `T` must be a vector with element type `U`, and `idx` must be `const`. /// /// # Safety /// @@ -15,14 +15,47 @@ pub const unsafe fn simd_insert(x: T, idx: u32, val: U) -> T; /// Extracts an element from a vector. /// +/// `T` must be a vector with element type `U`, and `idx` must be `const`. +/// +/// # Safety +/// +/// `idx` must be const and in-bounds of the vector. +#[rustc_intrinsic] +#[rustc_nounwind] +pub const unsafe fn simd_extract(x: T, idx: u32) -> U; + +/// Inserts an element into a vector, returning the updated vector. +/// /// `T` must be a vector with element type `U`. /// +/// If the index is `const`, [`simd_insert`] may emit better assembly. +/// /// # Safety /// /// `idx` must be in-bounds of the vector. -#[rustc_intrinsic] #[rustc_nounwind] -pub const unsafe fn simd_extract(x: T, idx: u32) -> U; +#[cfg_attr(not(bootstrap), rustc_intrinsic)] +pub unsafe fn simd_insert_dyn(mut x: T, idx: u32, val: U) -> T { + // SAFETY: `idx` must be in-bounds + unsafe { (&raw mut x).cast::().add(idx as usize).write(val) } + x +} + +/// Extracts an element from a vector. +/// +/// `T` must be a vector with element type `U`. +/// +/// If the index is `const`, [`simd_extract`] may emit better assembly. +/// +/// # Safety +/// +/// `idx` must be in-bounds of the vector. +#[rustc_nounwind] +#[cfg_attr(not(bootstrap), rustc_intrinsic)] +pub unsafe fn simd_extract_dyn(x: T, idx: u32) -> U { + // SAFETY: `idx` must be in-bounds + unsafe { (&raw const x).cast::().add(idx as usize).read() } +} /// Adds two simd vectors elementwise. /// diff --git a/library/core/src/iter/adapters/cloned.rs b/library/core/src/iter/adapters/cloned.rs index aea6d64281ae..72d746289711 100644 --- a/library/core/src/iter/adapters/cloned.rs +++ b/library/core/src/iter/adapters/cloned.rs @@ -1,5 +1,6 @@ use core::num::NonZero; +use crate::cmp::Ordering; use crate::iter::adapters::zip::try_get_unchecked; use crate::iter::adapters::{SourceIter, TrustedRandomAccess, TrustedRandomAccessNoCoerce}; use crate::iter::{FusedIterator, InPlaceIterable, TrustedLen, UncheckedIterator}; @@ -41,13 +42,31 @@ where self.it.next().cloned() } + #[inline] fn size_hint(&self) -> (usize, Option) { self.it.size_hint() } + #[inline] + fn count(self) -> usize { + self.it.count() + } + + fn last(self) -> Option { + self.it.last().cloned() + } + + #[inline] + fn advance_by(&mut self, n: usize) -> Result<(), NonZero> { + self.it.advance_by(n) + } + + fn nth(&mut self, n: usize) -> Option { + self.it.nth(n).cloned() + } + fn try_fold(&mut self, init: B, f: F) -> R where - Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try, { @@ -61,6 +80,58 @@ where self.it.map(T::clone).fold(init, f) } + fn find

(&mut self, mut predicate: P) -> Option + where + P: FnMut(&Self::Item) -> bool, + { + self.it.find(move |x| predicate(&x)).cloned() + } + + fn max_by(self, mut compare: F) -> Option + where + F: FnMut(&Self::Item, &Self::Item) -> Ordering, + { + self.it.max_by(move |&x, &y| compare(x, y)).cloned() + } + + fn min_by(self, mut compare: F) -> Option + where + F: FnMut(&Self::Item, &Self::Item) -> Ordering, + { + self.it.min_by(move |&x, &y| compare(x, y)).cloned() + } + + fn cmp(self, other: O) -> Ordering + where + O: IntoIterator, + Self::Item: Ord, + { + self.it.cmp_by(other, |x, y| x.cmp(&y)) + } + + fn partial_cmp(self, other: O) -> Option + where + O: IntoIterator, + Self::Item: PartialOrd, + { + self.it.partial_cmp_by(other, |x, y| x.partial_cmp(&y)) + } + + fn eq(self, other: O) -> bool + where + O: IntoIterator, + Self::Item: PartialEq, + { + self.it.eq_by(other, |x, y| x == &y) + } + + fn is_sorted_by(self, mut compare: F) -> bool + where + F: FnMut(&Self::Item, &Self::Item) -> bool, + { + self.it.is_sorted_by(move |&x, &y| compare(x, y)) + } + unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> T where Self: TrustedRandomAccessNoCoerce, @@ -81,9 +152,13 @@ where self.it.next_back().cloned() } + #[inline] + fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero> { + self.it.advance_back_by(n) + } + fn try_rfold(&mut self, init: B, f: F) -> R where - Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try, { @@ -96,6 +171,13 @@ where { self.it.map(T::clone).rfold(init, f) } + + fn rfind

(&mut self, mut predicate: P) -> Option + where + P: FnMut(&Self::Item) -> bool, + { + self.it.rfind(move |x| predicate(&x)).cloned() + } } #[stable(feature = "iter_cloned", since = "1.1.0")] @@ -104,10 +186,12 @@ where I: ExactSizeIterator, T: Clone, { + #[inline] fn len(&self) -> usize { self.it.len() } + #[inline] fn is_empty(&self) -> bool { self.it.is_empty() } diff --git a/library/core/src/iter/adapters/copied.rs b/library/core/src/iter/adapters/copied.rs index 23e4e25ab538..73913aa34a9e 100644 --- a/library/core/src/iter/adapters/copied.rs +++ b/library/core/src/iter/adapters/copied.rs @@ -1,3 +1,4 @@ +use crate::cmp::Ordering; use crate::iter::adapters::zip::try_get_unchecked; use crate::iter::adapters::{SourceIter, TrustedRandomAccess, TrustedRandomAccessNoCoerce}; use crate::iter::{FusedIterator, InPlaceIterable, TrustedLen}; @@ -48,20 +49,35 @@ where fn next_chunk( &mut self, - ) -> Result<[Self::Item; N], array::IntoIter> - where - Self: Sized, - { + ) -> Result<[Self::Item; N], array::IntoIter> { >::spec_next_chunk(&mut self.it) } + #[inline] fn size_hint(&self) -> (usize, Option) { self.it.size_hint() } + #[inline] + fn count(self) -> usize { + self.it.count() + } + + fn last(self) -> Option { + self.it.last().copied() + } + + #[inline] + fn advance_by(&mut self, n: usize) -> Result<(), NonZero> { + self.it.advance_by(n) + } + + fn nth(&mut self, n: usize) -> Option { + self.it.nth(n).copied() + } + fn try_fold(&mut self, init: B, f: F) -> R where - Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try, { @@ -75,21 +91,56 @@ where self.it.fold(init, copy_fold(f)) } - fn nth(&mut self, n: usize) -> Option { - self.it.nth(n).copied() + fn find

(&mut self, mut predicate: P) -> Option + where + P: FnMut(&Self::Item) -> bool, + { + self.it.find(move |x| predicate(&x)).copied() } - fn last(self) -> Option { - self.it.last().copied() + fn max_by(self, mut compare: F) -> Option + where + F: FnMut(&Self::Item, &Self::Item) -> Ordering, + { + self.it.max_by(move |&x, &y| compare(x, y)).copied() } - fn count(self) -> usize { - self.it.count() + fn min_by(self, mut compare: F) -> Option + where + F: FnMut(&Self::Item, &Self::Item) -> Ordering, + { + self.it.min_by(move |&x, &y| compare(x, y)).copied() } - #[inline] - fn advance_by(&mut self, n: usize) -> Result<(), NonZero> { - self.it.advance_by(n) + fn cmp(self, other: O) -> Ordering + where + O: IntoIterator, + Self::Item: Ord, + { + self.it.cmp_by(other, |x, y| x.cmp(&y)) + } + + fn partial_cmp(self, other: O) -> Option + where + O: IntoIterator, + Self::Item: PartialOrd, + { + self.it.partial_cmp_by(other, |x, y| x.partial_cmp(&y)) + } + + fn eq(self, other: O) -> bool + where + O: IntoIterator, + Self::Item: PartialEq, + { + self.it.eq_by(other, |x, y| x == &y) + } + + fn is_sorted_by(self, mut compare: F) -> bool + where + F: FnMut(&Self::Item, &Self::Item) -> bool, + { + self.it.is_sorted_by(move |&x, &y| compare(x, y)) } unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> T @@ -112,9 +163,13 @@ where self.it.next_back().copied() } + #[inline] + fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero> { + self.it.advance_back_by(n) + } + fn try_rfold(&mut self, init: B, f: F) -> R where - Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try, { @@ -128,9 +183,11 @@ where self.it.rfold(init, copy_fold(f)) } - #[inline] - fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero> { - self.it.advance_back_by(n) + fn rfind

(&mut self, mut predicate: P) -> Option + where + P: FnMut(&Self::Item) -> bool, + { + self.it.rfind(move |x| predicate(&x)).copied() } } @@ -140,10 +197,12 @@ where I: ExactSizeIterator, T: Copy, { + #[inline] fn len(&self) -> usize { self.it.len() } + #[inline] fn is_empty(&self) -> bool { self.it.is_empty() } diff --git a/library/core/src/iter/adapters/enumerate.rs b/library/core/src/iter/adapters/enumerate.rs index f9c388e8564d..bd093e279c38 100644 --- a/library/core/src/iter/adapters/enumerate.rs +++ b/library/core/src/iter/adapters/enumerate.rs @@ -36,7 +36,7 @@ where /// /// The method does no guarding against overflows, so enumerating more than /// `usize::MAX` elements either produces the wrong result or panics. If - /// debug assertions are enabled, a panic is guaranteed. + /// overflow checks are enabled, a panic is guaranteed. /// /// # Panics /// diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 3bbb52fdbcb5..d9534a445980 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -199,7 +199,7 @@ pub trait Iterator { /// /// The method does no guarding against overflows, so counting elements of /// an iterator with more than [`usize::MAX`] elements either produces the - /// wrong result or panics. If debug assertions are enabled, a panic is + /// wrong result or panics. If overflow checks are enabled, a panic is /// guaranteed. /// /// # Panics @@ -931,7 +931,7 @@ pub trait Iterator { /// /// The method does no guarding against overflows, so enumerating more than /// [`usize::MAX`] elements either produces the wrong result or panics. If - /// debug assertions are enabled, a panic is guaranteed. + /// overflow checks are enabled, a panic is guaranteed. /// /// # Panics /// @@ -2964,7 +2964,7 @@ pub trait Iterator { /// /// The method does no guarding against overflows, so if there are more /// than [`usize::MAX`] non-matching elements, it either produces the wrong - /// result or panics. If debug assertions are enabled, a panic is + /// result or panics. If overflow checks are enabled, a panic is /// guaranteed. /// /// # Panics @@ -3516,7 +3516,7 @@ pub trait Iterator { /// # Panics /// /// When calling `sum()` and a primitive integer type is being returned, this - /// method will panic if the computation overflows and debug assertions are + /// method will panic if the computation overflows and overflow checks are /// enabled. /// /// # Examples @@ -3550,7 +3550,7 @@ pub trait Iterator { /// # Panics /// /// When calling `product()` and a primitive integer type is being returned, - /// method will panic if the computation overflows and debug assertions are + /// method will panic if the computation overflows and overflow checks are /// enabled. /// /// # Examples diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index dc06aa4c38d5..9625475e617e 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -101,7 +101,6 @@ #![feature(bstr)] #![feature(bstr_internals)] #![feature(cfg_match)] -#![feature(closure_track_caller)] #![feature(const_carrying_mul_add)] #![feature(const_eval_select)] #![feature(core_intrinsics)] @@ -127,6 +126,7 @@ #![feature(ub_checks)] #![feature(unchecked_neg)] #![feature(unchecked_shifts)] +#![feature(unsafe_pinned)] #![feature(utf16_extra)] #![feature(variant_count)] // tidy-alphabetical-end @@ -169,7 +169,6 @@ #![feature(negative_impls)] #![feature(never_type)] #![feature(no_core)] -#![feature(no_sanitize)] #![feature(optimize_attribute)] #![feature(prelude_import)] #![feature(repr_simd)] diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index 5f200b31d1ae..330b40987645 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -237,9 +237,10 @@ pub macro assert_matches { /// ``` #[unstable(feature = "cfg_match", issue = "115585")] #[rustc_diagnostic_item = "cfg_match"] +#[rustc_macro_transparency = "semitransparent"] pub macro cfg_match { ({ $($tt:tt)* }) => {{ - cfg_match! { $($tt)* } + $crate::cfg_match! { $($tt)* } }}, (_ => { $($output:tt)* }) => { $($output)* @@ -249,10 +250,10 @@ pub macro cfg_match { $($( $rest:tt )+)? ) => { #[cfg($cfg)] - cfg_match! { _ => $output } + $crate::cfg_match! { _ => $output } $( #[cfg(not($cfg))] - cfg_match! { $($rest)+ } + $crate::cfg_match! { $($rest)+ } )? }, } @@ -1753,7 +1754,6 @@ pub(crate) mod builtin { reason = "`type_alias_impl_trait` has open design concerns" )] #[rustc_builtin_macro] - #[cfg(not(bootstrap))] pub macro define_opaque($($tt:tt)*) { /* compiler built-in */ } diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index 68011310d2ca..9dc20beda6c6 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -17,6 +17,7 @@ use crate::cell::UnsafeCell; use crate::cmp; use crate::fmt::Debug; use crate::hash::{Hash, Hasher}; +use crate::pin::UnsafePinned; /// Implements a given marker trait for multiple types at the same time. /// @@ -878,6 +879,23 @@ marker_impls! { {T: ?Sized} &mut T, } +/// Used to determine whether a type contains any `UnsafePinned` (or `PhantomPinned`) internally, +/// but not through an indirection. This affects, for example, whether we emit `noalias` metadata +/// for `&mut T` or not. +/// +/// This is part of [RFC 3467](https://rust-lang.github.io/rfcs/3467-unsafe-pinned.html), and is +/// tracked by [#125735](https://github.com/rust-lang/rust/issues/125735). +#[cfg_attr(not(bootstrap), lang = "unsafe_unpin")] +#[cfg_attr(bootstrap, allow(dead_code))] +pub(crate) unsafe auto trait UnsafeUnpin {} + +impl !UnsafeUnpin for UnsafePinned {} +unsafe impl UnsafeUnpin for PhantomData {} +unsafe impl UnsafeUnpin for *const T {} +unsafe impl UnsafeUnpin for *mut T {} +unsafe impl UnsafeUnpin for &T {} +unsafe impl UnsafeUnpin for &mut T {} + /// Types that do not require any pinning guarantees. /// /// For information on what "pinning" is, see the [`pin` module] documentation. @@ -953,6 +971,11 @@ pub auto trait Unpin {} /// A marker type which does not implement `Unpin`. /// /// If a type contains a `PhantomPinned`, it will not implement `Unpin` by default. +// +// FIXME(unsafe_pinned): This is *not* a stable guarantee we want to make, at least not yet. +// Note that for backwards compatibility with the new [`UnsafePinned`] wrapper type, placing this +// marker in your struct acts as if you wrapped the entire struct in an `UnsafePinned`. This type +// will likely eventually be deprecated, and all new code should be using `UnsafePinned` instead. #[stable(feature = "pin", since = "1.33.0")] #[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] pub struct PhantomPinned; @@ -960,6 +983,12 @@ pub struct PhantomPinned; #[stable(feature = "pin", since = "1.33.0")] impl !Unpin for PhantomPinned {} +// This is a small hack to allow existing code which uses PhantomPinned to opt-out of noalias to +// continue working. Ideally PhantomPinned could just wrap an `UnsafePinned<()>` to get the same +// effect, but we can't add a new field to an already stable unit struct -- that would be a breaking +// change. +impl !UnsafeUnpin for PhantomPinned {} + marker_impls! { #[stable(feature = "pin", since = "1.33.0")] Unpin for diff --git a/library/core/src/net/socket_addr.rs b/library/core/src/net/socket_addr.rs index 21753d009249..936f9f64930d 100644 --- a/library/core/src/net/socket_addr.rs +++ b/library/core/src/net/socket_addr.rs @@ -210,7 +210,7 @@ impl SocketAddr { /// ``` #[inline] #[stable(feature = "sockaddr_setters", since = "1.9.0")] - #[rustc_const_stable(feature = "const_sockaddr_setters", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_sockaddr_setters", since = "1.87.0")] pub const fn set_ip(&mut self, new_ip: IpAddr) { // `match (*self, new_ip)` would have us mutate a copy of self only to throw it away. match (self, new_ip) { @@ -254,7 +254,7 @@ impl SocketAddr { /// ``` #[inline] #[stable(feature = "sockaddr_setters", since = "1.9.0")] - #[rustc_const_stable(feature = "const_sockaddr_setters", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_sockaddr_setters", since = "1.87.0")] pub const fn set_port(&mut self, new_port: u16) { match *self { SocketAddr::V4(ref mut a) => a.set_port(new_port), @@ -360,7 +360,7 @@ impl SocketAddrV4 { /// ``` #[inline] #[stable(feature = "sockaddr_setters", since = "1.9.0")] - #[rustc_const_stable(feature = "const_sockaddr_setters", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_sockaddr_setters", since = "1.87.0")] pub const fn set_ip(&mut self, new_ip: Ipv4Addr) { self.ip = new_ip; } @@ -396,7 +396,7 @@ impl SocketAddrV4 { /// ``` #[inline] #[stable(feature = "sockaddr_setters", since = "1.9.0")] - #[rustc_const_stable(feature = "const_sockaddr_setters", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_sockaddr_setters", since = "1.87.0")] pub const fn set_port(&mut self, new_port: u16) { self.port = new_port; } @@ -458,7 +458,7 @@ impl SocketAddrV6 { /// ``` #[inline] #[stable(feature = "sockaddr_setters", since = "1.9.0")] - #[rustc_const_stable(feature = "const_sockaddr_setters", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_sockaddr_setters", since = "1.87.0")] pub const fn set_ip(&mut self, new_ip: Ipv6Addr) { self.ip = new_ip; } @@ -494,7 +494,7 @@ impl SocketAddrV6 { /// ``` #[inline] #[stable(feature = "sockaddr_setters", since = "1.9.0")] - #[rustc_const_stable(feature = "const_sockaddr_setters", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_sockaddr_setters", since = "1.87.0")] pub const fn set_port(&mut self, new_port: u16) { self.port = new_port; } @@ -542,7 +542,7 @@ impl SocketAddrV6 { /// ``` #[inline] #[stable(feature = "sockaddr_setters", since = "1.9.0")] - #[rustc_const_stable(feature = "const_sockaddr_setters", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_sockaddr_setters", since = "1.87.0")] pub const fn set_flowinfo(&mut self, new_flowinfo: u32) { self.flowinfo = new_flowinfo; } @@ -585,7 +585,7 @@ impl SocketAddrV6 { /// ``` #[inline] #[stable(feature = "sockaddr_setters", since = "1.9.0")] - #[rustc_const_stable(feature = "const_sockaddr_setters", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_sockaddr_setters", since = "1.87.0")] pub const fn set_scope_id(&mut self, new_scope_id: u32) { self.scope_id = new_scope_id; } diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs index 08c34e852da4..d3d1eebc2275 100644 --- a/library/core/src/num/f128.rs +++ b/library/core/src/num/f128.rs @@ -224,14 +224,16 @@ impl f128 { /// Not a Number (NaN). /// - /// Note that IEEE 754 doesn't define just a single NaN value; - /// a plethora of bit patterns are considered to be NaN. - /// Furthermore, the standard makes a difference - /// between a "signaling" and a "quiet" NaN, - /// and allows inspecting its "payload" (the unspecified bits in the bit pattern). - /// This constant isn't guaranteed to equal to any specific NaN bitpattern, - /// and the stability of its representation over Rust versions - /// and target platforms isn't guaranteed. + /// Note that IEEE 754 doesn't define just a single NaN value; a plethora of bit patterns are + /// considered to be NaN. Furthermore, the standard makes a difference between a "signaling" and + /// a "quiet" NaN, and allows inspecting its "payload" (the unspecified bits in the bit pattern) + /// and its sign. See the [specification of NaN bit patterns](f32#nan-bit-patterns) for more + /// info. + /// + /// This constant is guaranteed to be a quiet NaN (on targets that follow the Rust assumptions + /// that the quiet/signaling bit being set to 1 indicates a quiet NaN). Beyond that, nothing is + /// guaranteed about the specific bit pattern chosen here: both payload and sign are arbitrary. + /// The concrete bit pattern may change across Rust versions and target platforms. #[allow(clippy::eq_op)] #[rustc_diagnostic_item = "f128_nan"] #[unstable(feature = "f128", issue = "116909")] diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs index a33e5f530146..dceb30177e66 100644 --- a/library/core/src/num/f16.rs +++ b/library/core/src/num/f16.rs @@ -219,14 +219,16 @@ impl f16 { /// Not a Number (NaN). /// - /// Note that IEEE 754 doesn't define just a single NaN value; - /// a plethora of bit patterns are considered to be NaN. - /// Furthermore, the standard makes a difference - /// between a "signaling" and a "quiet" NaN, - /// and allows inspecting its "payload" (the unspecified bits in the bit pattern). - /// This constant isn't guaranteed to equal to any specific NaN bitpattern, - /// and the stability of its representation over Rust versions - /// and target platforms isn't guaranteed. + /// Note that IEEE 754 doesn't define just a single NaN value; a plethora of bit patterns are + /// considered to be NaN. Furthermore, the standard makes a difference between a "signaling" and + /// a "quiet" NaN, and allows inspecting its "payload" (the unspecified bits in the bit pattern) + /// and its sign. See the [specification of NaN bit patterns](f32#nan-bit-patterns) for more + /// info. + /// + /// This constant is guaranteed to be a quiet NaN (on targets that follow the Rust assumptions + /// that the quiet/signaling bit being set to 1 indicates a quiet NaN). Beyond that, nothing is + /// guaranteed about the specific bit pattern chosen here: both payload and sign are arbitrary. + /// The concrete bit pattern may change across Rust versions and target platforms. #[allow(clippy::eq_op)] #[rustc_diagnostic_item = "f16_nan"] #[unstable(feature = "f16", issue = "116909")] diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index e473fac03935..c97dbfb63ae1 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -470,14 +470,16 @@ impl f32 { /// Not a Number (NaN). /// - /// Note that IEEE 754 doesn't define just a single NaN value; - /// a plethora of bit patterns are considered to be NaN. - /// Furthermore, the standard makes a difference - /// between a "signaling" and a "quiet" NaN, - /// and allows inspecting its "payload" (the unspecified bits in the bit pattern). - /// This constant isn't guaranteed to equal to any specific NaN bitpattern, - /// and the stability of its representation over Rust versions - /// and target platforms isn't guaranteed. + /// Note that IEEE 754 doesn't define just a single NaN value; a plethora of bit patterns are + /// considered to be NaN. Furthermore, the standard makes a difference between a "signaling" and + /// a "quiet" NaN, and allows inspecting its "payload" (the unspecified bits in the bit pattern) + /// and its sign. See the [specification of NaN bit patterns](f32#nan-bit-patterns) for more + /// info. + /// + /// This constant is guaranteed to be a quiet NaN (on targets that follow the Rust assumptions + /// that the quiet/signaling bit being set to 1 indicates a quiet NaN). Beyond that, nothing is + /// guaranteed about the specific bit pattern chosen here: both payload and sign are arbitrary. + /// The concrete bit pattern may change across Rust versions and target platforms. #[stable(feature = "assoc_int_consts", since = "1.43.0")] #[rustc_diagnostic_item = "f32_nan"] #[allow(clippy::eq_op)] diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index 6522a80b0b7e..91affdb3794b 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -469,14 +469,16 @@ impl f64 { /// Not a Number (NaN). /// - /// Note that IEEE 754 doesn't define just a single NaN value; - /// a plethora of bit patterns are considered to be NaN. - /// Furthermore, the standard makes a difference - /// between a "signaling" and a "quiet" NaN, - /// and allows inspecting its "payload" (the unspecified bits in the bit pattern). - /// This constant isn't guaranteed to equal to any specific NaN bitpattern, - /// and the stability of its representation over Rust versions - /// and target platforms isn't guaranteed. + /// Note that IEEE 754 doesn't define just a single NaN value; a plethora of bit patterns are + /// considered to be NaN. Furthermore, the standard makes a difference between a "signaling" and + /// a "quiet" NaN, and allows inspecting its "payload" (the unspecified bits in the bit pattern) + /// and its sign. See the [specification of NaN bit patterns](f32#nan-bit-patterns) for more + /// info. + /// + /// This constant is guaranteed to be a quiet NaN (on targets that follow the Rust assumptions + /// that the quiet/signaling bit being set to 1 indicates a quiet NaN). Beyond that, nothing is + /// guaranteed about the specific bit pattern chosen here: both payload and sign are arbitrary. + /// The concrete bit pattern may change across Rust versions and target platforms. #[rustc_diagnostic_item = "f64_nan"] #[stable(feature = "assoc_int_consts", since = "1.43.0")] #[allow(clippy::eq_op)] diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index a72ca4bcb059..05d8216ac27e 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -244,8 +244,8 @@ macro_rules! int_impl { /// #[doc = concat!("assert_eq!(n.cast_unsigned(), ", stringify!($UnsignedT), "::MAX);")] /// ``` - #[stable(feature = "integer_sign_cast", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "integer_sign_cast", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "integer_sign_cast", since = "1.87.0")] + #[rustc_const_stable(feature = "integer_sign_cast", since = "1.87.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] @@ -1355,8 +1355,8 @@ macro_rules! int_impl { #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".unbounded_shl(4), 0x10);")] #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".unbounded_shl(129), 0);")] /// ``` - #[stable(feature = "unbounded_shifts", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "unbounded_shifts", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "unbounded_shifts", since = "1.87.0")] + #[rustc_const_stable(feature = "unbounded_shifts", since = "1.87.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -1478,8 +1478,8 @@ macro_rules! int_impl { #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".unbounded_shr(129), 0);")] #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.unbounded_shr(129), -1);")] /// ``` - #[stable(feature = "unbounded_shifts", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "unbounded_shifts", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "unbounded_shifts", since = "1.87.0")] + #[rustc_const_stable(feature = "unbounded_shifts", since = "1.87.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -3571,10 +3571,7 @@ macro_rules! int_impl { // so delegate it to `Ord` which is already producing -1/0/+1 // exactly like we need and can be the place to deal with the complexity. - // FIXME(const-hack): replace with cmp - if self < 0 { -1 } - else if self == 0 { 0 } - else { 1 } + crate::intrinsics::three_way_compare(self, 0) as Self } /// Returns `true` if `self` is positive and `false` if the number is zero or diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index 151e128cd78a..348457e2c00f 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -99,8 +99,8 @@ macro_rules! i8_xe_bytes_doc { **Note**: This function is meaningless on `i8`. Byte order does not exist as a concept for byte-sized integers. This function is only provided in symmetry -with larger integer types. You can cast from and to `u8` using `as i8` and `as -u8`. +with larger integer types. You can cast from and to `u8` using +[`cast_signed`](u8::cast_signed) and [`cast_unsigned`](Self::cast_unsigned). " }; @@ -169,8 +169,8 @@ macro_rules! midpoint_impl { #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".midpoint(-7), -3);")] #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".midpoint(7), 3);")] /// ``` - #[stable(feature = "num_midpoint_signed", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "num_midpoint_signed", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "num_midpoint_signed", since = "1.87.0")] + #[rustc_const_stable(feature = "num_midpoint_signed", since = "1.87.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -221,8 +221,8 @@ macro_rules! midpoint_impl { #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".midpoint(-7), -3);")] #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".midpoint(7), 3);")] /// ``` - #[stable(feature = "num_midpoint_signed", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "num_midpoint_signed", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "num_midpoint_signed", since = "1.87.0")] + #[rustc_const_stable(feature = "num_midpoint_signed", since = "1.87.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 7585ec140e31..1b79112aec1f 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -1704,8 +1704,8 @@ macro_rules! nonzero_integer_signedness_dependent_methods { /// #[doc = concat!("assert_eq!(n.cast_signed(), NonZero::new(-1", stringify!($Sint), ").unwrap());")] /// ``` - #[stable(feature = "integer_sign_cast", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "integer_sign_cast", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "integer_sign_cast", since = "1.87.0")] + #[rustc_const_stable(feature = "integer_sign_cast", since = "1.87.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] @@ -2143,8 +2143,8 @@ macro_rules! nonzero_integer_signedness_dependent_methods { /// #[doc = concat!("assert_eq!(n.cast_unsigned(), NonZero::<", stringify!($Uint), ">::MAX);")] /// ``` - #[stable(feature = "integer_sign_cast", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "integer_sign_cast", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "integer_sign_cast", since = "1.87.0")] + #[rustc_const_stable(feature = "integer_sign_cast", since = "1.87.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index 586892758398..3678bb091e7d 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -273,8 +273,8 @@ macro_rules! uint_impl { /// #[doc = concat!("assert_eq!(n.cast_signed(), -1", stringify!($SignedT), ");")] /// ``` - #[stable(feature = "integer_sign_cast", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "integer_sign_cast", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "integer_sign_cast", since = "1.87.0")] + #[rustc_const_stable(feature = "integer_sign_cast", since = "1.87.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] @@ -1616,8 +1616,8 @@ macro_rules! uint_impl { #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".unbounded_shl(4), 0x10);")] #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".unbounded_shl(129), 0);")] /// ``` - #[stable(feature = "unbounded_shifts", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "unbounded_shifts", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "unbounded_shifts", since = "1.87.0")] + #[rustc_const_stable(feature = "unbounded_shifts", since = "1.87.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -1737,8 +1737,8 @@ macro_rules! uint_impl { #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".unbounded_shr(4), 0x1);")] #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".unbounded_shr(129), 0);")] /// ``` - #[stable(feature = "unbounded_shifts", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "unbounded_shifts", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "unbounded_shifts", since = "1.87.0")] + #[rustc_const_stable(feature = "unbounded_shifts", since = "1.87.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -3331,8 +3331,8 @@ macro_rules! uint_impl { #[doc = concat!("assert!(0_", stringify!($SelfT), ".is_multiple_of(0));")] #[doc = concat!("assert!(!6_", stringify!($SelfT), ".is_multiple_of(0));")] /// ``` - #[stable(feature = "unsigned_is_multiple_of", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "unsigned_is_multiple_of", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "unsigned_is_multiple_of", since = "1.87.0")] + #[rustc_const_stable(feature = "unsigned_is_multiple_of", since = "1.87.0")] #[must_use] #[inline] #[rustc_inherit_overflow_checks] @@ -3343,7 +3343,7 @@ macro_rules! uint_impl { } } - /// Returns `true` if and only if `self == 2^k` for some `k`. + /// Returns `true` if and only if `self == 2^k` for some unsigned integer `k`. /// /// # Examples /// diff --git a/library/core/src/ops/index_range.rs b/library/core/src/ops/index_range.rs index b82184b15b2f..c645c996eb70 100644 --- a/library/core/src/ops/index_range.rs +++ b/library/core/src/ops/index_range.rs @@ -1,5 +1,6 @@ use crate::iter::{FusedIterator, TrustedLen}; use crate::num::NonZero; +use crate::ops::{NeverShortCircuit, Try}; use crate::ub_checks; /// Like a `Range`, but with a safety invariant that `start <= end`. @@ -112,6 +113,12 @@ impl IndexRange { self.end = mid; suffix } + + #[inline] + fn assume_range(&self) { + // SAFETY: This is the type invariant + unsafe { crate::hint::assert_unchecked(self.start <= self.end) } + } } impl Iterator for IndexRange { @@ -138,6 +145,30 @@ impl Iterator for IndexRange { let taken = self.take_prefix(n); NonZero::new(n - taken.len()).map_or(Ok(()), Err) } + + #[inline] + fn fold B>(mut self, init: B, f: F) -> B { + self.try_fold(init, NeverShortCircuit::wrap_mut_2(f)).0 + } + + #[inline] + fn try_fold(&mut self, mut accum: B, mut f: F) -> R + where + Self: Sized, + F: FnMut(B, Self::Item) -> R, + R: Try, + { + // `Range` needs to check `start < end`, but thanks to our type invariant + // we can loop on the stricter `start != end`. + + self.assume_range(); + while self.start != self.end { + // SAFETY: We just checked that the range is non-empty + let i = unsafe { self.next_unchecked() }; + accum = f(accum, i)?; + } + try { accum } + } } impl DoubleEndedIterator for IndexRange { @@ -156,6 +187,30 @@ impl DoubleEndedIterator for IndexRange { let taken = self.take_suffix(n); NonZero::new(n - taken.len()).map_or(Ok(()), Err) } + + #[inline] + fn rfold B>(mut self, init: B, f: F) -> B { + self.try_rfold(init, NeverShortCircuit::wrap_mut_2(f)).0 + } + + #[inline] + fn try_rfold(&mut self, mut accum: B, mut f: F) -> R + where + Self: Sized, + F: FnMut(B, Self::Item) -> R, + R: Try, + { + // `Range` needs to check `start < end`, but thanks to our type invariant + // we can loop on the stricter `start != end`. + + self.assume_range(); + while self.start != self.end { + // SAFETY: We just checked that the range is non-empty + let i = unsafe { self.next_back_unchecked() }; + accum = f(accum, i)?; + } + try { accum } + } } impl ExactSizeIterator for IndexRange { diff --git a/library/core/src/pat.rs b/library/core/src/pat.rs index f8826096df3e..91d015b1bc53 100644 --- a/library/core/src/pat.rs +++ b/library/core/src/pat.rs @@ -25,15 +25,15 @@ macro_rules! pattern_type { )] pub trait RangePattern { /// Trait version of the inherent `MIN` assoc const. - #[cfg_attr(not(bootstrap), lang = "RangeMin")] + #[lang = "RangeMin"] const MIN: Self; /// Trait version of the inherent `MIN` assoc const. - #[cfg_attr(not(bootstrap), lang = "RangeMax")] + #[lang = "RangeMax"] const MAX: Self; /// A compile-time helper to subtract 1 for exclusive ranges. - #[cfg_attr(not(bootstrap), lang = "RangeSub")] + #[lang = "RangeSub"] #[track_caller] fn sub_one(self) -> Self; } diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index bc097bf198d0..9e6acf04bf72 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -931,6 +931,11 @@ use crate::{ }; use crate::{cmp, fmt}; +mod unsafe_pinned; + +#[unstable(feature = "unsafe_pinned", issue = "125735")] +pub use self::unsafe_pinned::UnsafePinned; + /// A pointer which pins its pointee in place. /// /// [`Pin`] is a wrapper around some kind of pointer `Ptr` which makes that pointer "pin" its @@ -1087,24 +1092,15 @@ use crate::{cmp, fmt}; #[rustc_pub_transparent] #[derive(Copy, Clone)] pub struct Pin { - // FIXME(#93176): this field is made `#[unstable] #[doc(hidden)] pub` to: - // - deter downstream users from accessing it (which would be unsound!), - // - let the `pin!` macro access it (such a macro requires using struct - // literal syntax in order to benefit from lifetime extension). - // - // However, if the `Deref` impl exposes a field with the same name as this - // field, then the two will collide, resulting in a confusing error when the - // user attempts to access the field through a `Pin`. Therefore, the - // name `__pointer` is designed to be unlikely to collide with any other - // field. Long-term, macro hygiene is expected to offer a more robust - // alternative, alongside `unsafe` fields. - #[unstable(feature = "unsafe_pin_internals", issue = "none")] - #[doc(hidden)] - pub __pointer: Ptr, + /// Only public for bootstrap. + #[cfg(bootstrap)] + pub pointer: Ptr, + #[cfg(not(bootstrap))] + pointer: Ptr, } // The following implementations aren't derived in order to avoid soundness -// issues. `&self.__pointer` should not be accessible to untrusted trait +// issues. `&self.pointer` should not be accessible to untrusted trait // implementations. // // See for more details. @@ -1218,7 +1214,7 @@ impl> Pin { #[rustc_const_stable(feature = "const_pin", since = "1.84.0")] #[stable(feature = "pin_into_inner", since = "1.39.0")] pub const fn into_inner(pin: Pin) -> Ptr { - pin.__pointer + pin.pointer } } @@ -1355,7 +1351,7 @@ impl Pin { #[rustc_const_stable(feature = "const_pin", since = "1.84.0")] #[stable(feature = "pin", since = "1.33.0")] pub const unsafe fn new_unchecked(pointer: Ptr) -> Pin { - Pin { __pointer: pointer } + Pin { pointer } } /// Gets a shared reference to the pinned value this [`Pin`] points to. @@ -1369,7 +1365,7 @@ impl Pin { #[inline(always)] pub fn as_ref(&self) -> Pin<&Ptr::Target> { // SAFETY: see documentation on this function - unsafe { Pin::new_unchecked(&*self.__pointer) } + unsafe { Pin::new_unchecked(&*self.pointer) } } } @@ -1413,7 +1409,7 @@ impl Pin { #[inline(always)] pub fn as_mut(&mut self) -> Pin<&mut Ptr::Target> { // SAFETY: see documentation on this function - unsafe { Pin::new_unchecked(&mut *self.__pointer) } + unsafe { Pin::new_unchecked(&mut *self.pointer) } } /// Gets `Pin<&mut T>` to the underlying pinned value from this nested `Pin`-pointer. @@ -1480,7 +1476,7 @@ impl Pin { where Ptr::Target: Sized, { - *(self.__pointer) = value; + *(self.pointer) = value; } } @@ -1508,7 +1504,7 @@ impl Pin { #[rustc_const_stable(feature = "const_pin", since = "1.84.0")] #[stable(feature = "pin_into_inner", since = "1.39.0")] pub const unsafe fn into_inner_unchecked(pin: Pin) -> Ptr { - pin.__pointer + pin.pointer } } @@ -1534,7 +1530,7 @@ impl<'a, T: ?Sized> Pin<&'a T> { U: ?Sized, F: FnOnce(&T) -> &U, { - let pointer = &*self.__pointer; + let pointer = &*self.pointer; let new_pointer = func(pointer); // SAFETY: the safety contract for `new_unchecked` must be @@ -1564,7 +1560,7 @@ impl<'a, T: ?Sized> Pin<&'a T> { #[rustc_const_stable(feature = "const_pin", since = "1.84.0")] #[stable(feature = "pin", since = "1.33.0")] pub const fn get_ref(self) -> &'a T { - self.__pointer + self.pointer } } @@ -1575,7 +1571,7 @@ impl<'a, T: ?Sized> Pin<&'a mut T> { #[rustc_const_stable(feature = "const_pin", since = "1.84.0")] #[stable(feature = "pin", since = "1.33.0")] pub const fn into_ref(self) -> Pin<&'a T> { - Pin { __pointer: self.__pointer } + Pin { pointer: self.pointer } } /// Gets a mutable reference to the data inside of this `Pin`. @@ -1595,7 +1591,7 @@ impl<'a, T: ?Sized> Pin<&'a mut T> { where T: Unpin, { - self.__pointer + self.pointer } /// Gets a mutable reference to the data inside of this `Pin`. @@ -1613,7 +1609,7 @@ impl<'a, T: ?Sized> Pin<&'a mut T> { #[stable(feature = "pin", since = "1.33.0")] #[rustc_const_stable(feature = "const_pin", since = "1.84.0")] pub const unsafe fn get_unchecked_mut(self) -> &'a mut T { - self.__pointer + self.pointer } /// Constructs a new pin by mapping the interior value. @@ -1700,21 +1696,21 @@ impl LegacyReceiver for Pin {} #[stable(feature = "pin", since = "1.33.0")] impl fmt::Debug for Pin { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Debug::fmt(&self.__pointer, f) + fmt::Debug::fmt(&self.pointer, f) } } #[stable(feature = "pin", since = "1.33.0")] impl fmt::Display for Pin { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(&self.__pointer, f) + fmt::Display::fmt(&self.pointer, f) } } #[stable(feature = "pin", since = "1.33.0")] impl fmt::Pointer for Pin { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Pointer::fmt(&self.__pointer, f) + fmt::Pointer::fmt(&self.pointer, f) } } @@ -1940,80 +1936,22 @@ unsafe impl PinCoerceUnsized for *mut T {} /// constructor. /// /// [`Box::pin`]: ../../std/boxed/struct.Box.html#method.pin +#[cfg(not(bootstrap))] #[stable(feature = "pin_macro", since = "1.68.0")] #[rustc_macro_transparency = "semitransparent"] -#[allow_internal_unstable(unsafe_pin_internals)] -#[cfg_attr(not(bootstrap), rustc_macro_edition_2021)] +#[allow_internal_unstable(super_let)] pub macro pin($value:expr $(,)?) { - // This is `Pin::new_unchecked(&mut { $value })`, so, for starters, let's - // review such a hypothetical macro (that any user-code could define): - // - // ```rust - // macro_rules! pin {( $value:expr ) => ( - // match &mut { $value } { at_value => unsafe { // Do not wrap `$value` in an `unsafe` block. - // $crate::pin::Pin::<&mut _>::new_unchecked(at_value) - // }} - // )} - // ``` - // - // Safety: - // - `type P = &mut _`. There are thus no pathological `Deref{,Mut}` impls - // that would break `Pin`'s invariants. - // - `{ $value }` is braced, making it a _block expression_, thus **moving** - // the given `$value`, and making it _become an **anonymous** temporary_. - // By virtue of being anonymous, it can no longer be accessed, thus - // preventing any attempts to `mem::replace` it or `mem::forget` it, _etc._ - // - // This gives us a `pin!` definition that is sound, and which works, but only - // in certain scenarios: - // - If the `pin!(value)` expression is _directly_ fed to a function call: - // `let poll = pin!(fut).poll(cx);` - // - If the `pin!(value)` expression is part of a scrutinee: - // ```rust - // match pin!(fut) { pinned_fut => { - // pinned_fut.as_mut().poll(...); - // pinned_fut.as_mut().poll(...); - // }} // <- `fut` is dropped here. - // ``` - // Alas, it doesn't work for the more straight-forward use-case: `let` bindings. - // ```rust - // let pinned_fut = pin!(fut); // <- temporary value is freed at the end of this statement - // pinned_fut.poll(...) // error[E0716]: temporary value dropped while borrowed - // // note: consider using a `let` binding to create a longer lived value - // ``` - // - Issues such as this one are the ones motivating https://github.com/rust-lang/rfcs/pull/66 - // - // This makes such a macro incredibly unergonomic in practice, and the reason most macros - // out there had to take the path of being a statement/binding macro (_e.g._, `pin!(future);`) - // instead of featuring the more intuitive ergonomics of an expression macro. - // - // Luckily, there is a way to avoid the problem. Indeed, the problem stems from the fact that a - // temporary is dropped at the end of its enclosing statement when it is part of the parameters - // given to function call, which has precisely been the case with our `Pin::new_unchecked()`! - // For instance, - // ```rust - // let p = Pin::new_unchecked(&mut ); - // ``` - // becomes: - // ```rust - // let p = { let mut anon = ; &mut anon }; - // ``` - // - // However, when using a literal braced struct to construct the value, references to temporaries - // can then be taken. This makes Rust change the lifespan of such temporaries so that they are, - // instead, dropped _at the end of the enscoping block_. - // For instance, - // ```rust - // let p = Pin { __pointer: &mut }; - // ``` - // becomes: - // ```rust - // let mut anon = ; - // let p = Pin { __pointer: &mut anon }; - // ``` - // which is *exactly* what we want. - // - // See https://doc.rust-lang.org/1.58.1/reference/destructors.html#temporary-lifetime-extension - // for more info. - $crate::pin::Pin::<&mut _> { __pointer: &mut { $value } } + { + super let mut pinned = $value; + // SAFETY: The value is pinned: it is the local above which cannot be named outside this macro. + unsafe { $crate::pin::Pin::new_unchecked(&mut pinned) } + } +} + +/// Only for bootstrap. +#[cfg(bootstrap)] +#[stable(feature = "pin_macro", since = "1.68.0")] +#[rustc_macro_transparency = "semitransparent"] +pub macro pin($value:expr $(,)?) { + $crate::pin::Pin::<&mut _> { pointer: &mut { $value } } } diff --git a/library/core/src/pin/unsafe_pinned.rs b/library/core/src/pin/unsafe_pinned.rs new file mode 100644 index 000000000000..5fb628c8adbc --- /dev/null +++ b/library/core/src/pin/unsafe_pinned.rs @@ -0,0 +1,197 @@ +use crate::marker::{PointerLike, Unpin}; +use crate::ops::{CoerceUnsized, DispatchFromDyn}; +use crate::pin::Pin; +use crate::{fmt, ptr}; + +/// This type provides a way to opt-out of typical aliasing rules; +/// specifically, `&mut UnsafePinned` is not guaranteed to be a unique pointer. +/// +/// However, even if you define your type like `pub struct Wrapper(UnsafePinned<...>)`, it is still +/// very risky to have an `&mut Wrapper` that aliases anything else. Many functions that work +/// generically on `&mut T` assume that the memory that stores `T` is uniquely owned (such as +/// `mem::swap`). In other words, while having aliasing with `&mut Wrapper` is not immediate +/// Undefined Behavior, it is still unsound to expose such a mutable reference to code you do not +/// control! Techniques such as pinning via [`Pin`] are needed to ensure soundness. +/// +/// Similar to [`UnsafeCell`](crate::cell::UnsafeCell), `UnsafePinned` will not usually show up in +/// the public API of a library. It is an internal implementation detail of libraries that need to +/// support aliasing mutable references. +/// +/// Further note that this does *not* lift the requirement that shared references must be read-only! +/// Use `UnsafeCell` for that. +/// +/// This type blocks niches the same way `UnsafeCell` does. +#[cfg_attr(not(bootstrap), lang = "unsafe_pinned")] +#[repr(transparent)] +#[unstable(feature = "unsafe_pinned", issue = "125735")] +pub struct UnsafePinned { + value: T, +} + +/// When this type is used, that almost certainly means safe APIs need to use pinning to avoid the +/// aliases from becoming invalidated. Therefore let's mark this as `!Unpin`. You can always opt +/// back in to `Unpin` with an `impl` block, provided your API is still sound while unpinned. +#[unstable(feature = "unsafe_pinned", issue = "125735")] +impl !Unpin for UnsafePinned {} + +/// The type is `Copy` when `T` is to avoid people assuming that `Copy` implies there is no +/// `UnsafePinned` anywhere. (This is an issue with `UnsafeCell`: people use `Copy` bounds to mean +/// `Freeze`.) Given that there is no `unsafe impl Copy for ...`, this is also the option that +/// leaves the user more choices (as they can always wrap this in a `!Copy` type). +// FIXME(unsafe_pinned): this may be unsound or a footgun? +#[unstable(feature = "unsafe_pinned", issue = "125735")] +impl Copy for UnsafePinned {} + +#[unstable(feature = "unsafe_pinned", issue = "125735")] +impl Clone for UnsafePinned { + fn clone(&self) -> Self { + *self + } +} + +// `Send` and `Sync` are inherited from `T`. This is similar to `SyncUnsafeCell`, since +// we eventually concluded that `UnsafeCell` implicitly making things `!Sync` is sometimes +// unergonomic. A type that needs to be `!Send`/`!Sync` should really have an explicit +// opt-out itself, e.g. via an `PhantomData<*mut T>` or (one day) via `impl !Send`/`impl !Sync`. + +impl UnsafePinned { + /// Constructs a new instance of `UnsafePinned` which will wrap the specified value. + /// + /// All access to the inner value through `&UnsafePinned` or `&mut UnsafePinned` or + /// `Pin<&mut UnsafePinned>` requires `unsafe` code. + #[inline(always)] + #[must_use] + #[unstable(feature = "unsafe_pinned", issue = "125735")] + pub const fn new(value: T) -> Self { + UnsafePinned { value } + } + + /// Unwraps the value, consuming this `UnsafePinned`. + #[inline(always)] + #[must_use] + #[unstable(feature = "unsafe_pinned", issue = "125735")] + #[rustc_allow_const_fn_unstable(const_precise_live_drops)] + pub const fn into_inner(self) -> T { + self.value + } +} + +impl UnsafePinned { + /// Get read-write access to the contents of a pinned `UnsafePinned`. + #[inline(always)] + #[must_use] + #[unstable(feature = "unsafe_pinned", issue = "125735")] + pub const fn get_mut_pinned(self: Pin<&mut Self>) -> *mut T { + // SAFETY: we're not using `get_unchecked_mut` to unpin anything + unsafe { self.get_unchecked_mut() }.get_mut_unchecked() + } + + /// Get read-write access to the contents of an `UnsafePinned`. + /// + /// You should usually be using `get_mut_pinned` instead to explicitly track the fact that this + /// memory is "pinned" due to there being aliases. + #[inline(always)] + #[must_use] + #[unstable(feature = "unsafe_pinned", issue = "125735")] + pub const fn get_mut_unchecked(&mut self) -> *mut T { + ptr::from_mut(self) as *mut T + } + + /// Get read-only access to the contents of a shared `UnsafePinned`. + /// + /// Note that `&UnsafePinned` is read-only if `&T` is read-only. This means that if there is + /// mutation of the `T`, future reads from the `*const T` returned here are UB! Use + /// [`UnsafeCell`] if you also need interior mutability. + /// + /// [`UnsafeCell`]: crate::cell::UnsafeCell + /// + /// ```rust,no_run + /// #![feature(unsafe_pinned)] + /// use std::pin::UnsafePinned; + /// + /// unsafe { + /// let mut x = UnsafePinned::new(0); + /// let ptr = x.get(); // read-only pointer, assumes immutability + /// x.get_mut_unchecked().write(1); + /// ptr.read(); // UB! + /// } + /// ``` + #[inline(always)] + #[must_use] + #[unstable(feature = "unsafe_pinned", issue = "125735")] + pub const fn get(&self) -> *const T { + ptr::from_ref(self) as *const T + } + + /// Gets an immutable pointer to the wrapped value. + /// + /// The difference from [`get`] is that this function accepts a raw pointer, which is useful to + /// avoid the creation of temporary references. + /// + /// [`get`]: UnsafePinned::get + #[inline(always)] + #[must_use] + #[unstable(feature = "unsafe_pinned", issue = "125735")] + pub const fn raw_get(this: *const Self) -> *const T { + this as *const T + } + + /// Gets a mutable pointer to the wrapped value. + /// + /// The difference from [`get_mut_pinned`] and [`get_mut_unchecked`] is that this function + /// accepts a raw pointer, which is useful to avoid the creation of temporary references. + /// + /// [`get_mut_pinned`]: UnsafePinned::get_mut_pinned + /// [`get_mut_unchecked`]: UnsafePinned::get_mut_unchecked + #[inline(always)] + #[must_use] + #[unstable(feature = "unsafe_pinned", issue = "125735")] + pub const fn raw_get_mut(this: *mut Self) -> *mut T { + this as *mut T + } +} + +#[unstable(feature = "unsafe_pinned", issue = "125735")] +impl Default for UnsafePinned { + /// Creates an `UnsafePinned`, with the `Default` value for T. + fn default() -> Self { + UnsafePinned::new(T::default()) + } +} + +#[unstable(feature = "unsafe_pinned", issue = "125735")] +impl From for UnsafePinned { + /// Creates a new `UnsafePinned` containing the given value. + fn from(value: T) -> Self { + UnsafePinned::new(value) + } +} + +#[unstable(feature = "unsafe_pinned", issue = "125735")] +impl fmt::Debug for UnsafePinned { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("UnsafePinned").finish_non_exhaustive() + } +} + +#[unstable(feature = "coerce_unsized", issue = "18598")] +// #[unstable(feature = "unsafe_pinned", issue = "125735")] +impl, U> CoerceUnsized> for UnsafePinned {} + +// Allow types that wrap `UnsafePinned` to also implement `DispatchFromDyn` +// and become dyn-compatible method receivers. +// Note that currently `UnsafePinned` itself cannot be a method receiver +// because it does not implement Deref. +// In other words: +// `self: UnsafePinned<&Self>` won't work +// `self: UnsafePinned` becomes possible +// FIXME(unsafe_pinned) this logic is copied from UnsafeCell, is it still sound? +#[unstable(feature = "dispatch_from_dyn", issue = "none")] +// #[unstable(feature = "unsafe_pinned", issue = "125735")] +impl, U> DispatchFromDyn> for UnsafePinned {} + +#[unstable(feature = "pointer_like_trait", issue = "none")] +// #[unstable(feature = "unsafe_pinned", issue = "125735")] +impl PointerLike for UnsafePinned {} + +// FIXME(unsafe_pinned): impl PinCoerceUnsized for UnsafePinned? diff --git a/library/core/src/prelude/v1.rs b/library/core/src/prelude/v1.rs index c5975c030503..8f1b5275871e 100644 --- a/library/core/src/prelude/v1.rs +++ b/library/core/src/prelude/v1.rs @@ -117,5 +117,4 @@ pub use crate::macros::builtin::deref; issue = "63063", reason = "`type_alias_impl_trait` has open design concerns" )] -#[cfg(not(bootstrap))] pub use crate::macros::builtin::define_opaque; diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 71a84aff2460..0854e31c1997 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -764,8 +764,8 @@ impl *const T { /// // This would be incorrect, as the pointers are not correctly ordered: /// // ptr1.offset_from_unsigned(ptr2) /// ``` - #[stable(feature = "ptr_sub_ptr", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "const_ptr_sub_ptr", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "ptr_sub_ptr", since = "1.87.0")] + #[rustc_const_stable(feature = "const_ptr_sub_ptr", since = "1.87.0")] #[inline] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn offset_from_unsigned(self, origin: *const T) -> usize @@ -809,8 +809,8 @@ impl *const T { /// /// For non-`Sized` pointees this operation considers only the data pointers, /// ignoring the metadata. - #[stable(feature = "ptr_sub_ptr", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "const_ptr_sub_ptr", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "ptr_sub_ptr", since = "1.87.0")] + #[rustc_const_stable(feature = "const_ptr_sub_ptr", since = "1.87.0")] #[inline] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn byte_offset_from_unsigned(self, origin: *const U) -> usize { diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index ea53da78d3bd..445c789a7de2 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -278,7 +278,7 @@ //! ### Using Strict Provenance //! //! Most code needs no changes to conform to strict provenance, as the only really concerning -//! operation is casts from usize to a pointer. For code which *does* cast a `usize` to a pointer, +//! operation is casts from `usize` to a pointer. For code which *does* cast a `usize` to a pointer, //! the scope of the change depends on exactly what you're doing. //! //! In general, you just need to make sure that if you want to convert a `usize` address to a @@ -398,6 +398,7 @@ use crate::cmp::Ordering; use crate::intrinsics::const_eval_select; use crate::marker::FnPtr; use crate::mem::{self, MaybeUninit, SizedTypeProperties}; +use crate::num::NonZero; use crate::{fmt, hash, intrinsics, ub_checks}; mod alignment; @@ -1094,51 +1095,25 @@ pub const unsafe fn swap_nonoverlapping(x: *mut T, y: *mut T, count: usize) { // are pointers inside `T` we will copy them in one go rather than trying to copy a part // of a pointer (which would not work). // SAFETY: Same preconditions as this function - unsafe { swap_nonoverlapping_simple_untyped(x, y, count) } + unsafe { swap_nonoverlapping_const(x, y, count) } } else { - macro_rules! attempt_swap_as_chunks { - ($ChunkTy:ty) => { - if align_of::() >= align_of::<$ChunkTy>() - && size_of::() % size_of::<$ChunkTy>() == 0 - { - let x: *mut $ChunkTy = x.cast(); - let y: *mut $ChunkTy = y.cast(); - let count = count * (size_of::() / size_of::<$ChunkTy>()); - // SAFETY: these are the same bytes that the caller promised were - // ok, just typed as `MaybeUninit`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_untyped(x, y, count) }; - } - }; + // Going though a slice here helps codegen know the size fits in `isize` + let slice = slice_from_raw_parts_mut(x, count); + // SAFETY: This is all readable from the pointer, meaning it's one + // allocated object, and thus cannot be more than isize::MAX bytes. + let bytes = unsafe { mem::size_of_val_raw::<[T]>(slice) }; + if let Some(bytes) = NonZero::new(bytes) { + // SAFETY: These are the same ranges, just expressed in a different + // type, so they're still non-overlapping. + unsafe { swap_nonoverlapping_bytes(x.cast(), y.cast(), bytes) }; } - - // Split up the slice into small power-of-two-sized chunks that LLVM is able - // to vectorize (unless it's a special type with more-than-pointer alignment, - // because we don't want to pessimize things like slices of SIMD vectors.) - if align_of::() <= size_of::() - && (!size_of::().is_power_of_two() - || size_of::() > size_of::() * 2) - { - attempt_swap_as_chunks!(usize); - attempt_swap_as_chunks!(u8); - } - - // SAFETY: Same preconditions as this function - unsafe { swap_nonoverlapping_simple_untyped(x, y, count) } } ) } /// Same behavior and safety conditions as [`swap_nonoverlapping`] -/// -/// LLVM can vectorize this (at least it can for the power-of-two-sized types -/// `swap_nonoverlapping` tries to use) so no need to manually SIMD it. #[inline] -const unsafe fn swap_nonoverlapping_simple_untyped(x: *mut T, y: *mut T, count: usize) { - let x = x.cast::>(); - let y = y.cast::>(); +const unsafe fn swap_nonoverlapping_const(x: *mut T, y: *mut T, count: usize) { let mut i = 0; while i < count { // SAFETY: By precondition, `i` is in-bounds because it's below `n` @@ -1147,26 +1122,91 @@ const unsafe fn swap_nonoverlapping_simple_untyped(x: *mut T, y: *mut T, coun // and it's distinct from `x` since the ranges are non-overlapping let y = unsafe { y.add(i) }; - // If we end up here, it's because we're using a simple type -- like - // a small power-of-two-sized thing -- or a special type with particularly - // large alignment, particularly SIMD types. - // Thus, we're fine just reading-and-writing it, as either it's small - // and that works well anyway or it's special and the type's author - // presumably wanted things to be done in the larger chunk. - // SAFETY: we're only ever given pointers that are valid to read/write, // including being aligned, and nothing here panics so it's drop-safe. unsafe { - let a: MaybeUninit = read(x); - let b: MaybeUninit = read(y); - write(x, b); - write(y, a); + // Note that it's critical that these use `copy_nonoverlapping`, + // rather than `read`/`write`, to avoid #134713 if T has padding. + let mut temp = MaybeUninit::::uninit(); + copy_nonoverlapping(x, temp.as_mut_ptr(), 1); + copy_nonoverlapping(y, x, 1); + copy_nonoverlapping(temp.as_ptr(), y, 1); } i += 1; } } +// Don't let MIR inline this, because we really want it to keep its noalias metadata +#[rustc_no_mir_inline] +#[inline] +fn swap_chunk(x: &mut MaybeUninit<[u8; N]>, y: &mut MaybeUninit<[u8; N]>) { + let a = *x; + let b = *y; + *x = b; + *y = a; +} + +#[inline] +unsafe fn swap_nonoverlapping_bytes(x: *mut u8, y: *mut u8, bytes: NonZero) { + // Same as `swap_nonoverlapping::<[u8; N]>`. + unsafe fn swap_nonoverlapping_chunks( + x: *mut MaybeUninit<[u8; N]>, + y: *mut MaybeUninit<[u8; N]>, + chunks: NonZero, + ) { + let chunks = chunks.get(); + for i in 0..chunks { + // SAFETY: i is in [0, chunks) so the adds and dereferences are in-bounds. + unsafe { swap_chunk(&mut *x.add(i), &mut *y.add(i)) }; + } + } + + // Same as `swap_nonoverlapping_bytes`, but accepts at most 1+2+4=7 bytes + #[inline] + unsafe fn swap_nonoverlapping_short(x: *mut u8, y: *mut u8, bytes: NonZero) { + // Tail handling for auto-vectorized code sometimes has element-at-a-time behaviour, + // see . + // By swapping as different sizes, rather than as a loop over bytes, + // we make sure not to end up with, say, seven byte-at-a-time copies. + + let bytes = bytes.get(); + let mut i = 0; + macro_rules! swap_prefix { + ($($n:literal)+) => {$( + if (bytes & $n) != 0 { + // SAFETY: `i` can only have the same bits set as those in bytes, + // so these `add`s are in-bounds of `bytes`. But the bit for + // `$n` hasn't been set yet, so the `$n` bytes that `swap_chunk` + // will read and write are within the usable range. + unsafe { swap_chunk::<$n>(&mut*x.add(i).cast(), &mut*y.add(i).cast()) }; + i |= $n; + } + )+}; + } + swap_prefix!(4 2 1); + debug_assert_eq!(i, bytes); + } + + const CHUNK_SIZE: usize = size_of::<*const ()>(); + let bytes = bytes.get(); + + let chunks = bytes / CHUNK_SIZE; + let tail = bytes % CHUNK_SIZE; + if let Some(chunks) = NonZero::new(chunks) { + // SAFETY: this is bytes/CHUNK_SIZE*CHUNK_SIZE bytes, which is <= bytes, + // so it's within the range of our non-overlapping bytes. + unsafe { swap_nonoverlapping_chunks::(x.cast(), y.cast(), chunks) }; + } + if let Some(tail) = NonZero::new(tail) { + const { assert!(CHUNK_SIZE <= 8) }; + let delta = chunks * CHUNK_SIZE; + // SAFETY: the tail length is below CHUNK SIZE because of the remainder, + // and CHUNK_SIZE is at most 8 by the const assert, so tail <= 7 + unsafe { swap_nonoverlapping_short(x.add(delta), y.add(delta), tail) }; + } +} + /// Moves `src` into the pointed `dst`, returning the previous `dst` value. /// /// Neither value is dropped. diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 9e62beb80492..e29774963db0 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -937,8 +937,8 @@ impl *mut T { /// /// // This would be incorrect, as the pointers are not correctly ordered: /// // ptr1.offset_from(ptr2) - #[stable(feature = "ptr_sub_ptr", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "const_ptr_sub_ptr", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "ptr_sub_ptr", since = "1.87.0")] + #[rustc_const_stable(feature = "const_ptr_sub_ptr", since = "1.87.0")] #[inline] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn offset_from_unsigned(self, origin: *const T) -> usize @@ -959,8 +959,8 @@ impl *mut T { /// /// For non-`Sized` pointees this operation considers only the data pointers, /// ignoring the metadata. - #[stable(feature = "ptr_sub_ptr", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "const_ptr_sub_ptr", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "ptr_sub_ptr", since = "1.87.0")] + #[rustc_const_stable(feature = "const_ptr_sub_ptr", since = "1.87.0")] #[inline] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn byte_offset_from_unsigned(self, origin: *mut U) -> usize { diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index e019aafad393..68b8f0c3e4e1 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -900,8 +900,8 @@ impl NonNull { /// ``` #[inline] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - #[stable(feature = "ptr_sub_ptr", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "const_ptr_sub_ptr", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "ptr_sub_ptr", since = "1.87.0")] + #[rustc_const_stable(feature = "const_ptr_sub_ptr", since = "1.87.0")] pub const unsafe fn offset_from_unsigned(self, subtracted: NonNull) -> usize where T: Sized, @@ -922,8 +922,8 @@ impl NonNull { /// ignoring the metadata. #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - #[stable(feature = "ptr_sub_ptr", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "const_ptr_sub_ptr", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "ptr_sub_ptr", since = "1.87.0")] + #[rustc_const_stable(feature = "const_ptr_sub_ptr", since = "1.87.0")] pub const unsafe fn byte_offset_from_unsigned(self, origin: NonNull) -> usize { // SAFETY: the caller must uphold the safety contract for `byte_sub_ptr`. unsafe { self.as_ptr().byte_offset_from_unsigned(origin.as_ptr()) } diff --git a/library/core/src/slice/cmp.rs b/library/core/src/slice/cmp.rs index da85f42926e6..5ce72b46eee3 100644 --- a/library/core/src/slice/cmp.rs +++ b/library/core/src/slice/cmp.rs @@ -5,6 +5,7 @@ use crate::ascii; use crate::cmp::{self, BytewiseEq, Ordering}; use crate::intrinsics::compare_bytes; use crate::num::NonZero; +use crate::ops::ControlFlow; #[stable(feature = "rust1", since = "1.0.0")] impl PartialEq<[U]> for [T] @@ -31,12 +32,64 @@ impl Ord for [T] { } } +#[inline] +fn as_underlying(x: ControlFlow) -> u8 { + // SAFETY: This will only compile if `bool` and `ControlFlow` have the same + // size (which isn't guaranteed but this is libcore). Because they have the same + // size, it's a niched implementation, which in one byte means there can't be + // any uninitialized memory. The callers then only check for `0` or `1` from this, + // which must necessarily match the `Break` variant, and we're fine no matter + // what ends up getting picked as the value representing `Continue(())`. + unsafe { crate::mem::transmute(x) } +} + /// Implements comparison of slices [lexicographically](Ord#lexicographical-comparison). #[stable(feature = "rust1", since = "1.0.0")] impl PartialOrd for [T] { + #[inline] fn partial_cmp(&self, other: &[T]) -> Option { SlicePartialOrd::partial_compare(self, other) } + #[inline] + fn lt(&self, other: &Self) -> bool { + // This is certainly not the obvious way to implement these methods. + // Unfortunately, using anything that looks at the discriminant means that + // LLVM sees a check for `2` (aka `ControlFlow::Continue(())`) and + // gets very distracted by that, ending up generating extraneous code. + // This should be changed to something simpler once either LLVM is smarter, + // see , or we generate + // niche discriminant checks in a way that doesn't trigger it. + + as_underlying(self.__chaining_lt(other)) == 1 + } + #[inline] + fn le(&self, other: &Self) -> bool { + as_underlying(self.__chaining_le(other)) != 0 + } + #[inline] + fn gt(&self, other: &Self) -> bool { + as_underlying(self.__chaining_gt(other)) == 1 + } + #[inline] + fn ge(&self, other: &Self) -> bool { + as_underlying(self.__chaining_ge(other)) != 0 + } + #[inline] + fn __chaining_lt(&self, other: &Self) -> ControlFlow { + SliceChain::chaining_lt(self, other) + } + #[inline] + fn __chaining_le(&self, other: &Self) -> ControlFlow { + SliceChain::chaining_le(self, other) + } + #[inline] + fn __chaining_gt(&self, other: &Self) -> ControlFlow { + SliceChain::chaining_gt(self, other) + } + #[inline] + fn __chaining_ge(&self, other: &Self) -> ControlFlow { + SliceChain::chaining_ge(self, other) + } } #[doc(hidden)] @@ -99,26 +152,65 @@ trait SlicePartialOrd: Sized { fn partial_compare(left: &[Self], right: &[Self]) -> Option; } +#[doc(hidden)] +// intermediate trait for specialization of slice's PartialOrd chaining methods +trait SliceChain: Sized { + fn chaining_lt(left: &[Self], right: &[Self]) -> ControlFlow; + fn chaining_le(left: &[Self], right: &[Self]) -> ControlFlow; + fn chaining_gt(left: &[Self], right: &[Self]) -> ControlFlow; + fn chaining_ge(left: &[Self], right: &[Self]) -> ControlFlow; +} + +type AlwaysBreak = ControlFlow; + impl SlicePartialOrd for A { default fn partial_compare(left: &[A], right: &[A]) -> Option { - let l = cmp::min(left.len(), right.len()); - - // Slice to the loop iteration range to enable bound check - // elimination in the compiler - let lhs = &left[..l]; - let rhs = &right[..l]; - - for i in 0..l { - match lhs[i].partial_cmp(&rhs[i]) { - Some(Ordering::Equal) => (), - non_eq => return non_eq, - } - } - - left.len().partial_cmp(&right.len()) + let elem_chain = |a, b| match PartialOrd::partial_cmp(a, b) { + Some(Ordering::Equal) => ControlFlow::Continue(()), + non_eq => ControlFlow::Break(non_eq), + }; + let len_chain = |a: &_, b: &_| ControlFlow::Break(usize::partial_cmp(a, b)); + let AlwaysBreak::Break(b) = chaining_impl(left, right, elem_chain, len_chain); + b } } +impl SliceChain for A { + default fn chaining_lt(left: &[Self], right: &[Self]) -> ControlFlow { + chaining_impl(left, right, PartialOrd::__chaining_lt, usize::__chaining_lt) + } + default fn chaining_le(left: &[Self], right: &[Self]) -> ControlFlow { + chaining_impl(left, right, PartialOrd::__chaining_le, usize::__chaining_le) + } + default fn chaining_gt(left: &[Self], right: &[Self]) -> ControlFlow { + chaining_impl(left, right, PartialOrd::__chaining_gt, usize::__chaining_gt) + } + default fn chaining_ge(left: &[Self], right: &[Self]) -> ControlFlow { + chaining_impl(left, right, PartialOrd::__chaining_ge, usize::__chaining_ge) + } +} + +#[inline] +fn chaining_impl<'l, 'r, A: PartialOrd, B, C>( + left: &'l [A], + right: &'r [A], + elem_chain: impl Fn(&'l A, &'r A) -> ControlFlow, + len_chain: impl for<'a> FnOnce(&'a usize, &'a usize) -> ControlFlow, +) -> ControlFlow { + let l = cmp::min(left.len(), right.len()); + + // Slice to the loop iteration range to enable bound check + // elimination in the compiler + let lhs = &left[..l]; + let rhs = &right[..l]; + + for i in 0..l { + elem_chain(&lhs[i], &rhs[i])?; + } + + len_chain(&left.len(), &right.len()) +} + // This is the impl that we would like to have. Unfortunately it's not sound. // See `partial_ord_slice.rs`. /* @@ -165,21 +257,13 @@ trait SliceOrd: Sized { impl SliceOrd for A { default fn compare(left: &[Self], right: &[Self]) -> Ordering { - let l = cmp::min(left.len(), right.len()); - - // Slice to the loop iteration range to enable bound check - // elimination in the compiler - let lhs = &left[..l]; - let rhs = &right[..l]; - - for i in 0..l { - match lhs[i].cmp(&rhs[i]) { - Ordering::Equal => (), - non_eq => return non_eq, - } - } - - left.len().cmp(&right.len()) + let elem_chain = |a, b| match Ord::cmp(a, b) { + Ordering::Equal => ControlFlow::Continue(()), + non_eq => ControlFlow::Break(non_eq), + }; + let len_chain = |a: &_, b: &_| ControlFlow::Break(usize::cmp(a, b)); + let AlwaysBreak::Break(b) = chaining_impl(left, right, elem_chain, len_chain); + b } } @@ -191,7 +275,7 @@ impl SliceOrd for A { /// * For every `x` and `y` of this type, `Ord(x, y)` must return the same /// value as `Ord::cmp(transmute::<_, u8>(x), transmute::<_, u8>(y))`. #[rustc_specialization_trait] -unsafe trait UnsignedBytewiseOrd {} +unsafe trait UnsignedBytewiseOrd: Ord {} unsafe impl UnsignedBytewiseOrd for bool {} unsafe impl UnsignedBytewiseOrd for u8 {} @@ -225,6 +309,38 @@ impl SliceOrd for A { } } +// Don't generate our own chaining loops for `memcmp`-able things either. +impl SliceChain for A { + #[inline] + fn chaining_lt(left: &[Self], right: &[Self]) -> ControlFlow { + match SliceOrd::compare(left, right) { + Ordering::Equal => ControlFlow::Continue(()), + ne => ControlFlow::Break(ne.is_lt()), + } + } + #[inline] + fn chaining_le(left: &[Self], right: &[Self]) -> ControlFlow { + match SliceOrd::compare(left, right) { + Ordering::Equal => ControlFlow::Continue(()), + ne => ControlFlow::Break(ne.is_le()), + } + } + #[inline] + fn chaining_gt(left: &[Self], right: &[Self]) -> ControlFlow { + match SliceOrd::compare(left, right) { + Ordering::Equal => ControlFlow::Continue(()), + ne => ControlFlow::Break(ne.is_gt()), + } + } + #[inline] + fn chaining_ge(left: &[Self], right: &[Self]) -> ControlFlow { + match SliceOrd::compare(left, right) { + Ordering::Equal => ControlFlow::Continue(()), + ne => ControlFlow::Break(ne.is_ge()), + } + } +} + pub(super) trait SliceContains: Sized { fn slice_contains(&self, x: &[Self]) -> bool; } diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index c7e8d5f989dd..7b2a3fac38a3 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -1287,7 +1287,6 @@ impl [T] { /// // let chunks: &[[_; 0]] = slice.as_chunks_unchecked() // Zero-length chunks are never allowed /// ``` #[unstable(feature = "slice_as_chunks", issue = "74985")] - #[rustc_const_unstable(feature = "slice_as_chunks", issue = "74985")] #[inline] #[must_use] pub const unsafe fn as_chunks_unchecked(&self) -> &[[T; N]] { @@ -1333,7 +1332,6 @@ impl [T] { /// assert_eq!(chunks, &[['R', 'u'], ['s', 't']]); /// ``` #[unstable(feature = "slice_as_chunks", issue = "74985")] - #[rustc_const_unstable(feature = "slice_as_chunks", issue = "74985")] #[inline] #[track_caller] #[must_use] @@ -1368,7 +1366,6 @@ impl [T] { /// assert_eq!(chunks, &[['o', 'r'], ['e', 'm']]); /// ``` #[unstable(feature = "slice_as_chunks", issue = "74985")] - #[rustc_const_unstable(feature = "slice_as_chunks", issue = "74985")] #[inline] #[track_caller] #[must_use] @@ -1448,7 +1445,6 @@ impl [T] { /// // let chunks: &[[_; 0]] = slice.as_chunks_unchecked_mut() // Zero-length chunks are never allowed /// ``` #[unstable(feature = "slice_as_chunks", issue = "74985")] - #[rustc_const_unstable(feature = "slice_as_chunks", issue = "74985")] #[inline] #[must_use] pub const unsafe fn as_chunks_unchecked_mut(&mut self) -> &mut [[T; N]] { @@ -1489,7 +1485,6 @@ impl [T] { /// assert_eq!(v, &[1, 1, 2, 2, 9]); /// ``` #[unstable(feature = "slice_as_chunks", issue = "74985")] - #[rustc_const_unstable(feature = "slice_as_chunks", issue = "74985")] #[inline] #[track_caller] #[must_use] @@ -1530,7 +1525,6 @@ impl [T] { /// assert_eq!(v, &[9, 1, 1, 2, 2]); /// ``` #[unstable(feature = "slice_as_chunks", issue = "74985")] - #[rustc_const_unstable(feature = "slice_as_chunks", issue = "74985")] #[inline] #[track_caller] #[must_use] @@ -2828,7 +2822,7 @@ impl [T] { // Binary search interacts poorly with branch prediction, so force // the compiler to use conditional moves if supported by the target // architecture. - base = (cmp == Greater).select_unpredictable(base, mid); + base = hint::select_unpredictable(cmp == Greater, base, mid); // This is imprecise in the case where `size` is odd and the // comparison returns Greater: the mid element still gets included @@ -3721,7 +3715,7 @@ impl [T] { #[doc(alias = "memcpy")] #[inline] #[stable(feature = "copy_from_slice", since = "1.9.0")] - #[rustc_const_stable(feature = "const_copy_from_slice", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_copy_from_slice", since = "1.87.0")] #[track_caller] pub const fn copy_from_slice(&mut self, src: &[T]) where @@ -4331,7 +4325,7 @@ impl [T] { /// ``` #[inline] #[must_use = "method does not modify the slice if the range is out of bounds"] - #[stable(feature = "slice_take", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "slice_take", since = "1.87.0")] pub fn split_off<'a, R: OneSidedRange>( self: &mut &'a Self, range: R, @@ -4397,7 +4391,7 @@ impl [T] { /// ``` #[inline] #[must_use = "method does not modify the slice if the range is out of bounds"] - #[stable(feature = "slice_take", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "slice_take", since = "1.87.0")] pub fn split_off_mut<'a, R: OneSidedRange>( self: &mut &'a mut Self, range: R, @@ -4434,7 +4428,7 @@ impl [T] { /// assert_eq!(first, &'a'); /// ``` #[inline] - #[stable(feature = "slice_take", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "slice_take", since = "1.87.0")] #[rustc_const_unstable(feature = "const_split_off_first_last", issue = "138539")] pub const fn split_off_first<'a>(self: &mut &'a Self) -> Option<&'a T> { // FIXME(const-hack): Use `?` when available in const instead of `let-else`. @@ -4459,7 +4453,7 @@ impl [T] { /// assert_eq!(first, &'d'); /// ``` #[inline] - #[stable(feature = "slice_take", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "slice_take", since = "1.87.0")] #[rustc_const_unstable(feature = "const_split_off_first_last", issue = "138539")] pub const fn split_off_first_mut<'a>(self: &mut &'a mut Self) -> Option<&'a mut T> { // FIXME(const-hack): Use `mem::take` and `?` when available in const. @@ -4484,7 +4478,7 @@ impl [T] { /// assert_eq!(last, &'c'); /// ``` #[inline] - #[stable(feature = "slice_take", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "slice_take", since = "1.87.0")] #[rustc_const_unstable(feature = "const_split_off_first_last", issue = "138539")] pub const fn split_off_last<'a>(self: &mut &'a Self) -> Option<&'a T> { // FIXME(const-hack): Use `?` when available in const instead of `let-else`. @@ -4509,7 +4503,7 @@ impl [T] { /// assert_eq!(last, &'d'); /// ``` #[inline] - #[stable(feature = "slice_take", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "slice_take", since = "1.87.0")] #[rustc_const_unstable(feature = "const_split_off_first_last", issue = "138539")] pub const fn split_off_last_mut<'a>(self: &mut &'a mut Self) -> Option<&'a mut T> { // FIXME(const-hack): Use `mem::take` and `?` when available in const. @@ -4841,7 +4835,7 @@ impl [[T; N]] { /// assert!(empty_slice_of_arrays.as_flattened().is_empty()); /// ``` #[stable(feature = "slice_flatten", since = "1.80.0")] - #[rustc_const_stable(feature = "const_slice_flatten", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_slice_flatten", since = "1.87.0")] pub const fn as_flattened(&self) -> &[T] { let len = if T::IS_ZST { self.len().checked_mul(N).expect("slice len overflow") @@ -4878,7 +4872,7 @@ impl [[T; N]] { /// assert_eq!(array, [[6, 7, 8], [9, 10, 11], [12, 13, 14]]); /// ``` #[stable(feature = "slice_flatten", since = "1.80.0")] - #[rustc_const_stable(feature = "const_slice_flatten", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_slice_flatten", since = "1.87.0")] pub const fn as_flattened_mut(&mut self) -> &mut [T] { let len = if T::IS_ZST { self.len().checked_mul(N).expect("slice len overflow") diff --git a/library/core/src/slice/sort/shared/smallsort.rs b/library/core/src/slice/sort/shared/smallsort.rs index 95f196a40d01..4280f7570db4 100644 --- a/library/core/src/slice/sort/shared/smallsort.rs +++ b/library/core/src/slice/sort/shared/smallsort.rs @@ -2,7 +2,7 @@ use crate::mem::{self, ManuallyDrop, MaybeUninit}; use crate::slice::sort::shared::FreezeMarker; -use crate::{intrinsics, ptr, slice}; +use crate::{hint, intrinsics, ptr, slice}; // It's important to differentiate between SMALL_SORT_THRESHOLD performance for // small slices and small-sort performance sorting small sub-slices as part of @@ -408,8 +408,8 @@ where // } // The goal is to generate cmov instructions here. - let v_a_swap = should_swap.select_unpredictable(v_b, v_a); - let v_b_swap = should_swap.select_unpredictable(v_a, v_b); + let v_a_swap = hint::select_unpredictable(should_swap, v_b, v_a); + let v_b_swap = hint::select_unpredictable(should_swap, v_a, v_b); let v_b_swap_tmp = ManuallyDrop::new(ptr::read(v_b_swap)); ptr::copy(v_a_swap, v_a, 1); @@ -640,15 +640,15 @@ pub unsafe fn sort4_stable bool>( // 1, 1 | c b a d let c3 = is_less(&*c, &*a); let c4 = is_less(&*d, &*b); - let min = c3.select_unpredictable(c, a); - let max = c4.select_unpredictable(b, d); - let unknown_left = c3.select_unpredictable(a, c4.select_unpredictable(c, b)); - let unknown_right = c4.select_unpredictable(d, c3.select_unpredictable(b, c)); + let min = hint::select_unpredictable(c3, c, a); + let max = hint::select_unpredictable(c4, b, d); + let unknown_left = hint::select_unpredictable(c3, a, hint::select_unpredictable(c4, c, b)); + let unknown_right = hint::select_unpredictable(c4, d, hint::select_unpredictable(c3, b, c)); // Sort the last two unknown elements. let c5 = is_less(&*unknown_right, &*unknown_left); - let lo = c5.select_unpredictable(unknown_right, unknown_left); - let hi = c5.select_unpredictable(unknown_left, unknown_right); + let lo = hint::select_unpredictable(c5, unknown_right, unknown_left); + let hi = hint::select_unpredictable(c5, unknown_left, unknown_right); ptr::copy_nonoverlapping(min, dst, 1); ptr::copy_nonoverlapping(lo, dst.add(1), 1); diff --git a/library/core/src/str/converts.rs b/library/core/src/str/converts.rs index 1276d9014f0e..37854a4da64c 100644 --- a/library/core/src/str/converts.rs +++ b/library/core/src/str/converts.rs @@ -126,7 +126,7 @@ pub const fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error> { /// See the docs for [`Utf8Error`] for more details on the kinds of /// errors that can be returned. #[stable(feature = "str_mut_extras", since = "1.20.0")] -#[rustc_const_stable(feature = "const_str_from_utf8", since = "CURRENT_RUSTC_VERSION")] +#[rustc_const_stable(feature = "const_str_from_utf8", since = "1.87.0")] #[rustc_diagnostic_item = "str_from_utf8_mut"] pub const fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> { // FIXME(const-hack): This should use `?` again, once it's `const` diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index 5cc08f8a71af..79b4953fcc11 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -230,8 +230,8 @@ impl str { /// /// assert_eq!("💖", sparkle_heart); /// ``` - #[stable(feature = "inherent_str_constructors", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "inherent_str_constructors", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "inherent_str_constructors", since = "1.87.0")] + #[rustc_const_stable(feature = "inherent_str_constructors", since = "1.87.0")] #[rustc_diagnostic_item = "str_inherent_from_utf8"] pub const fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error> { converts::from_utf8(v) @@ -263,8 +263,8 @@ impl str { /// ``` /// See the docs for [`Utf8Error`] for more details on the kinds of /// errors that can be returned. - #[stable(feature = "inherent_str_constructors", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "const_str_from_utf8", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "inherent_str_constructors", since = "1.87.0")] + #[rustc_const_stable(feature = "const_str_from_utf8", since = "1.87.0")] #[rustc_diagnostic_item = "str_inherent_from_utf8_mut"] pub const fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> { converts::from_utf8_mut(v) @@ -295,8 +295,8 @@ impl str { /// ``` #[inline] #[must_use] - #[stable(feature = "inherent_str_constructors", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "inherent_str_constructors", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "inherent_str_constructors", since = "1.87.0")] + #[rustc_const_stable(feature = "inherent_str_constructors", since = "1.87.0")] #[rustc_diagnostic_item = "str_inherent_from_utf8_unchecked"] pub const unsafe fn from_utf8_unchecked(v: &[u8]) -> &str { // SAFETY: converts::from_utf8_unchecked has the same safety requirements as this function. @@ -320,8 +320,8 @@ impl str { /// ``` #[inline] #[must_use] - #[stable(feature = "inherent_str_constructors", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "inherent_str_constructors", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "inherent_str_constructors", since = "1.87.0")] + #[rustc_const_stable(feature = "inherent_str_constructors", since = "1.87.0")] #[rustc_diagnostic_item = "str_inherent_from_utf8_unchecked_mut"] pub const unsafe fn from_utf8_unchecked_mut(v: &mut [u8]) -> &mut str { // SAFETY: converts::from_utf8_unchecked_mut has the same safety requirements as this function. diff --git a/library/core/src/tuple.rs b/library/core/src/tuple.rs index d754bb903430..02eb805ece12 100644 --- a/library/core/src/tuple.rs +++ b/library/core/src/tuple.rs @@ -2,7 +2,7 @@ use crate::cmp::Ordering::{self, *}; use crate::marker::{ConstParamTy_, StructuralPartialEq, UnsizedConstParamTy}; -use crate::ops::ControlFlow::{Break, Continue}; +use crate::ops::ControlFlow::{self, Break, Continue}; // Recursive macro for implementing n-ary tuple functions and operations // @@ -95,6 +95,22 @@ macro_rules! tuple_impls { fn gt(&self, other: &($($T,)+)) -> bool { lexical_ord!(gt, __chaining_gt, $( ${ignore($T)} self.${index()}, other.${index()} ),+) } + #[inline] + fn __chaining_lt(&self, other: &($($T,)+)) -> ControlFlow { + lexical_chain!(__chaining_lt, $( ${ignore($T)} self.${index()}, other.${index()} ),+) + } + #[inline] + fn __chaining_le(&self, other: &($($T,)+)) -> ControlFlow { + lexical_chain!(__chaining_le, $( ${ignore($T)} self.${index()}, other.${index()} ),+) + } + #[inline] + fn __chaining_gt(&self, other: &($($T,)+)) -> ControlFlow { + lexical_chain!(__chaining_gt, $( ${ignore($T)} self.${index()}, other.${index()} ),+) + } + #[inline] + fn __chaining_ge(&self, other: &($($T,)+)) -> ControlFlow { + lexical_chain!(__chaining_ge, $( ${ignore($T)} self.${index()}, other.${index()} ),+) + } } } @@ -187,6 +203,17 @@ macro_rules! lexical_ord { }; } +// Same parameter interleaving as `lexical_ord` above +macro_rules! lexical_chain { + ($chain_rel: ident, $a:expr, $b:expr $(,$rest_a:expr, $rest_b:expr)*) => {{ + PartialOrd::$chain_rel(&$a, &$b)?; + lexical_chain!($chain_rel $(,$rest_a, $rest_b)*) + }}; + ($chain_rel: ident) => { + Continue(()) + }; +} + macro_rules! lexical_partial_cmp { ($a:expr, $b:expr, $($rest_a:expr, $rest_b:expr),+) => { match ($a).partial_cmp(&$b) { diff --git a/library/coretests/tests/hint.rs b/library/coretests/tests/hint.rs new file mode 100644 index 000000000000..032bbc1dcc80 --- /dev/null +++ b/library/coretests/tests/hint.rs @@ -0,0 +1,23 @@ +#[test] +fn select_unpredictable_drop() { + use core::cell::Cell; + struct X<'a>(&'a Cell); + impl Drop for X<'_> { + fn drop(&mut self) { + self.0.set(true); + } + } + + let a_dropped = Cell::new(false); + let b_dropped = Cell::new(false); + let a = X(&a_dropped); + let b = X(&b_dropped); + assert!(!a_dropped.get()); + assert!(!b_dropped.get()); + let selected = core::hint::select_unpredictable(core::hint::black_box(true), a, b); + assert!(!a_dropped.get()); + assert!(b_dropped.get()); + drop(selected); + assert!(a_dropped.get()); + assert!(b_dropped.get()); +} diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index 7ad154796f64..1c43bfe0ed4a 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -68,6 +68,7 @@ #![feature(pointer_is_aligned_to)] #![feature(portable_simd)] #![feature(ptr_metadata)] +#![feature(select_unpredictable)] #![feature(slice_from_ptr_range)] #![feature(slice_internals)] #![feature(slice_partition_dedup)] @@ -147,6 +148,7 @@ mod ffi; mod fmt; mod future; mod hash; +mod hint; mod intrinsics; mod io; mod iter; diff --git a/library/coretests/tests/ptr.rs b/library/coretests/tests/ptr.rs index 6091926084a3..cc5f7946863a 100644 --- a/library/coretests/tests/ptr.rs +++ b/library/coretests/tests/ptr.rs @@ -984,3 +984,39 @@ fn test_ptr_metadata_in_const() { assert_eq!(SLICE_META, 3); assert_eq!(DYN_META.size_of(), 42); } + +// See +const fn ptr_swap_nonoverlapping_is_untyped_inner() { + #[repr(C)] + struct HasPadding(usize, u8); + + let buf1: [usize; 2] = [1000, 2000]; + let buf2: [usize; 2] = [3000, 4000]; + + // HasPadding and [usize; 2] have the same size and alignment, + // so swap_nonoverlapping should treat them the same + assert!(size_of::() == size_of::<[usize; 2]>()); + assert!(align_of::() == align_of::<[usize; 2]>()); + + let mut b1 = buf1; + let mut b2 = buf2; + // Safety: b1 and b2 are distinct local variables, + // with the same size and alignment as HasPadding. + unsafe { + std::ptr::swap_nonoverlapping( + b1.as_mut_ptr().cast::(), + b2.as_mut_ptr().cast::(), + 1, + ); + } + assert!(b1[0] == buf2[0]); + assert!(b1[1] == buf2[1]); + assert!(b2[0] == buf1[0]); + assert!(b2[1] == buf1[1]); +} + +#[test] +fn test_ptr_swap_nonoverlapping_is_untyped() { + ptr_swap_nonoverlapping_is_untyped_inner(); + const { ptr_swap_nonoverlapping_is_untyped_inner() }; +} diff --git a/library/panic_unwind/src/lib.rs b/library/panic_unwind/src/lib.rs index e5c1d6bdb3b0..50bd933aca20 100644 --- a/library/panic_unwind/src/lib.rs +++ b/library/panic_unwind/src/lib.rs @@ -79,11 +79,11 @@ cfg_if::cfg_if! { unsafe extern "C" { /// Handler in std called when a panic object is dropped outside of /// `catch_unwind`. - #[cfg_attr(not(bootstrap), rustc_std_internal_symbol)] + #[rustc_std_internal_symbol] fn __rust_drop_panic() -> !; /// Handler in std called when a foreign exception is caught. - #[cfg_attr(not(bootstrap), rustc_std_internal_symbol)] + #[rustc_std_internal_symbol] fn __rust_foreign_exception() -> !; } diff --git a/library/proc_macro/src/bridge/client.rs b/library/proc_macro/src/bridge/client.rs index f6d4825c67b2..e7d547966a5d 100644 --- a/library/proc_macro/src/bridge/client.rs +++ b/library/proc_macro/src/bridge/client.rs @@ -111,12 +111,6 @@ impl Clone for TokenStream { } } -impl Clone for SourceFile { - fn clone(&self) -> Self { - self.clone() - } -} - impl Span { pub(crate) fn def_site() -> Span { Bridge::with(|bridge| bridge.globals.def_site) diff --git a/library/proc_macro/src/bridge/mod.rs b/library/proc_macro/src/bridge/mod.rs index 52cc8fba0438..75d82d746540 100644 --- a/library/proc_macro/src/bridge/mod.rs +++ b/library/proc_macro/src/bridge/mod.rs @@ -9,7 +9,6 @@ #![deny(unsafe_code)] // proc_macros anyway don't work on wasm hosts so while both sides of this bridge can // be built with different versions of rustc, the wasm ABI changes don't really matter. -#![cfg_attr(bootstrap, allow(unknown_lints))] #![allow(wasm_c_abi)] use std::hash::Hash; @@ -82,16 +81,8 @@ macro_rules! with_api { $self: $S::TokenStream ) -> Vec>; }, - SourceFile { - fn drop($self: $S::SourceFile); - fn clone($self: &$S::SourceFile) -> $S::SourceFile; - fn eq($self: &$S::SourceFile, other: &$S::SourceFile) -> bool; - fn path($self: &$S::SourceFile) -> String; - fn is_real($self: &$S::SourceFile) -> bool; - }, Span { fn debug($self: $S::Span) -> String; - fn source_file($self: $S::Span) -> $S::SourceFile; fn parent($self: $S::Span) -> Option<$S::Span>; fn source($self: $S::Span) -> $S::Span; fn byte_range($self: $S::Span) -> Range; @@ -99,6 +90,8 @@ macro_rules! with_api { fn end($self: $S::Span) -> $S::Span; fn line($self: $S::Span) -> usize; fn column($self: $S::Span) -> usize; + fn file($self: $S::Span) -> String; + fn local_file($self: $S::Span) -> Option; fn join($self: $S::Span, other: $S::Span) -> Option<$S::Span>; fn subspan($self: $S::Span, start: Bound, end: Bound) -> Option<$S::Span>; fn resolved_at($self: $S::Span, at: $S::Span) -> $S::Span; @@ -121,7 +114,6 @@ macro_rules! with_api_handle_types { 'owned: FreeFunctions, TokenStream, - SourceFile, 'interned: Span, diff --git a/library/proc_macro/src/bridge/server.rs b/library/proc_macro/src/bridge/server.rs index 97e5a603c3ac..5beda7c3c96e 100644 --- a/library/proc_macro/src/bridge/server.rs +++ b/library/proc_macro/src/bridge/server.rs @@ -82,7 +82,6 @@ with_api_handle_types!(define_server_handles); pub trait Types { type FreeFunctions: 'static; type TokenStream: 'static + Clone; - type SourceFile: 'static + Clone; type Span: 'static + Copy + Eq + Hash; type Symbol: 'static; } diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs index f1cf0c5a2db7..c46dcebedcab 100644 --- a/library/proc_macro/src/lib.rs +++ b/library/proc_macro/src/lib.rs @@ -491,12 +491,6 @@ impl Span { Span(bridge::client::Span::mixed_site()) } - /// The original source file into which this span points. - #[unstable(feature = "proc_macro_span", issue = "54725")] - pub fn source_file(&self) -> SourceFile { - SourceFile(self.0.source_file()) - } - /// The `Span` for the tokens in the previous macro expansion from which /// `self` was generated from, if any. #[unstable(feature = "proc_macro_span", issue = "54725")] @@ -546,6 +540,25 @@ impl Span { self.0.column() } + /// The path to the source file in which this span occurs, for display purposes. + /// + /// This might not correspond to a valid file system path. + /// It might be remapped, or might be an artificial path such as `""`. + #[unstable(feature = "proc_macro_span", issue = "54725")] + pub fn file(&self) -> String { + self.0.file() + } + + /// The path to the source file in which this span occurs on disk. + /// + /// This is the actual path on disk. It is unaffected by path remapping. + /// + /// This path should not be embedded in the output of the macro; prefer `file()` instead. + #[unstable(feature = "proc_macro_span", issue = "54725")] + pub fn local_file(&self) -> Option { + self.0.local_file().map(|s| PathBuf::from(s)) + } + /// Creates a new span encompassing `self` and `other`. /// /// Returns `None` if `self` and `other` are from different files. @@ -614,58 +627,6 @@ impl fmt::Debug for Span { } } -/// The source file of a given `Span`. -#[unstable(feature = "proc_macro_span", issue = "54725")] -#[derive(Clone)] -pub struct SourceFile(bridge::client::SourceFile); - -impl SourceFile { - /// Gets the path to this source file. - /// - /// ### Note - /// If the code span associated with this `SourceFile` was generated by an external macro, this - /// macro, this might not be an actual path on the filesystem. Use [`is_real`] to check. - /// - /// Also note that even if `is_real` returns `true`, if `--remap-path-prefix` was passed on - /// the command line, the path as given might not actually be valid. - /// - /// [`is_real`]: Self::is_real - #[unstable(feature = "proc_macro_span", issue = "54725")] - pub fn path(&self) -> PathBuf { - PathBuf::from(self.0.path()) - } - - /// Returns `true` if this source file is a real source file, and not generated by an external - /// macro's expansion. - #[unstable(feature = "proc_macro_span", issue = "54725")] - pub fn is_real(&self) -> bool { - // This is a hack until intercrate spans are implemented and we can have real source files - // for spans generated in external macros. - // https://github.com/rust-lang/rust/pull/43604#issuecomment-333334368 - self.0.is_real() - } -} - -#[unstable(feature = "proc_macro_span", issue = "54725")] -impl fmt::Debug for SourceFile { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("SourceFile") - .field("path", &self.path()) - .field("is_real", &self.is_real()) - .finish() - } -} - -#[unstable(feature = "proc_macro_span", issue = "54725")] -impl PartialEq for SourceFile { - fn eq(&self, other: &Self) -> bool { - self.0.eq(&other.0) - } -} - -#[unstable(feature = "proc_macro_span", issue = "54725")] -impl Eq for SourceFile {} - /// A single token or a delimited sequence of token trees (e.g., `[1, (), ..]`). #[stable(feature = "proc_macro_lib2", since = "1.29.0")] #[derive(Clone)] diff --git a/library/profiler_builtins/build.rs b/library/profiler_builtins/build.rs index dd85239fa8cf..fc1a9ecc1ec3 100644 --- a/library/profiler_builtins/build.rs +++ b/library/profiler_builtins/build.rs @@ -9,8 +9,14 @@ use std::path::PathBuf; fn main() { if let Ok(rt) = tracked_env_var("LLVM_PROFILER_RT_LIB") { - println!("cargo::rustc-link-lib=static:+verbatim={rt}"); - return; + let rt = PathBuf::from(rt); + if let Some(lib) = rt.file_name() { + if let Some(dir) = rt.parent() { + println!("cargo::rustc-link-search=native={}", dir.display()); + } + println!("cargo::rustc-link-lib=static:+verbatim={}", lib.to_str().unwrap()); + return; + } } let target_os = env::var("CARGO_CFG_TARGET_OS").expect("CARGO_CFG_TARGET_OS was not set"); diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 176da603d58d..917a470842ca 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -18,7 +18,7 @@ cfg-if = { version = "1.0", features = ['rustc-dep-of-std'] } panic_unwind = { path = "../panic_unwind", optional = true } panic_abort = { path = "../panic_abort" } core = { path = "../core", public = true } -compiler_builtins = { version = "=0.1.152" } +compiler_builtins = { version = "=0.1.155" } unwind = { path = "../unwind" } hashbrown = { version = "0.15", default-features = false, features = [ 'rustc-dep-of-std', diff --git a/library/std/build.rs b/library/std/build.rs index d76d07a89f4e..40a56d4930d3 100644 --- a/library/std/build.rs +++ b/library/std/build.rs @@ -12,11 +12,6 @@ fn main() { .expect("CARGO_CFG_TARGET_POINTER_WIDTH was not set") .parse() .unwrap(); - let target_features: Vec<_> = env::var("CARGO_CFG_TARGET_FEATURE") - .unwrap_or_default() - .split(",") - .map(ToOwned::to_owned) - .collect(); let is_miri = env::var_os("CARGO_CFG_MIRI").is_some(); println!("cargo:rustc-check-cfg=cfg(netbsd10)"); @@ -108,8 +103,6 @@ fn main() { ("s390x", _) => false, // Unsupported ("arm64ec", _) => false, - // LLVM crash - ("aarch64", _) if !target_features.iter().any(|f| f == "neon") => false, // MinGW ABI bugs ("x86_64", "windows") if target_env == "gnu" && target_abi != "llvm" => false, // Infinite recursion diff --git a/library/std/src/alloc.rs b/library/std/src/alloc.rs index 5d2a304b41c5..75971ac90e78 100644 --- a/library/std/src/alloc.rs +++ b/library/std/src/alloc.rs @@ -348,7 +348,7 @@ fn default_alloc_error_hook(layout: Layout) { unsafe extern "Rust" { // This symbol is emitted by rustc next to __rust_alloc_error_handler. // Its value depends on the -Zoom={panic,abort} compiler option. - #[cfg_attr(not(bootstrap), rustc_std_internal_symbol)] + #[rustc_std_internal_symbol] static __rust_alloc_error_handler_should_panic: u8; } diff --git a/library/std/src/backtrace.rs b/library/std/src/backtrace.rs index 3e641ac5d904..3683485640c2 100644 --- a/library/std/src/backtrace.rs +++ b/library/std/src/backtrace.rs @@ -432,7 +432,7 @@ mod helper { use super::*; pub(super) type LazyResolve = impl (FnOnce() -> Capture) + Send + Sync + UnwindSafe; - #[cfg_attr(not(bootstrap), define_opaque(LazyResolve))] + #[define_opaque(LazyResolve)] pub(super) fn lazy_resolve(mut capture: Capture) -> LazyResolve { move || { // Use the global backtrace lock to synchronize this as it's a diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index 2487f5a2a503..0eef2bd225c0 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -683,7 +683,7 @@ impl HashMap { /// ``` #[inline] #[rustc_lint_query_instability] - #[stable(feature = "hash_extract_if", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "hash_extract_if", since = "1.87.0")] pub fn extract_if(&mut self, pred: F) -> ExtractIf<'_, K, V, F> where F: FnMut(&K, &mut V) -> bool, @@ -1677,7 +1677,7 @@ impl<'a, K, V> Drain<'a, K, V> { /// ]); /// let iter = map.extract_if(|_k, v| *v % 2 == 0); /// ``` -#[stable(feature = "hash_extract_if", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "hash_extract_if", since = "1.87.0")] #[must_use = "iterators are lazy and do nothing unless consumed"] pub struct ExtractIf<'a, K, V, F> where @@ -2294,7 +2294,7 @@ where } } -#[stable(feature = "hash_extract_if", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "hash_extract_if", since = "1.87.0")] impl Iterator for ExtractIf<'_, K, V, F> where F: FnMut(&K, &mut V) -> bool, @@ -2311,10 +2311,10 @@ where } } -#[stable(feature = "hash_extract_if", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "hash_extract_if", since = "1.87.0")] impl FusedIterator for ExtractIf<'_, K, V, F> where F: FnMut(&K, &mut V) -> bool {} -#[stable(feature = "hash_extract_if", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "hash_extract_if", since = "1.87.0")] impl<'a, K, V, F> fmt::Debug for ExtractIf<'a, K, V, F> where F: FnMut(&K, &mut V) -> bool, diff --git a/library/std/src/collections/hash/set.rs b/library/std/src/collections/hash/set.rs index a547a9943c1a..7be000594bc5 100644 --- a/library/std/src/collections/hash/set.rs +++ b/library/std/src/collections/hash/set.rs @@ -308,7 +308,7 @@ impl HashSet { /// ``` #[inline] #[rustc_lint_query_instability] - #[stable(feature = "hash_extract_if", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "hash_extract_if", since = "1.87.0")] pub fn extract_if(&mut self, pred: F) -> ExtractIf<'_, T, F> where F: FnMut(&T) -> bool, @@ -1390,7 +1390,7 @@ pub struct Drain<'a, K: 'a> { /// /// let mut extract_ifed = a.extract_if(|v| v % 2 == 0); /// ``` -#[stable(feature = "hash_extract_if", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "hash_extract_if", since = "1.87.0")] pub struct ExtractIf<'a, K, F> where F: FnMut(&K) -> bool, @@ -1673,7 +1673,7 @@ impl fmt::Debug for Drain<'_, K> { } } -#[stable(feature = "hash_extract_if", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "hash_extract_if", since = "1.87.0")] impl Iterator for ExtractIf<'_, K, F> where F: FnMut(&K) -> bool, @@ -1690,10 +1690,10 @@ where } } -#[stable(feature = "hash_extract_if", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "hash_extract_if", since = "1.87.0")] impl FusedIterator for ExtractIf<'_, K, F> where F: FnMut(&K) -> bool {} -#[stable(feature = "hash_extract_if", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "hash_extract_if", since = "1.87.0")] impl<'a, K, F> fmt::Debug for ExtractIf<'a, K, F> where F: FnMut(&K) -> bool, diff --git a/library/std/src/f128.rs b/library/std/src/f128.rs index ede219690511..217528fdf1c1 100644 --- a/library/std/src/f128.rs +++ b/library/std/src/f128.rs @@ -666,7 +666,7 @@ impl f128 { #[unstable(feature = "f128", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn cbrt(self) -> f128 { - unsafe { cmath::cbrtf128(self) } + cmath::cbrtf128(self) } /// Compute the distance between the origin and a point (`x`, `y`) on the @@ -703,7 +703,7 @@ impl f128 { #[unstable(feature = "f128", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn hypot(self, other: f128) -> f128 { - unsafe { cmath::hypotf128(self, other) } + cmath::hypotf128(self, other) } /// Computes the sine of a number (in radians). @@ -789,7 +789,7 @@ impl f128 { #[unstable(feature = "f128", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn tan(self) -> f128 { - unsafe { cmath::tanf128(self) } + cmath::tanf128(self) } /// Computes the arcsine of a number. Return value is in radians in @@ -824,7 +824,7 @@ impl f128 { #[unstable(feature = "f128", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn asin(self) -> f128 { - unsafe { cmath::asinf128(self) } + cmath::asinf128(self) } /// Computes the arccosine of a number. Return value is in radians in @@ -859,7 +859,7 @@ impl f128 { #[unstable(feature = "f128", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn acos(self) -> f128 { - unsafe { cmath::acosf128(self) } + cmath::acosf128(self) } /// Computes the arctangent of a number. Return value is in radians in the @@ -893,7 +893,7 @@ impl f128 { #[unstable(feature = "f128", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn atan(self) -> f128 { - unsafe { cmath::atanf128(self) } + cmath::atanf128(self) } /// Computes the four quadrant arctangent of `self` (`y`) and `other` (`x`) in radians. @@ -939,7 +939,7 @@ impl f128 { #[unstable(feature = "f128", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn atan2(self, other: f128) -> f128 { - unsafe { cmath::atan2f128(self, other) } + cmath::atan2f128(self, other) } /// Simultaneously computes the sine and cosine of the number, `x`. Returns @@ -1008,7 +1008,7 @@ impl f128 { #[unstable(feature = "f128", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn exp_m1(self) -> f128 { - unsafe { cmath::expm1f128(self) } + cmath::expm1f128(self) } /// Returns `ln(1+n)` (natural logarithm) more accurately than if @@ -1055,7 +1055,7 @@ impl f128 { #[rustc_allow_incoherent_impl] #[unstable(feature = "f128", issue = "116909")] pub fn ln_1p(self) -> f128 { - unsafe { cmath::log1pf128(self) } + cmath::log1pf128(self) } /// Hyperbolic sine function. @@ -1090,7 +1090,7 @@ impl f128 { #[unstable(feature = "f128", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn sinh(self) -> f128 { - unsafe { cmath::sinhf128(self) } + cmath::sinhf128(self) } /// Hyperbolic cosine function. @@ -1125,7 +1125,7 @@ impl f128 { #[unstable(feature = "f128", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn cosh(self) -> f128 { - unsafe { cmath::coshf128(self) } + cmath::coshf128(self) } /// Hyperbolic tangent function. @@ -1160,7 +1160,7 @@ impl f128 { #[unstable(feature = "f128", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn tanh(self) -> f128 { - unsafe { cmath::tanhf128(self) } + cmath::tanhf128(self) } /// Inverse hyperbolic sine function. @@ -1289,7 +1289,7 @@ impl f128 { // #[unstable(feature = "float_gamma", issue = "99842")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn gamma(self) -> f128 { - unsafe { cmath::tgammaf128(self) } + cmath::tgammaf128(self) } /// Natural logarithm of the absolute value of the gamma function @@ -1325,7 +1325,7 @@ impl f128 { #[must_use = "method returns a new number and does not mutate the original value"] pub fn ln_gamma(self) -> (f128, i32) { let mut signgamp: i32 = 0; - let x = unsafe { cmath::lgammaf128_r(self, &mut signgamp) }; + let x = cmath::lgammaf128_r(self, &mut signgamp); (x, signgamp) } @@ -1365,7 +1365,7 @@ impl f128 { // #[unstable(feature = "float_erf", issue = "136321")] #[inline] pub fn erf(self) -> f128 { - unsafe { cmath::erff128(self) } + cmath::erff128(self) } /// Complementary error function. @@ -1398,6 +1398,6 @@ impl f128 { // #[unstable(feature = "float_erf", issue = "136321")] #[inline] pub fn erfc(self) -> f128 { - unsafe { cmath::erfcf128(self) } + cmath::erfcf128(self) } } diff --git a/library/std/src/f16.rs b/library/std/src/f16.rs index 286993d736b9..4dadcbb51855 100644 --- a/library/std/src/f16.rs +++ b/library/std/src/f16.rs @@ -665,7 +665,7 @@ impl f16 { #[unstable(feature = "f16", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn cbrt(self) -> f16 { - (unsafe { cmath::cbrtf(self as f32) }) as f16 + cmath::cbrtf(self as f32) as f16 } /// Compute the distance between the origin and a point (`x`, `y`) on the @@ -701,7 +701,7 @@ impl f16 { #[unstable(feature = "f16", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn hypot(self, other: f16) -> f16 { - (unsafe { cmath::hypotf(self as f32, other as f32) }) as f16 + cmath::hypotf(self as f32, other as f32) as f16 } /// Computes the sine of a number (in radians). @@ -787,7 +787,7 @@ impl f16 { #[unstable(feature = "f16", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn tan(self) -> f16 { - (unsafe { cmath::tanf(self as f32) }) as f16 + cmath::tanf(self as f32) as f16 } /// Computes the arcsine of a number. Return value is in radians in @@ -822,7 +822,7 @@ impl f16 { #[unstable(feature = "f16", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn asin(self) -> f16 { - (unsafe { cmath::asinf(self as f32) }) as f16 + cmath::asinf(self as f32) as f16 } /// Computes the arccosine of a number. Return value is in radians in @@ -857,7 +857,7 @@ impl f16 { #[unstable(feature = "f16", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn acos(self) -> f16 { - (unsafe { cmath::acosf(self as f32) }) as f16 + cmath::acosf(self as f32) as f16 } /// Computes the arctangent of a number. Return value is in radians in the @@ -891,7 +891,7 @@ impl f16 { #[unstable(feature = "f16", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn atan(self) -> f16 { - (unsafe { cmath::atanf(self as f32) }) as f16 + cmath::atanf(self as f32) as f16 } /// Computes the four quadrant arctangent of `self` (`y`) and `other` (`x`) in radians. @@ -937,7 +937,7 @@ impl f16 { #[unstable(feature = "f16", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn atan2(self, other: f16) -> f16 { - (unsafe { cmath::atan2f(self as f32, other as f32) }) as f16 + cmath::atan2f(self as f32, other as f32) as f16 } /// Simultaneously computes the sine and cosine of the number, `x`. Returns @@ -1006,7 +1006,7 @@ impl f16 { #[unstable(feature = "f16", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn exp_m1(self) -> f16 { - (unsafe { cmath::expm1f(self as f32) }) as f16 + cmath::expm1f(self as f32) as f16 } /// Returns `ln(1+n)` (natural logarithm) more accurately than if @@ -1053,7 +1053,7 @@ impl f16 { #[unstable(feature = "f16", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn ln_1p(self) -> f16 { - (unsafe { cmath::log1pf(self as f32) }) as f16 + cmath::log1pf(self as f32) as f16 } /// Hyperbolic sine function. @@ -1088,7 +1088,7 @@ impl f16 { #[unstable(feature = "f16", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn sinh(self) -> f16 { - (unsafe { cmath::sinhf(self as f32) }) as f16 + cmath::sinhf(self as f32) as f16 } /// Hyperbolic cosine function. @@ -1123,7 +1123,7 @@ impl f16 { #[unstable(feature = "f16", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn cosh(self) -> f16 { - (unsafe { cmath::coshf(self as f32) }) as f16 + cmath::coshf(self as f32) as f16 } /// Hyperbolic tangent function. @@ -1158,7 +1158,7 @@ impl f16 { #[unstable(feature = "f16", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn tanh(self) -> f16 { - (unsafe { cmath::tanhf(self as f32) }) as f16 + cmath::tanhf(self as f32) as f16 } /// Inverse hyperbolic sine function. @@ -1287,7 +1287,7 @@ impl f16 { // #[unstable(feature = "float_gamma", issue = "99842")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn gamma(self) -> f16 { - (unsafe { cmath::tgammaf(self as f32) }) as f16 + cmath::tgammaf(self as f32) as f16 } /// Natural logarithm of the absolute value of the gamma function @@ -1323,7 +1323,7 @@ impl f16 { #[must_use = "method returns a new number and does not mutate the original value"] pub fn ln_gamma(self) -> (f16, i32) { let mut signgamp: i32 = 0; - let x = (unsafe { cmath::lgammaf_r(self as f32, &mut signgamp) }) as f16; + let x = cmath::lgammaf_r(self as f32, &mut signgamp) as f16; (x, signgamp) } @@ -1363,7 +1363,7 @@ impl f16 { // #[unstable(feature = "float_erf", issue = "136321")] #[inline] pub fn erf(self) -> f16 { - (unsafe { cmath::erff(self as f32) }) as f16 + cmath::erff(self as f32) as f16 } /// Complementary error function. @@ -1396,6 +1396,6 @@ impl f16 { // #[unstable(feature = "float_erf", issue = "136321")] #[inline] pub fn erfc(self) -> f16 { - (unsafe { cmath::erfcf(self as f32) }) as f16 + cmath::erfcf(self as f32) as f16 } } diff --git a/library/std/src/f32.rs b/library/std/src/f32.rs index 980e7f7793af..baf7002f3803 100644 --- a/library/std/src/f32.rs +++ b/library/std/src/f32.rs @@ -599,7 +599,7 @@ impl f32 { filing an issue describing your use-case too)." )] pub fn abs_sub(self, other: f32) -> f32 { - unsafe { cmath::fdimf(self, other) } + cmath::fdimf(self, other) } /// Returns the cube root of a number. @@ -626,7 +626,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn cbrt(self) -> f32 { - unsafe { cmath::cbrtf(self) } + cmath::cbrtf(self) } /// Compute the distance between the origin and a point (`x`, `y`) on the @@ -657,7 +657,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn hypot(self, other: f32) -> f32 { - unsafe { cmath::hypotf(self, other) } + cmath::hypotf(self, other) } /// Computes the sine of a number (in radians). @@ -730,7 +730,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn tan(self) -> f32 { - unsafe { cmath::tanf(self) } + cmath::tanf(self) } /// Computes the arcsine of a number. Return value is in radians in @@ -760,7 +760,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn asin(self) -> f32 { - unsafe { cmath::asinf(self) } + cmath::asinf(self) } /// Computes the arccosine of a number. Return value is in radians in @@ -790,7 +790,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn acos(self) -> f32 { - unsafe { cmath::acosf(self) } + cmath::acosf(self) } /// Computes the arctangent of a number. Return value is in radians in the @@ -819,7 +819,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn atan(self) -> f32 { - unsafe { cmath::atanf(self) } + cmath::atanf(self) } /// Computes the four quadrant arctangent of `self` (`y`) and `other` (`x`) in radians. @@ -860,7 +860,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn atan2(self, other: f32) -> f32 { - unsafe { cmath::atan2f(self, other) } + cmath::atan2f(self, other) } /// Simultaneously computes the sine and cosine of the number, `x`. Returns @@ -919,7 +919,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn exp_m1(self) -> f32 { - unsafe { cmath::expm1f(self) } + cmath::expm1f(self) } /// Returns `ln(1+n)` (natural logarithm) more accurately than if @@ -957,7 +957,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn ln_1p(self) -> f32 { - unsafe { cmath::log1pf(self) } + cmath::log1pf(self) } /// Hyperbolic sine function. @@ -987,7 +987,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn sinh(self) -> f32 { - unsafe { cmath::sinhf(self) } + cmath::sinhf(self) } /// Hyperbolic cosine function. @@ -1017,7 +1017,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn cosh(self) -> f32 { - unsafe { cmath::coshf(self) } + cmath::coshf(self) } /// Hyperbolic tangent function. @@ -1047,7 +1047,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn tanh(self) -> f32 { - unsafe { cmath::tanhf(self) } + cmath::tanhf(self) } /// Inverse hyperbolic sine function. @@ -1158,7 +1158,7 @@ impl f32 { #[unstable(feature = "float_gamma", issue = "99842")] #[inline] pub fn gamma(self) -> f32 { - unsafe { cmath::tgammaf(self) } + cmath::tgammaf(self) } /// Natural logarithm of the absolute value of the gamma function @@ -1188,7 +1188,7 @@ impl f32 { #[inline] pub fn ln_gamma(self) -> (f32, i32) { let mut signgamp: i32 = 0; - let x = unsafe { cmath::lgammaf_r(self, &mut signgamp) }; + let x = cmath::lgammaf_r(self, &mut signgamp); (x, signgamp) } @@ -1224,7 +1224,7 @@ impl f32 { #[unstable(feature = "float_erf", issue = "136321")] #[inline] pub fn erf(self) -> f32 { - unsafe { cmath::erff(self) } + cmath::erff(self) } /// Complementary error function. @@ -1253,6 +1253,6 @@ impl f32 { #[unstable(feature = "float_erf", issue = "136321")] #[inline] pub fn erfc(self) -> f32 { - unsafe { cmath::erfcf(self) } + cmath::erfcf(self) } } diff --git a/library/std/src/f64.rs b/library/std/src/f64.rs index 2aaab3ffc835..84fd9bfb7b68 100644 --- a/library/std/src/f64.rs +++ b/library/std/src/f64.rs @@ -599,7 +599,7 @@ impl f64 { filing an issue describing your use-case too)." )] pub fn abs_sub(self, other: f64) -> f64 { - unsafe { cmath::fdim(self, other) } + cmath::fdim(self, other) } /// Returns the cube root of a number. @@ -626,7 +626,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn cbrt(self) -> f64 { - unsafe { cmath::cbrt(self) } + cmath::cbrt(self) } /// Compute the distance between the origin and a point (`x`, `y`) on the @@ -657,7 +657,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn hypot(self, other: f64) -> f64 { - unsafe { cmath::hypot(self, other) } + cmath::hypot(self, other) } /// Computes the sine of a number (in radians). @@ -730,7 +730,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn tan(self) -> f64 { - unsafe { cmath::tan(self) } + cmath::tan(self) } /// Computes the arcsine of a number. Return value is in radians in @@ -760,7 +760,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn asin(self) -> f64 { - unsafe { cmath::asin(self) } + cmath::asin(self) } /// Computes the arccosine of a number. Return value is in radians in @@ -790,7 +790,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn acos(self) -> f64 { - unsafe { cmath::acos(self) } + cmath::acos(self) } /// Computes the arctangent of a number. Return value is in radians in the @@ -819,7 +819,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn atan(self) -> f64 { - unsafe { cmath::atan(self) } + cmath::atan(self) } /// Computes the four quadrant arctangent of `self` (`y`) and `other` (`x`) in radians. @@ -860,7 +860,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn atan2(self, other: f64) -> f64 { - unsafe { cmath::atan2(self, other) } + cmath::atan2(self, other) } /// Simultaneously computes the sine and cosine of the number, `x`. Returns @@ -919,7 +919,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn exp_m1(self) -> f64 { - unsafe { cmath::expm1(self) } + cmath::expm1(self) } /// Returns `ln(1+n)` (natural logarithm) more accurately than if @@ -957,7 +957,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn ln_1p(self) -> f64 { - unsafe { cmath::log1p(self) } + cmath::log1p(self) } /// Hyperbolic sine function. @@ -987,7 +987,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn sinh(self) -> f64 { - unsafe { cmath::sinh(self) } + cmath::sinh(self) } /// Hyperbolic cosine function. @@ -1017,7 +1017,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn cosh(self) -> f64 { - unsafe { cmath::cosh(self) } + cmath::cosh(self) } /// Hyperbolic tangent function. @@ -1047,7 +1047,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn tanh(self) -> f64 { - unsafe { cmath::tanh(self) } + cmath::tanh(self) } /// Inverse hyperbolic sine function. @@ -1158,7 +1158,7 @@ impl f64 { #[unstable(feature = "float_gamma", issue = "99842")] #[inline] pub fn gamma(self) -> f64 { - unsafe { cmath::tgamma(self) } + cmath::tgamma(self) } /// Natural logarithm of the absolute value of the gamma function @@ -1188,7 +1188,7 @@ impl f64 { #[inline] pub fn ln_gamma(self) -> (f64, i32) { let mut signgamp: i32 = 0; - let x = unsafe { cmath::lgamma_r(self, &mut signgamp) }; + let x = cmath::lgamma_r(self, &mut signgamp); (x, signgamp) } @@ -1224,7 +1224,7 @@ impl f64 { #[unstable(feature = "float_erf", issue = "136321")] #[inline] pub fn erf(self) -> f64 { - unsafe { cmath::erf(self) } + cmath::erf(self) } /// Complementary error function. @@ -1253,6 +1253,6 @@ impl f64 { #[unstable(feature = "float_erf", issue = "136321")] #[inline] pub fn erfc(self) -> f64 { - unsafe { cmath::erfc(self) } + cmath::erfc(self) } } diff --git a/library/std/src/ffi/mod.rs b/library/std/src/ffi/mod.rs index 860ec3a6be16..d34e3ca00b9f 100644 --- a/library/std/src/ffi/mod.rs +++ b/library/std/src/ffi/mod.rs @@ -201,5 +201,5 @@ pub use self::c_str::{CStr, CString}; #[doc(inline)] pub use self::os_str::{OsStr, OsString}; -#[stable(feature = "os_str_display", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "os_str_display", since = "1.87.0")] pub mod os_str; diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index aa25ff5293c7..ce01175309a7 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -1255,7 +1255,7 @@ impl OsStr { /// let s = OsStr::new("Hello, world!"); /// println!("{}", s.display()); /// ``` - #[stable(feature = "os_str_display", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "os_str_display", since = "1.87.0")] #[must_use = "this does not display the `OsStr`; \ it returns an object that can be displayed"] #[inline] @@ -1612,19 +1612,19 @@ impl fmt::Debug for OsStr { /// /// [`Display`]: fmt::Display /// [`format!`]: crate::format -#[stable(feature = "os_str_display", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "os_str_display", since = "1.87.0")] pub struct Display<'a> { os_str: &'a OsStr, } -#[stable(feature = "os_str_display", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "os_str_display", since = "1.87.0")] impl fmt::Debug for Display<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(&self.os_str, f) } } -#[stable(feature = "os_str_display", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "os_str_display", since = "1.87.0")] impl fmt::Display for Display<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Display::fmt(&self.os_str.inner, f) diff --git a/library/std/src/io/error.rs b/library/std/src/io/error.rs index 8472f9030500..cf3778bd2907 100644 --- a/library/std/src/io/error.rs +++ b/library/std/src/io/error.rs @@ -48,6 +48,7 @@ use crate::{error, fmt, result, sys}; /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(bootstrap), doc(search_unbox))] pub type Result = result::Result; /// The error type for I/O operations of the [`Read`], [`Write`], [`Seek`], and @@ -374,7 +375,7 @@ pub enum ErrorKind { /// A filename was invalid. /// /// This error can also occur if a length limit for a name was exceeded. - #[stable(feature = "io_error_invalid_filename", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "io_error_invalid_filename", since = "1.87.0")] InvalidFilename, /// Program argument list too long. /// diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 314cbb45d49e..5242261cf93f 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -310,7 +310,7 @@ pub use self::error::RawOsError; pub use self::error::SimpleMessage; #[unstable(feature = "io_const_error", issue = "133448")] pub use self::error::const_error; -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "anonymous_pipe", since = "1.87.0")] pub use self::pipe::{PipeReader, PipeWriter, pipe}; #[stable(feature = "is_terminal", since = "1.70.0")] pub use self::stdio::IsTerminal; @@ -2658,6 +2658,10 @@ impl Chain { /// Gets references to the underlying readers in this `Chain`. /// + /// Care should be taken to avoid modifying the internal I/O state of the + /// underlying readers as doing so may corrupt the internal state of this + /// `Chain`. + /// /// # Examples /// /// ```no_run @@ -2915,6 +2919,10 @@ impl Take { /// Gets a reference to the underlying reader. /// + /// Care should be taken to avoid modifying the internal I/O state of the + /// underlying reader as doing so may corrupt the internal limit of this + /// `Take`. + /// /// # Examples /// /// ```no_run diff --git a/library/std/src/io/pipe.rs b/library/std/src/io/pipe.rs index cfed9b05cc0c..c6b7b49a351e 100644 --- a/library/std/src/io/pipe.rs +++ b/library/std/src/io/pipe.rs @@ -67,19 +67,19 @@ use crate::sys_common::{FromInner, IntoInner}; /// ``` /// [changes]: io#platform-specific-behavior /// [man page]: https://man7.org/linux/man-pages/man7/pipe.7.html -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "anonymous_pipe", since = "1.87.0")] #[inline] pub fn pipe() -> io::Result<(PipeReader, PipeWriter)> { pipe_inner().map(|(reader, writer)| (PipeReader(reader), PipeWriter(writer))) } /// Read end of an anonymous pipe. -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "anonymous_pipe", since = "1.87.0")] #[derive(Debug)] pub struct PipeReader(pub(crate) AnonPipe); /// Write end of an anonymous pipe. -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "anonymous_pipe", since = "1.87.0")] #[derive(Debug)] pub struct PipeWriter(pub(crate) AnonPipe); @@ -160,7 +160,7 @@ impl PipeReader { /// # Ok(()) /// # } /// ``` - #[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "anonymous_pipe", since = "1.87.0")] pub fn try_clone(&self) -> io::Result { self.0.try_clone().map(Self) } @@ -199,13 +199,13 @@ impl PipeWriter { /// # Ok(()) /// # } /// ``` - #[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "anonymous_pipe", since = "1.87.0")] pub fn try_clone(&self) -> io::Result { self.0.try_clone().map(Self) } } -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "anonymous_pipe", since = "1.87.0")] impl io::Read for &PipeReader { fn read(&mut self, buf: &mut [u8]) -> io::Result { self.0.read(buf) @@ -225,7 +225,7 @@ impl io::Read for &PipeReader { } } -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "anonymous_pipe", since = "1.87.0")] impl io::Read for PipeReader { fn read(&mut self, buf: &mut [u8]) -> io::Result { self.0.read(buf) @@ -245,7 +245,7 @@ impl io::Read for PipeReader { } } -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "anonymous_pipe", since = "1.87.0")] impl io::Write for &PipeWriter { fn write(&mut self, buf: &[u8]) -> io::Result { self.0.write(buf) @@ -263,7 +263,7 @@ impl io::Write for &PipeWriter { } } -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "anonymous_pipe", since = "1.87.0")] impl io::Write for PipeWriter { fn write(&mut self, buf: &[u8]) -> io::Result { self.0.write(buf) diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 5c381181218d..3a52b7790376 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -312,7 +312,6 @@ #![feature(needs_panic_runtime)] #![feature(negative_impls)] #![feature(never_type)] -#![feature(no_sanitize)] #![feature(optimize_attribute)] #![feature(prelude_import)] #![feature(rustc_attrs)] diff --git a/library/std/src/os/fd/owned.rs b/library/std/src/os/fd/owned.rs index be73e7dee9c7..10e1e73a115b 100644 --- a/library/std/src/os/fd/owned.rs +++ b/library/std/src/os/fd/owned.rs @@ -505,7 +505,7 @@ impl<'a> AsFd for io::StderrLock<'a> { } } -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "anonymous_pipe", since = "1.87.0")] #[cfg(not(target_os = "trusty"))] impl AsFd for io::PipeReader { fn as_fd(&self) -> BorrowedFd<'_> { @@ -513,7 +513,7 @@ impl AsFd for io::PipeReader { } } -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "anonymous_pipe", since = "1.87.0")] #[cfg(not(target_os = "trusty"))] impl From for OwnedFd { fn from(pipe: io::PipeReader) -> Self { @@ -521,7 +521,7 @@ impl From for OwnedFd { } } -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "anonymous_pipe", since = "1.87.0")] #[cfg(not(target_os = "trusty"))] impl AsFd for io::PipeWriter { fn as_fd(&self) -> BorrowedFd<'_> { @@ -529,7 +529,7 @@ impl AsFd for io::PipeWriter { } } -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "anonymous_pipe", since = "1.87.0")] #[cfg(not(target_os = "trusty"))] impl From for OwnedFd { fn from(pipe: io::PipeWriter) -> Self { @@ -537,7 +537,7 @@ impl From for OwnedFd { } } -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "anonymous_pipe", since = "1.87.0")] #[cfg(not(target_os = "trusty"))] impl From for io::PipeReader { fn from(owned_fd: OwnedFd) -> Self { @@ -545,7 +545,7 @@ impl From for io::PipeReader { } } -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "anonymous_pipe", since = "1.87.0")] #[cfg(not(target_os = "trusty"))] impl From for io::PipeWriter { fn from(owned_fd: OwnedFd) -> Self { diff --git a/library/std/src/os/fd/raw.rs b/library/std/src/os/fd/raw.rs index c800c1489ad2..34a6cf1a8b84 100644 --- a/library/std/src/os/fd/raw.rs +++ b/library/std/src/os/fd/raw.rs @@ -285,7 +285,7 @@ impl AsRawFd for Box { } } -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "anonymous_pipe", since = "1.87.0")] #[cfg(not(target_os = "trusty"))] impl AsRawFd for io::PipeReader { fn as_raw_fd(&self) -> RawFd { @@ -293,7 +293,7 @@ impl AsRawFd for io::PipeReader { } } -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "anonymous_pipe", since = "1.87.0")] #[cfg(not(target_os = "trusty"))] impl FromRawFd for io::PipeReader { unsafe fn from_raw_fd(raw_fd: RawFd) -> Self { @@ -301,7 +301,7 @@ impl FromRawFd for io::PipeReader { } } -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "anonymous_pipe", since = "1.87.0")] #[cfg(not(target_os = "trusty"))] impl IntoRawFd for io::PipeReader { fn into_raw_fd(self) -> RawFd { @@ -309,7 +309,7 @@ impl IntoRawFd for io::PipeReader { } } -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "anonymous_pipe", since = "1.87.0")] #[cfg(not(target_os = "trusty"))] impl AsRawFd for io::PipeWriter { fn as_raw_fd(&self) -> RawFd { @@ -317,7 +317,7 @@ impl AsRawFd for io::PipeWriter { } } -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "anonymous_pipe", since = "1.87.0")] #[cfg(not(target_os = "trusty"))] impl FromRawFd for io::PipeWriter { unsafe fn from_raw_fd(raw_fd: RawFd) -> Self { @@ -325,7 +325,7 @@ impl FromRawFd for io::PipeWriter { } } -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "anonymous_pipe", since = "1.87.0")] #[cfg(not(target_os = "trusty"))] impl IntoRawFd for io::PipeWriter { fn into_raw_fd(self) -> RawFd { diff --git a/library/std/src/os/windows/io/handle.rs b/library/std/src/os/windows/io/handle.rs index 7f21929b85f9..4fc04b79315f 100644 --- a/library/std/src/os/windows/io/handle.rs +++ b/library/std/src/os/windows/io/handle.rs @@ -661,42 +661,42 @@ impl From> for OwnedHandle { } } -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "anonymous_pipe", since = "1.87.0")] impl AsHandle for io::PipeReader { fn as_handle(&self) -> BorrowedHandle<'_> { self.0.as_handle() } } -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "anonymous_pipe", since = "1.87.0")] impl From for OwnedHandle { fn from(pipe: io::PipeReader) -> Self { pipe.into_inner().into_inner() } } -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "anonymous_pipe", since = "1.87.0")] impl AsHandle for io::PipeWriter { fn as_handle(&self) -> BorrowedHandle<'_> { self.0.as_handle() } } -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "anonymous_pipe", since = "1.87.0")] impl From for OwnedHandle { fn from(pipe: io::PipeWriter) -> Self { pipe.into_inner().into_inner() } } -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "anonymous_pipe", since = "1.87.0")] impl From for io::PipeReader { fn from(owned_handle: OwnedHandle) -> Self { Self::from_inner(FromInner::from_inner(owned_handle)) } } -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "anonymous_pipe", since = "1.87.0")] impl From for io::PipeWriter { fn from(owned_handle: OwnedHandle) -> Self { Self::from_inner(FromInner::from_inner(owned_handle)) diff --git a/library/std/src/os/windows/io/raw.rs b/library/std/src/os/windows/io/raw.rs index bc3e55c86296..a3ec7440338d 100644 --- a/library/std/src/os/windows/io/raw.rs +++ b/library/std/src/os/windows/io/raw.rs @@ -311,42 +311,42 @@ impl IntoRawSocket for net::UdpSocket { } } -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "anonymous_pipe", since = "1.87.0")] impl AsRawHandle for io::PipeReader { fn as_raw_handle(&self) -> RawHandle { self.0.as_raw_handle() } } -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "anonymous_pipe", since = "1.87.0")] impl FromRawHandle for io::PipeReader { unsafe fn from_raw_handle(raw_handle: RawHandle) -> Self { unsafe { Self::from_inner(FromRawHandle::from_raw_handle(raw_handle)) } } } -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "anonymous_pipe", since = "1.87.0")] impl IntoRawHandle for io::PipeReader { fn into_raw_handle(self) -> RawHandle { self.0.into_raw_handle() } } -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "anonymous_pipe", since = "1.87.0")] impl AsRawHandle for io::PipeWriter { fn as_raw_handle(&self) -> RawHandle { self.0.as_raw_handle() } } -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "anonymous_pipe", since = "1.87.0")] impl FromRawHandle for io::PipeWriter { unsafe fn from_raw_handle(raw_handle: RawHandle) -> Self { unsafe { Self::from_inner(FromRawHandle::from_raw_handle(raw_handle)) } } } -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "anonymous_pipe", since = "1.87.0")] impl IntoRawHandle for io::PipeWriter { fn into_raw_handle(self) -> RawHandle { self.0.into_raw_handle() diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs index b35549c92ada..a3950980b5e3 100644 --- a/library/std/src/panicking.rs +++ b/library/std/src/panicking.rs @@ -55,14 +55,14 @@ pub static EMPTY_PANIC: fn(&'static str) -> ! = // hook up these functions, but it is not this day! #[allow(improper_ctypes)] unsafe extern "C" { - #[cfg_attr(not(bootstrap), rustc_std_internal_symbol)] + #[rustc_std_internal_symbol] fn __rust_panic_cleanup(payload: *mut u8) -> *mut (dyn Any + Send + 'static); } unsafe extern "Rust" { /// `PanicPayload` lazily performs allocation only when needed (this avoids /// allocations when using the "abort" panic runtime). - #[cfg_attr(not(bootstrap), rustc_std_internal_symbol)] + #[rustc_std_internal_symbol] fn __rust_start_panic(payload: &mut dyn PanicPayload) -> u32; } diff --git a/library/std/src/prelude/v1.rs b/library/std/src/prelude/v1.rs index 4217f6586407..c15d8c40085a 100644 --- a/library/std/src/prelude/v1.rs +++ b/library/std/src/prelude/v1.rs @@ -109,7 +109,6 @@ pub use core::prelude::v1::deref; issue = "63063", reason = "`type_alias_impl_trait` has open design concerns" )] -#[cfg(not(bootstrap))] pub use core::prelude::v1::define_opaque; // The file so far is equivalent to core/src/prelude/v1.rs. It is duplicated diff --git a/library/std/src/process.rs b/library/std/src/process.rs index 3b765a9537bc..76ce7bce81b1 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -1286,6 +1286,40 @@ pub struct Output { pub stderr: Vec, } +impl Output { + /// Returns an error if a nonzero exit status was received. + /// + /// If the [`Command`] exited successfully, + /// `self` is returned. + /// + /// This is equivalent to calling [`exit_ok`](ExitStatus::exit_ok) + /// on [`Output.status`](Output::status). + /// + /// Note that this will throw away the [`Output::stderr`] field in the error case. + /// If the child process outputs useful informantion to stderr, you can: + /// * Use `cmd.stderr(Stdio::inherit())` to forward the + /// stderr child process to the parent's stderr, + /// usually printing it to console where the user can see it. + /// This is usually correct for command-line applications. + /// * Capture `stderr` using a custom error type. + /// This is usually correct for libraries. + /// + /// # Examples + /// + /// ``` + /// #![feature(exit_status_error)] + /// # #[cfg(unix)] { + /// use std::process::Command; + /// assert!(Command::new("false").output().unwrap().exit_ok().is_err()); + /// # } + /// ``` + #[unstable(feature = "exit_status_error", issue = "84908")] + pub fn exit_ok(self) -> Result { + self.status.exit_ok()?; + Ok(self) + } +} + // If either stderr or stdout are valid utf8 strings it prints the valid // strings, otherwise it prints the byte sequence instead #[stable(feature = "process_output_debug", since = "1.7.0")] @@ -1659,14 +1693,14 @@ impl From for Stdio { } } -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "anonymous_pipe", since = "1.87.0")] impl From for Stdio { fn from(pipe: io::PipeWriter) -> Self { Stdio::from_inner(pipe.into_inner().into()) } } -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "anonymous_pipe", since = "1.87.0")] impl From for Stdio { fn from(pipe: io::PipeReader) -> Self { Stdio::from_inner(pipe.into_inner().into()) diff --git a/library/std/src/sync/mpmc/list.rs b/library/std/src/sync/mpmc/list.rs index d88914f52914..1c6acb29e375 100644 --- a/library/std/src/sync/mpmc/list.rs +++ b/library/std/src/sync/mpmc/list.rs @@ -213,6 +213,11 @@ impl Channel { .compare_exchange(block, new, Ordering::Release, Ordering::Relaxed) .is_ok() { + // This yield point leaves the channel in a half-initialized state where the + // tail.block pointer is set but the head.block is not. This is used to + // facilitate the test in src/tools/miri/tests/pass/issues/issue-139553.rs + #[cfg(miri)] + crate::thread::yield_now(); self.head.block.store(new, Ordering::Release); block = new; } else { @@ -564,9 +569,15 @@ impl Channel { // In that case, just wait until it gets initialized. while block.is_null() { backoff.spin_heavy(); - block = self.head.block.load(Ordering::Acquire); + block = self.head.block.swap(ptr::null_mut(), Ordering::AcqRel); } } + // After this point `head.block` is not modified again and it will be deallocated if it's + // non-null. The `Drop` code of the channel, which runs after this function, also attempts + // to deallocate `head.block` if it's non-null. Therefore this function must maintain the + // invariant that if a deallocation of head.block is attemped then it must also be set to + // NULL. Failing to do so will lead to the Drop code attempting a double free. For this + // reason both reads above do an atomic swap instead of a simple atomic load. unsafe { // Drop all messages between head and tail and deallocate the heap-allocated blocks. diff --git a/library/std/src/sync/poison/mutex.rs b/library/std/src/sync/poison/mutex.rs index 9362c764173a..adb74bb6f3de 100644 --- a/library/std/src/sync/poison/mutex.rs +++ b/library/std/src/sync/poison/mutex.rs @@ -582,7 +582,9 @@ impl Mutex { /// Returns a mutable reference to the underlying data. /// /// Since this call borrows the `Mutex` mutably, no actual locking needs to - /// take place -- the mutable borrow statically guarantees no locks exist. + /// take place -- the mutable borrow statically guarantees no new locks can be acquired + /// while this reference exists. Note that this method does not clear any previous abandoned locks + /// (e.g., via [`forget()`] on a [`MutexGuard`]). /// /// # Errors /// @@ -599,6 +601,8 @@ impl Mutex { /// *mutex.get_mut().unwrap() = 10; /// assert_eq!(*mutex.lock().unwrap(), 10); /// ``` + /// + /// [`forget()`]: mem::forget #[stable(feature = "mutex_get_mut", since = "1.6.0")] pub fn get_mut(&mut self) -> LockResult<&mut T> { let data = self.data.get_mut(); diff --git a/library/std/src/sync/poison/rwlock.rs b/library/std/src/sync/poison/rwlock.rs index f9d9321f5f2d..a2abd4f692ec 100644 --- a/library/std/src/sync/poison/rwlock.rs +++ b/library/std/src/sync/poison/rwlock.rs @@ -608,7 +608,9 @@ impl RwLock { /// Returns a mutable reference to the underlying data. /// /// Since this call borrows the `RwLock` mutably, no actual locking needs to - /// take place -- the mutable borrow statically guarantees no locks exist. + /// take place -- the mutable borrow statically guarantees no new locks can be acquired + /// while this reference exists. Note that this method does not clear any previously abandoned locks + /// (e.g., via [`forget()`] on a [`RwLockReadGuard`] or [`RwLockWriteGuard`]). /// /// # Errors /// diff --git a/library/std/src/sys/args/common.rs b/library/std/src/sys/args/common.rs new file mode 100644 index 000000000000..43ac5e959234 --- /dev/null +++ b/library/std/src/sys/args/common.rs @@ -0,0 +1,43 @@ +use crate::ffi::OsString; +use crate::{fmt, vec}; + +pub struct Args { + iter: vec::IntoIter, +} + +impl !Send for Args {} +impl !Sync for Args {} + +impl Args { + pub(super) fn new(args: Vec) -> Self { + Args { iter: args.into_iter() } + } +} + +impl fmt::Debug for Args { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.iter.as_slice().fmt(f) + } +} + +impl Iterator for Args { + type Item = OsString; + fn next(&mut self) -> Option { + self.iter.next() + } + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} + +impl ExactSizeIterator for Args { + fn len(&self) -> usize { + self.iter.len() + } +} + +impl DoubleEndedIterator for Args { + fn next_back(&mut self) -> Option { + self.iter.next_back() + } +} diff --git a/library/std/src/sys/pal/hermit/args.rs b/library/std/src/sys/args/hermit.rs similarity index 59% rename from library/std/src/sys/pal/hermit/args.rs rename to library/std/src/sys/args/hermit.rs index 440242602773..ddd644a55404 100644 --- a/library/std/src/sys/pal/hermit/args.rs +++ b/library/std/src/sys/args/hermit.rs @@ -1,8 +1,12 @@ use crate::ffi::{CStr, OsString, c_char}; use crate::os::hermit::ffi::OsStringExt; +use crate::ptr; use crate::sync::atomic::Ordering::{Acquire, Relaxed, Release}; use crate::sync::atomic::{AtomicIsize, AtomicPtr}; -use crate::{fmt, ptr, vec}; + +#[path = "common.rs"] +mod common; +pub use common::Args; static ARGC: AtomicIsize = AtomicIsize::new(0); static ARGV: AtomicPtr<*const u8> = AtomicPtr::new(ptr::null_mut()); @@ -27,40 +31,5 @@ pub fn args() -> Args { }) .collect(); - Args { iter: args.into_iter() } -} - -pub struct Args { - iter: vec::IntoIter, -} - -impl fmt::Debug for Args { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.iter.as_slice().fmt(f) - } -} - -impl !Send for Args {} -impl !Sync for Args {} - -impl Iterator for Args { - type Item = OsString; - fn next(&mut self) -> Option { - self.iter.next() - } - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } -} - -impl ExactSizeIterator for Args { - fn len(&self) -> usize { - self.iter.len() - } -} - -impl DoubleEndedIterator for Args { - fn next_back(&mut self) -> Option { - self.iter.next_back() - } + Args::new(args) } diff --git a/library/std/src/sys/args/mod.rs b/library/std/src/sys/args/mod.rs new file mode 100644 index 000000000000..f24d6eb123e0 --- /dev/null +++ b/library/std/src/sys/args/mod.rs @@ -0,0 +1,34 @@ +//! Platform-dependent command line arguments abstraction. + +#![forbid(unsafe_op_in_unsafe_fn)] + +cfg_if::cfg_if! { + if #[cfg(all(target_family = "unix", not(any(target_os = "espidf", target_os = "vita"))))] { + mod unix; + pub use unix::*; + } else if #[cfg(target_family = "windows")] { + mod windows; + pub use windows::*; + } else if #[cfg(target_os = "hermit")] { + mod hermit; + pub use hermit::*; + } else if #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] { + mod sgx; + pub use sgx::*; + } else if #[cfg(target_os = "uefi")] { + mod uefi; + pub use uefi::*; + } else if #[cfg(target_os = "wasi")] { + mod wasi; + pub use wasi::*; + } else if #[cfg(target_os = "xous")] { + mod xous; + pub use xous::*; + } else if #[cfg(target_os = "zkvm")] { + mod zkvm; + pub use zkvm::*; + } else { + mod unsupported; + pub use unsupported::*; + } +} diff --git a/library/std/src/sys/pal/sgx/args.rs b/library/std/src/sys/args/sgx.rs similarity index 89% rename from library/std/src/sys/pal/sgx/args.rs rename to library/std/src/sys/args/sgx.rs index e62bf383954e..efc4b7918522 100644 --- a/library/std/src/sys/pal/sgx/args.rs +++ b/library/std/src/sys/args/sgx.rs @@ -1,8 +1,10 @@ -use super::abi::usercalls::alloc; -use super::abi::usercalls::raw::ByteBuffer; +#![allow(fuzzy_provenance_casts)] // FIXME: this module systematically confuses pointers and integers + use crate::ffi::OsString; use crate::sync::atomic::{AtomicUsize, Ordering}; use crate::sys::os_str::Buf; +use crate::sys::pal::abi::usercalls::alloc; +use crate::sys::pal::abi::usercalls::raw::ByteBuffer; use crate::sys_common::FromInner; use crate::{fmt, slice}; diff --git a/library/std/src/sys/pal/uefi/args.rs b/library/std/src/sys/args/uefi.rs similarity index 79% rename from library/std/src/sys/pal/uefi/args.rs rename to library/std/src/sys/args/uefi.rs index 0c29caf2db67..84406c7f69df 100644 --- a/library/std/src/sys/pal/uefi/args.rs +++ b/library/std/src/sys/args/uefi.rs @@ -1,14 +1,13 @@ use r_efi::protocols::loaded_image; -use super::helpers; use crate::env::current_exe; use crate::ffi::OsString; use crate::iter::Iterator; -use crate::{fmt, vec}; +use crate::sys::pal::helpers; -pub struct Args { - parsed_args_list: vec::IntoIter, -} +#[path = "common.rs"] +mod common; +pub use common::Args; pub fn args() -> Args { let lazy_current_exe = || Vec::from([current_exe().map(Into::into).unwrap_or_default()]); @@ -22,51 +21,17 @@ pub fn args() -> Args { let lp_size = unsafe { (*protocol.as_ptr()).load_options_size } as usize; // Break if we are sure that it cannot be UTF-16 if lp_size < size_of::() || lp_size % size_of::() != 0 { - return Args { parsed_args_list: lazy_current_exe().into_iter() }; + return Args::new(lazy_current_exe()); } let lp_size = lp_size / size_of::(); let lp_cmd_line = unsafe { (*protocol.as_ptr()).load_options as *const u16 }; if !lp_cmd_line.is_aligned() { - return Args { parsed_args_list: lazy_current_exe().into_iter() }; + return Args::new(lazy_current_exe()); } let lp_cmd_line = unsafe { crate::slice::from_raw_parts(lp_cmd_line, lp_size) }; - Args { - parsed_args_list: parse_lp_cmd_line(lp_cmd_line) - .unwrap_or_else(lazy_current_exe) - .into_iter(), - } -} - -impl fmt::Debug for Args { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.parsed_args_list.as_slice().fmt(f) - } -} - -impl Iterator for Args { - type Item = OsString; - - fn next(&mut self) -> Option { - self.parsed_args_list.next() - } - - fn size_hint(&self) -> (usize, Option) { - self.parsed_args_list.size_hint() - } -} - -impl ExactSizeIterator for Args { - fn len(&self) -> usize { - self.parsed_args_list.len() - } -} - -impl DoubleEndedIterator for Args { - fn next_back(&mut self) -> Option { - self.parsed_args_list.next_back() - } + Args::new(parse_lp_cmd_line(lp_cmd_line).unwrap_or_else(lazy_current_exe)) } /// Implements the UEFI command-line argument parsing algorithm. diff --git a/library/std/src/sys/pal/unix/args.rs b/library/std/src/sys/args/unix.rs similarity index 85% rename from library/std/src/sys/pal/unix/args.rs rename to library/std/src/sys/args/unix.rs index 0bb7b64007ab..7d7815c6dff2 100644 --- a/library/std/src/sys/pal/unix/args.rs +++ b/library/std/src/sys/args/unix.rs @@ -5,13 +5,16 @@ #![allow(dead_code)] // runtime init functions not used during testing -use crate::ffi::{CStr, OsString}; +use crate::ffi::CStr; use crate::os::unix::ffi::OsStringExt; -use crate::{fmt, vec}; + +#[path = "common.rs"] +mod common; +pub use common::Args; /// One-time global initialization. pub unsafe fn init(argc: isize, argv: *const *const u8) { - imp::init(argc, argv) + unsafe { imp::init(argc, argv) } } /// Returns the command line arguments @@ -55,42 +58,7 @@ pub fn args() -> Args { vec.push(OsStringExt::from_vec(cstr.to_bytes().to_vec())); } - Args { iter: vec.into_iter() } -} - -pub struct Args { - iter: vec::IntoIter, -} - -impl !Send for Args {} -impl !Sync for Args {} - -impl fmt::Debug for Args { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.iter.as_slice().fmt(f) - } -} - -impl Iterator for Args { - type Item = OsString; - fn next(&mut self) -> Option { - self.iter.next() - } - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } -} - -impl ExactSizeIterator for Args { - fn len(&self) -> usize { - self.iter.len() - } -} - -impl DoubleEndedIterator for Args { - fn next_back(&mut self) -> Option { - self.iter.next_back() - } + Args::new(vec) } #[cfg(any( @@ -141,7 +109,7 @@ mod imp { pub unsafe fn init(argc: isize, argv: *const *const u8) { // on GNU/Linux if we are main then we will init argv and argc twice, it "duplicates work" // BUT edge-cases are real: only using .init_array can break most emulators, dlopen, etc. - really_init(argc, argv); + unsafe { really_init(argc, argv) }; } /// glibc passes argc, argv, and envp to functions in .init_array, as a non-standard extension. @@ -159,9 +127,7 @@ mod imp { argv: *const *const u8, _envp: *const *const u8, ) { - unsafe { - really_init(argc as isize, argv); - } + unsafe { really_init(argc as isize, argv) }; } init_wrapper }; @@ -228,16 +194,3 @@ mod imp { (argc as isize, argv.cast()) } } - -#[cfg(any(target_os = "espidf", target_os = "vita"))] -mod imp { - use crate::ffi::c_char; - use crate::ptr; - - #[inline(always)] - pub unsafe fn init(_argc: isize, _argv: *const *const u8) {} - - pub fn argc_argv() -> (isize, *const *const c_char) { - (0, ptr::null()) - } -} diff --git a/library/std/src/sys/pal/unsupported/args.rs b/library/std/src/sys/args/unsupported.rs similarity index 100% rename from library/std/src/sys/pal/unsupported/args.rs rename to library/std/src/sys/args/unsupported.rs diff --git a/library/std/src/sys/args/wasi.rs b/library/std/src/sys/args/wasi.rs new file mode 100644 index 000000000000..4795789e4c71 --- /dev/null +++ b/library/std/src/sys/args/wasi.rs @@ -0,0 +1,29 @@ +#![forbid(unsafe_op_in_unsafe_fn)] + +use crate::ffi::{CStr, OsStr, OsString}; +use crate::os::wasi::ffi::OsStrExt; + +#[path = "common.rs"] +mod common; +pub use common::Args; + +/// Returns the command line arguments +pub fn args() -> Args { + Args::new(maybe_args().unwrap_or(Vec::new())) +} + +fn maybe_args() -> Option> { + unsafe { + let (argc, buf_size) = wasi::args_sizes_get().ok()?; + let mut argv = Vec::with_capacity(argc); + let mut buf = Vec::with_capacity(buf_size); + wasi::args_get(argv.as_mut_ptr(), buf.as_mut_ptr()).ok()?; + argv.set_len(argc); + let mut ret = Vec::with_capacity(argc); + for ptr in argv { + let s = CStr::from_ptr(ptr.cast()); + ret.push(OsStr::from_bytes(s.to_bytes()).to_owned()); + } + Some(ret) + } +} diff --git a/library/std/src/sys/pal/windows/args.rs b/library/std/src/sys/args/windows.rs similarity index 94% rename from library/std/src/sys/pal/windows/args.rs rename to library/std/src/sys/args/windows.rs index d973743639ab..47f0e5f2d05f 100644 --- a/library/std/src/sys/pal/windows/args.rs +++ b/library/std/src/sys/args/windows.rs @@ -6,17 +6,21 @@ #[cfg(test)] mod tests; -use super::ensure_no_nuls; -use super::os::current_exe; use crate::ffi::{OsStr, OsString}; use crate::num::NonZero; use crate::os::windows::prelude::*; use crate::path::{Path, PathBuf}; +use crate::sys::pal::os::current_exe; +use crate::sys::pal::{ensure_no_nuls, fill_utf16_buf}; use crate::sys::path::get_long_path; use crate::sys::{c, to_u16s}; use crate::sys_common::AsInner; use crate::sys_common::wstr::WStrUnits; -use crate::{fmt, io, iter, vec}; +use crate::{io, iter, ptr}; + +#[path = "common.rs"] +mod common; +pub use common::Args; pub fn args() -> Args { // SAFETY: `GetCommandLineW` returns a pointer to a null terminated UTF-16 @@ -27,7 +31,7 @@ pub fn args() -> Args { current_exe().map(PathBuf::into_os_string).unwrap_or_else(|_| OsString::new()) }); - Args { parsed_args_list: parsed_args_list.into_iter() } + Args::new(parsed_args_list) } } @@ -153,38 +157,6 @@ fn parse_lp_cmd_line<'a, F: Fn() -> OsString>( ret_val } -pub struct Args { - parsed_args_list: vec::IntoIter, -} - -impl fmt::Debug for Args { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.parsed_args_list.as_slice().fmt(f) - } -} - -impl Iterator for Args { - type Item = OsString; - fn next(&mut self) -> Option { - self.parsed_args_list.next() - } - fn size_hint(&self) -> (usize, Option) { - self.parsed_args_list.size_hint() - } -} - -impl DoubleEndedIterator for Args { - fn next_back(&mut self) -> Option { - self.parsed_args_list.next_back() - } -} - -impl ExactSizeIterator for Args { - fn len(&self) -> usize { - self.parsed_args_list.len() - } -} - #[derive(Debug)] pub(crate) enum Arg { /// Add quotes (if needed) @@ -384,9 +356,6 @@ pub(crate) fn to_user_path(path: &Path) -> io::Result> { from_wide_to_user_path(to_u16s(path)?) } pub(crate) fn from_wide_to_user_path(mut path: Vec) -> io::Result> { - use super::fill_utf16_buf; - use crate::ptr; - // UTF-16 encoded code points, used in parsing and building UTF-16 paths. // All of these are in the ASCII range so they can be cast directly to `u16`. const SEP: u16 = b'\\' as _; diff --git a/library/std/src/sys/pal/windows/args/tests.rs b/library/std/src/sys/args/windows/tests.rs similarity index 100% rename from library/std/src/sys/pal/windows/args/tests.rs rename to library/std/src/sys/args/windows/tests.rs diff --git a/library/std/src/sys/args/xous.rs b/library/std/src/sys/args/xous.rs new file mode 100644 index 000000000000..09a47283d657 --- /dev/null +++ b/library/std/src/sys/args/xous.rs @@ -0,0 +1,23 @@ +use crate::sys::pal::os::get_application_parameters; +use crate::sys::pal::os::params::ArgumentList; + +#[path = "common.rs"] +mod common; +pub use common::Args; + +pub fn args() -> Args { + let Some(params) = get_application_parameters() else { + return Args::new(vec![]); + }; + + for param in params { + if let Ok(args) = ArgumentList::try_from(¶m) { + let mut parsed_args = vec![]; + for arg in args { + parsed_args.push(arg.into()); + } + return Args::new(parsed_args); + } + } + Args::new(vec![]) +} diff --git a/library/std/src/sys/pal/zkvm/args.rs b/library/std/src/sys/args/zkvm.rs similarity index 98% rename from library/std/src/sys/pal/zkvm/args.rs rename to library/std/src/sys/args/zkvm.rs index 47857f6c448b..194ba7159d45 100644 --- a/library/std/src/sys/pal/zkvm/args.rs +++ b/library/std/src/sys/args/zkvm.rs @@ -1,7 +1,7 @@ -use super::{WORD_SIZE, abi}; use crate::ffi::OsString; use crate::fmt; use crate::sys::os_str; +use crate::sys::pal::{WORD_SIZE, abi}; use crate::sys_common::FromInner; pub struct Args { diff --git a/library/std/src/sys/cmath.rs b/library/std/src/sys/cmath.rs index c9969b4e376e..668fd9285340 100644 --- a/library/std/src/sys/cmath.rs +++ b/library/std/src/sys/cmath.rs @@ -3,70 +3,70 @@ // These symbols are all defined by `libm`, // or by `compiler-builtins` on unsupported platforms. unsafe extern "C" { - pub fn acos(n: f64) -> f64; - pub fn asin(n: f64) -> f64; - pub fn atan(n: f64) -> f64; - pub fn atan2(a: f64, b: f64) -> f64; - pub fn cbrt(n: f64) -> f64; - pub fn cbrtf(n: f32) -> f32; - pub fn cosh(n: f64) -> f64; - pub fn expm1(n: f64) -> f64; - pub fn expm1f(n: f32) -> f32; - pub fn fdim(a: f64, b: f64) -> f64; - pub fn fdimf(a: f32, b: f32) -> f32; + pub safe fn acos(n: f64) -> f64; + pub safe fn asin(n: f64) -> f64; + pub safe fn atan(n: f64) -> f64; + pub safe fn atan2(a: f64, b: f64) -> f64; + pub safe fn cbrt(n: f64) -> f64; + pub safe fn cbrtf(n: f32) -> f32; + pub safe fn cosh(n: f64) -> f64; + pub safe fn expm1(n: f64) -> f64; + pub safe fn expm1f(n: f32) -> f32; + pub safe fn fdim(a: f64, b: f64) -> f64; + pub safe fn fdimf(a: f32, b: f32) -> f32; #[cfg_attr(target_env = "msvc", link_name = "_hypot")] - pub fn hypot(x: f64, y: f64) -> f64; + pub safe fn hypot(x: f64, y: f64) -> f64; #[cfg_attr(target_env = "msvc", link_name = "_hypotf")] - pub fn hypotf(x: f32, y: f32) -> f32; - pub fn log1p(n: f64) -> f64; - pub fn log1pf(n: f32) -> f32; - pub fn sinh(n: f64) -> f64; - pub fn tan(n: f64) -> f64; - pub fn tanh(n: f64) -> f64; - pub fn tgamma(n: f64) -> f64; - pub fn tgammaf(n: f32) -> f32; - pub fn lgamma_r(n: f64, s: &mut i32) -> f64; + pub safe fn hypotf(x: f32, y: f32) -> f32; + pub safe fn log1p(n: f64) -> f64; + pub safe fn log1pf(n: f32) -> f32; + pub safe fn sinh(n: f64) -> f64; + pub safe fn tan(n: f64) -> f64; + pub safe fn tanh(n: f64) -> f64; + pub safe fn tgamma(n: f64) -> f64; + pub safe fn tgammaf(n: f32) -> f32; + pub safe fn lgamma_r(n: f64, s: &mut i32) -> f64; #[cfg(not(target_os = "aix"))] - pub fn lgammaf_r(n: f32, s: &mut i32) -> f32; - pub fn erf(n: f64) -> f64; - pub fn erff(n: f32) -> f32; - pub fn erfc(n: f64) -> f64; - pub fn erfcf(n: f32) -> f32; + pub safe fn lgammaf_r(n: f32, s: &mut i32) -> f32; + pub safe fn erf(n: f64) -> f64; + pub safe fn erff(n: f32) -> f32; + pub safe fn erfc(n: f64) -> f64; + pub safe fn erfcf(n: f32) -> f32; - pub fn acosf128(n: f128) -> f128; - pub fn asinf128(n: f128) -> f128; - pub fn atanf128(n: f128) -> f128; - pub fn atan2f128(a: f128, b: f128) -> f128; - pub fn cbrtf128(n: f128) -> f128; - pub fn coshf128(n: f128) -> f128; - pub fn expm1f128(n: f128) -> f128; - pub fn hypotf128(x: f128, y: f128) -> f128; - pub fn log1pf128(n: f128) -> f128; - pub fn sinhf128(n: f128) -> f128; - pub fn tanf128(n: f128) -> f128; - pub fn tanhf128(n: f128) -> f128; - pub fn tgammaf128(n: f128) -> f128; - pub fn lgammaf128_r(n: f128, s: &mut i32) -> f128; - pub fn erff128(n: f128) -> f128; - pub fn erfcf128(n: f128) -> f128; + pub safe fn acosf128(n: f128) -> f128; + pub safe fn asinf128(n: f128) -> f128; + pub safe fn atanf128(n: f128) -> f128; + pub safe fn atan2f128(a: f128, b: f128) -> f128; + pub safe fn cbrtf128(n: f128) -> f128; + pub safe fn coshf128(n: f128) -> f128; + pub safe fn expm1f128(n: f128) -> f128; + pub safe fn hypotf128(x: f128, y: f128) -> f128; + pub safe fn log1pf128(n: f128) -> f128; + pub safe fn sinhf128(n: f128) -> f128; + pub safe fn tanf128(n: f128) -> f128; + pub safe fn tanhf128(n: f128) -> f128; + pub safe fn tgammaf128(n: f128) -> f128; + pub safe fn lgammaf128_r(n: f128, s: &mut i32) -> f128; + pub safe fn erff128(n: f128) -> f128; + pub safe fn erfcf128(n: f128) -> f128; cfg_if::cfg_if! { if #[cfg(not(all(target_os = "windows", target_env = "msvc", target_arch = "x86")))] { - pub fn acosf(n: f32) -> f32; - pub fn asinf(n: f32) -> f32; - pub fn atan2f(a: f32, b: f32) -> f32; - pub fn atanf(n: f32) -> f32; - pub fn coshf(n: f32) -> f32; - pub fn sinhf(n: f32) -> f32; - pub fn tanf(n: f32) -> f32; - pub fn tanhf(n: f32) -> f32; + pub safe fn acosf(n: f32) -> f32; + pub safe fn asinf(n: f32) -> f32; + pub safe fn atan2f(a: f32, b: f32) -> f32; + pub safe fn atanf(n: f32) -> f32; + pub safe fn coshf(n: f32) -> f32; + pub safe fn sinhf(n: f32) -> f32; + pub safe fn tanf(n: f32) -> f32; + pub safe fn tanhf(n: f32) -> f32; }} } // On AIX, we don't have lgammaf_r only the f64 version, so we can // use the f64 version lgamma_r #[cfg(target_os = "aix")] -pub unsafe fn lgammaf_r(n: f32, s: &mut i32) -> f32 { +pub fn lgammaf_r(n: f32, s: &mut i32) -> f32 { lgamma_r(n.into(), s) as f32 } @@ -76,42 +76,42 @@ pub unsafe fn lgammaf_r(n: f32, s: &mut i32) -> f32 { cfg_if::cfg_if! { if #[cfg(all(target_os = "windows", target_env = "msvc", target_arch = "x86"))] { #[inline] - pub unsafe fn acosf(n: f32) -> f32 { + pub fn acosf(n: f32) -> f32 { f64::acos(n as f64) as f32 } #[inline] - pub unsafe fn asinf(n: f32) -> f32 { + pub fn asinf(n: f32) -> f32 { f64::asin(n as f64) as f32 } #[inline] - pub unsafe fn atan2f(n: f32, b: f32) -> f32 { + pub fn atan2f(n: f32, b: f32) -> f32 { f64::atan2(n as f64, b as f64) as f32 } #[inline] - pub unsafe fn atanf(n: f32) -> f32 { + pub fn atanf(n: f32) -> f32 { f64::atan(n as f64) as f32 } #[inline] - pub unsafe fn coshf(n: f32) -> f32 { + pub fn coshf(n: f32) -> f32 { f64::cosh(n as f64) as f32 } #[inline] - pub unsafe fn sinhf(n: f32) -> f32 { + pub fn sinhf(n: f32) -> f32 { f64::sinh(n as f64) as f32 } #[inline] - pub unsafe fn tanf(n: f32) -> f32 { + pub fn tanf(n: f32) -> f32 { f64::tan(n as f64) as f32 } #[inline] - pub unsafe fn tanhf(n: f32) -> f32 { + pub fn tanhf(n: f32) -> f32 { f64::tanh(n as f64) as f32 } }} diff --git a/library/std/src/sys/fd/unix.rs b/library/std/src/sys/fd/unix.rs index 2042ea2c73d0..cdca73cdca11 100644 --- a/library/std/src/sys/fd/unix.rs +++ b/library/std/src/sys/fd/unix.rs @@ -71,9 +71,11 @@ const fn max_iov() -> usize { target_os = "android", target_os = "dragonfly", target_os = "emscripten", + target_os = "espidf", target_os = "freebsd", target_os = "linux", target_os = "netbsd", + target_os = "nuttx", target_os = "nto", target_os = "openbsd", target_os = "horizon", @@ -257,9 +259,6 @@ impl FileDesc { } #[cfg(all(target_os = "android", target_pointer_width = "32"))] - // FIXME(#115199): Rust currently omits weak function definitions - // and its metadata from LLVM IR. - #[no_sanitize(cfi)] pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result { weak!( fn preadv64( diff --git a/library/std/src/sys/fs/mod.rs b/library/std/src/sys/fs/mod.rs index 3b176d0d16c4..4c5e36ce67a3 100644 --- a/library/std/src/sys/fs/mod.rs +++ b/library/std/src/sys/fs/mod.rs @@ -20,6 +20,7 @@ cfg_if::cfg_if! { mod windows; use windows as imp; pub use windows::{symlink_inner, junction_point}; + use crate::sys::path::with_native_path; } else if #[cfg(target_os = "hermit")] { mod hermit; use hermit as imp; @@ -39,7 +40,7 @@ cfg_if::cfg_if! { } // FIXME: Replace this with platform-specific path conversion functions. -#[cfg(not(target_family = "unix"))] +#[cfg(not(any(target_family = "unix", target_os = "windows")))] #[inline] pub fn with_native_path(path: &Path, f: &dyn Fn(&Path) -> io::Result) -> io::Result { f(path) @@ -51,7 +52,7 @@ pub use imp::{ }; pub fn read_dir(path: &Path) -> io::Result { - // FIXME: use with_native_path + // FIXME: use with_native_path on all platforms imp::readdir(path) } @@ -68,8 +69,11 @@ pub fn remove_dir(path: &Path) -> io::Result<()> { } pub fn remove_dir_all(path: &Path) -> io::Result<()> { - // FIXME: use with_native_path - imp::remove_dir_all(path) + // FIXME: use with_native_path on all platforms + #[cfg(not(windows))] + return imp::remove_dir_all(path); + #[cfg(windows)] + with_native_path(path, &imp::remove_dir_all) } pub fn read_link(path: &Path) -> io::Result { @@ -77,6 +81,10 @@ pub fn read_link(path: &Path) -> io::Result { } pub fn symlink(original: &Path, link: &Path) -> io::Result<()> { + // FIXME: use with_native_path on all platforms + #[cfg(windows)] + return imp::symlink(original, link); + #[cfg(not(windows))] with_native_path(original, &|original| { with_native_path(link, &|link| imp::symlink(original, link)) }) @@ -105,11 +113,17 @@ pub fn canonicalize(path: &Path) -> io::Result { } pub fn copy(from: &Path, to: &Path) -> io::Result { - // FIXME: use with_native_path - imp::copy(from, to) + // FIXME: use with_native_path on all platforms + #[cfg(not(windows))] + return imp::copy(from, to); + #[cfg(windows)] + with_native_path(from, &|from| with_native_path(to, &|to| imp::copy(from, to))) } pub fn exists(path: &Path) -> io::Result { - // FIXME: use with_native_path - imp::exists(path) + // FIXME: use with_native_path on all platforms + #[cfg(not(windows))] + return imp::exists(path); + #[cfg(windows)] + with_native_path(path, &imp::exists) } diff --git a/library/std/src/sys/fs/unix.rs b/library/std/src/sys/fs/unix.rs index 87865be0387d..687fc322e598 100644 --- a/library/std/src/sys/fs/unix.rs +++ b/library/std/src/sys/fs/unix.rs @@ -1463,20 +1463,6 @@ impl File { Ok(()) } - // FIXME(#115199): Rust currently omits weak function definitions - // and its metadata from LLVM IR. - #[cfg_attr( - any( - target_os = "android", - all( - target_os = "linux", - target_env = "gnu", - target_pointer_width = "32", - not(target_arch = "riscv32") - ) - ), - no_sanitize(cfi) - )] pub fn set_times(&self, times: FileTimes) -> io::Result<()> { #[cfg(not(any( target_os = "redox", diff --git a/library/std/src/sys/fs/windows.rs b/library/std/src/sys/fs/windows.rs index 15727c996837..9215f9375671 100644 --- a/library/std/src/sys/fs/windows.rs +++ b/library/std/src/sys/fs/windows.rs @@ -12,7 +12,7 @@ use crate::sync::Arc; use crate::sys::handle::Handle; use crate::sys::pal::api::{self, WinError, set_file_information_by_handle}; use crate::sys::pal::{IoResult, fill_utf16_buf, to_u16s, truncate_utf16_at_nul}; -use crate::sys::path::maybe_verbatim; +use crate::sys::path::{WCStr, maybe_verbatim}; use crate::sys::time::SystemTime; use crate::sys::{Align8, c, cvt}; use crate::sys_common::{AsInner, FromInner, IntoInner}; @@ -298,10 +298,12 @@ impl OpenOptions { impl File { pub fn open(path: &Path, opts: &OpenOptions) -> io::Result { let path = maybe_verbatim(path)?; + // SAFETY: maybe_verbatim returns null-terminated strings + let path = unsafe { WCStr::from_wchars_with_null_unchecked(&path) }; Self::open_native(&path, opts) } - fn open_native(path: &[u16], opts: &OpenOptions) -> io::Result { + fn open_native(path: &WCStr, opts: &OpenOptions) -> io::Result { let creation = opts.get_creation_mode()?; let handle = unsafe { c::CreateFileW( @@ -1212,9 +1214,8 @@ pub fn readdir(p: &Path) -> io::Result { } } -pub fn unlink(p: &Path) -> io::Result<()> { - let p_u16s = maybe_verbatim(p)?; - if unsafe { c::DeleteFileW(p_u16s.as_ptr()) } == 0 { +pub fn unlink(path: &WCStr) -> io::Result<()> { + if unsafe { c::DeleteFileW(path.as_ptr()) } == 0 { let err = api::get_last_error(); // if `DeleteFileW` fails with ERROR_ACCESS_DENIED then try to remove // the file while ignoring the readonly attribute. @@ -1223,7 +1224,7 @@ pub fn unlink(p: &Path) -> io::Result<()> { let mut opts = OpenOptions::new(); opts.access_mode(c::DELETE); opts.custom_flags(c::FILE_FLAG_OPEN_REPARSE_POINT); - if let Ok(f) = File::open_native(&p_u16s, &opts) { + if let Ok(f) = File::open_native(&path, &opts) { if f.posix_delete().is_ok() { return Ok(()); } @@ -1236,10 +1237,7 @@ pub fn unlink(p: &Path) -> io::Result<()> { } } -pub fn rename(old: &Path, new: &Path) -> io::Result<()> { - let old = maybe_verbatim(old)?; - let new = maybe_verbatim(new)?; - +pub fn rename(old: &WCStr, new: &WCStr) -> io::Result<()> { if unsafe { c::MoveFileExW(old.as_ptr(), new.as_ptr(), c::MOVEFILE_REPLACE_EXISTING) } == 0 { let err = api::get_last_error(); // if `MoveFileExW` fails with ERROR_ACCESS_DENIED then try to move @@ -1253,7 +1251,8 @@ pub fn rename(old: &Path, new: &Path) -> io::Result<()> { // Calculate the layout of the `FILE_RENAME_INFO` we pass to `SetFileInformation` // This is a dynamically sized struct so we need to get the position of the last field to calculate the actual size. - let Ok(new_len_without_nul_in_bytes): Result = ((new.len() - 1) * 2).try_into() + let Ok(new_len_without_nul_in_bytes): Result = + ((new.count_bytes() - 1) * 2).try_into() else { return Err(err).io_result(); }; @@ -1282,7 +1281,7 @@ pub fn rename(old: &Path, new: &Path) -> io::Result<()> { new.as_ptr().copy_to_nonoverlapping( (&raw mut (*file_rename_info).FileName).cast::(), - new.len(), + new.count_bytes(), ); } @@ -1309,20 +1308,19 @@ pub fn rename(old: &Path, new: &Path) -> io::Result<()> { Ok(()) } -pub fn rmdir(p: &Path) -> io::Result<()> { - let p = maybe_verbatim(p)?; +pub fn rmdir(p: &WCStr) -> io::Result<()> { cvt(unsafe { c::RemoveDirectoryW(p.as_ptr()) })?; Ok(()) } -pub fn remove_dir_all(path: &Path) -> io::Result<()> { +pub fn remove_dir_all(path: &WCStr) -> io::Result<()> { // Open a file or directory without following symlinks. let mut opts = OpenOptions::new(); opts.access_mode(c::FILE_LIST_DIRECTORY); // `FILE_FLAG_BACKUP_SEMANTICS` allows opening directories. // `FILE_FLAG_OPEN_REPARSE_POINT` opens a link instead of its target. opts.custom_flags(c::FILE_FLAG_BACKUP_SEMANTICS | c::FILE_FLAG_OPEN_REPARSE_POINT); - let file = File::open(path, &opts)?; + let file = File::open_native(path, &opts)?; // Test if the file is not a directory or a symlink to a directory. if (file.basic_info()?.FileAttributes & c::FILE_ATTRIBUTE_DIRECTORY) == 0 { @@ -1333,14 +1331,14 @@ pub fn remove_dir_all(path: &Path) -> io::Result<()> { remove_dir_all_iterative(file).io_result() } -pub fn readlink(path: &Path) -> io::Result { +pub fn readlink(path: &WCStr) -> io::Result { // Open the link with no access mode, instead of generic read. // By default FILE_LIST_DIRECTORY is denied for the junction "C:\Documents and Settings", so // this is needed for a common case. let mut opts = OpenOptions::new(); opts.access_mode(0); opts.custom_flags(c::FILE_FLAG_OPEN_REPARSE_POINT | c::FILE_FLAG_BACKUP_SEMANTICS); - let file = File::open(path, &opts)?; + let file = File::open_native(&path, &opts)?; file.readlink() } @@ -1378,19 +1376,17 @@ pub fn symlink_inner(original: &Path, link: &Path, dir: bool) -> io::Result<()> } #[cfg(not(target_vendor = "uwp"))] -pub fn link(original: &Path, link: &Path) -> io::Result<()> { - let original = maybe_verbatim(original)?; - let link = maybe_verbatim(link)?; +pub fn link(original: &WCStr, link: &WCStr) -> io::Result<()> { cvt(unsafe { c::CreateHardLinkW(link.as_ptr(), original.as_ptr(), ptr::null_mut()) })?; Ok(()) } #[cfg(target_vendor = "uwp")] -pub fn link(_original: &Path, _link: &Path) -> io::Result<()> { +pub fn link(_original: &WCStr, _link: &WCStr) -> io::Result<()> { return Err(io::const_error!(io::ErrorKind::Unsupported, "hard link are not supported on UWP")); } -pub fn stat(path: &Path) -> io::Result { +pub fn stat(path: &WCStr) -> io::Result { match metadata(path, ReparsePoint::Follow) { Err(err) if err.raw_os_error() == Some(c::ERROR_CANT_ACCESS_FILE as i32) => { if let Ok(attrs) = lstat(path) { @@ -1404,7 +1400,7 @@ pub fn stat(path: &Path) -> io::Result { } } -pub fn lstat(path: &Path) -> io::Result { +pub fn lstat(path: &WCStr) -> io::Result { metadata(path, ReparsePoint::Open) } @@ -1420,7 +1416,7 @@ impl ReparsePoint { } } -fn metadata(path: &Path, reparse: ReparsePoint) -> io::Result { +fn metadata(path: &WCStr, reparse: ReparsePoint) -> io::Result { let mut opts = OpenOptions::new(); // No read or write permissions are necessary opts.access_mode(0); @@ -1429,7 +1425,7 @@ fn metadata(path: &Path, reparse: ReparsePoint) -> io::Result { // Attempt to open the file normally. // If that fails with `ERROR_SHARING_VIOLATION` then retry using `FindFirstFileExW`. // If the fallback fails for any reason we return the original error. - match File::open(path, &opts) { + match File::open_native(&path, &opts) { Ok(file) => file.file_attr(), Err(e) if [Some(c::ERROR_SHARING_VIOLATION as _), Some(c::ERROR_ACCESS_DENIED as _)] @@ -1442,8 +1438,6 @@ fn metadata(path: &Path, reparse: ReparsePoint) -> io::Result { // However, there are special system files, such as // `C:\hiberfil.sys`, that are locked in a way that denies even that. unsafe { - let path = maybe_verbatim(path)?; - // `FindFirstFileExW` accepts wildcard file names. // Fortunately wildcards are not valid file names and // `ERROR_SHARING_VIOLATION` means the file exists (but is locked) @@ -1482,8 +1476,7 @@ fn metadata(path: &Path, reparse: ReparsePoint) -> io::Result { } } -pub fn set_perm(p: &Path, perm: FilePermissions) -> io::Result<()> { - let p = maybe_verbatim(p)?; +pub fn set_perm(p: &WCStr, perm: FilePermissions) -> io::Result<()> { unsafe { cvt(c::SetFileAttributesW(p.as_ptr(), perm.attrs))?; Ok(()) @@ -1499,17 +1492,17 @@ fn get_path(f: &File) -> io::Result { ) } -pub fn canonicalize(p: &Path) -> io::Result { +pub fn canonicalize(p: &WCStr) -> io::Result { let mut opts = OpenOptions::new(); // No read or write permissions are necessary opts.access_mode(0); // This flag is so we can open directories too opts.custom_flags(c::FILE_FLAG_BACKUP_SEMANTICS); - let f = File::open(p, &opts)?; + let f = File::open_native(p, &opts)?; get_path(&f) } -pub fn copy(from: &Path, to: &Path) -> io::Result { +pub fn copy(from: &WCStr, to: &WCStr) -> io::Result { unsafe extern "system" fn callback( _TotalFileSize: i64, _TotalBytesTransferred: i64, @@ -1528,13 +1521,11 @@ pub fn copy(from: &Path, to: &Path) -> io::Result { c::PROGRESS_CONTINUE } } - let pfrom = maybe_verbatim(from)?; - let pto = maybe_verbatim(to)?; let mut size = 0i64; cvt(unsafe { c::CopyFileExW( - pfrom.as_ptr(), - pto.as_ptr(), + from.as_ptr(), + to.as_ptr(), Some(callback), (&raw mut size) as *mut _, ptr::null_mut(), @@ -1624,14 +1615,14 @@ pub fn junction_point(original: &Path, link: &Path) -> io::Result<()> { } // Try to see if a file exists but, unlike `exists`, report I/O errors. -pub fn exists(path: &Path) -> io::Result { +pub fn exists(path: &WCStr) -> io::Result { // Open the file to ensure any symlinks are followed to their target. let mut opts = OpenOptions::new(); // No read, write, etc access rights are needed. opts.access_mode(0); // Backup semantics enables opening directories as well as files. opts.custom_flags(c::FILE_FLAG_BACKUP_SEMANTICS); - match File::open(path, &opts) { + match File::open_native(path, &opts) { Err(e) => match e.kind() { // The file definitely does not exist io::ErrorKind::NotFound => Ok(false), diff --git a/library/std/src/sys/fs/windows/remove_dir_all.rs b/library/std/src/sys/fs/windows/remove_dir_all.rs index f51eced84164..b213c49bcb00 100644 --- a/library/std/src/sys/fs/windows/remove_dir_all.rs +++ b/library/std/src/sys/fs/windows/remove_dir_all.rs @@ -95,7 +95,7 @@ fn open_link_no_reparse( ObjectName: &mut path_str, RootDirectory: parent.as_raw_handle(), Attributes: ATTRIBUTES.load(Ordering::Relaxed), - ..c::OBJECT_ATTRIBUTES::default() + ..c::OBJECT_ATTRIBUTES::with_length() }; let share = c::FILE_SHARE_DELETE | c::FILE_SHARE_READ | c::FILE_SHARE_WRITE; let options = c::FILE_OPEN_REPARSE_POINT | options; diff --git a/library/std/src/sys/mod.rs b/library/std/src/sys/mod.rs index f8f220fafd1d..bc4bf11cb740 100644 --- a/library/std/src/sys/mod.rs +++ b/library/std/src/sys/mod.rs @@ -9,6 +9,7 @@ mod alloc; mod personality; pub mod anonymous_pipe; +pub mod args; pub mod backtrace; pub mod cmath; pub mod exit_guard; diff --git a/library/std/src/sys/net/connection/socket/unix.rs b/library/std/src/sys/net/connection/socket/unix.rs index bbe1e038dccf..b35d5d2aa841 100644 --- a/library/std/src/sys/net/connection/socket/unix.rs +++ b/library/std/src/sys/net/connection/socket/unix.rs @@ -1,5 +1,6 @@ use libc::{MSG_PEEK, c_int, c_void, size_t, sockaddr, socklen_t}; +#[cfg(not(any(target_os = "espidf", target_os = "nuttx")))] use crate::ffi::CStr; use crate::io::{self, BorrowedBuf, BorrowedCursor, IoSlice, IoSliceMut}; use crate::net::{Shutdown, SocketAddr}; diff --git a/library/std/src/sys/pal/hermit/mod.rs b/library/std/src/sys/pal/hermit/mod.rs index 26211bcb1520..821836824e2b 100644 --- a/library/std/src/sys/pal/hermit/mod.rs +++ b/library/std/src/sys/pal/hermit/mod.rs @@ -18,7 +18,6 @@ use crate::os::raw::c_char; -pub mod args; pub mod env; pub mod futex; pub mod os; @@ -58,7 +57,7 @@ pub extern "C" fn __rust_abort() { // NOTE: this is not guaranteed to run, for example when Rust code is called externally. pub unsafe fn init(argc: isize, argv: *const *const u8, _sigpipe: u8) { unsafe { - args::init(argc, argv); + crate::sys::args::init(argc, argv); } } diff --git a/library/std/src/sys/pal/sgx/mod.rs b/library/std/src/sys/pal/sgx/mod.rs index 52684e18ac27..8a87e7a7ae13 100644 --- a/library/std/src/sys/pal/sgx/mod.rs +++ b/library/std/src/sys/pal/sgx/mod.rs @@ -9,7 +9,6 @@ use crate::io::ErrorKind; use crate::sync::atomic::{AtomicBool, Ordering}; pub mod abi; -pub mod args; pub mod env; mod libunwind_integration; pub mod os; @@ -24,7 +23,7 @@ pub mod waitqueue; // NOTE: this is not guaranteed to run, for example when Rust code is called externally. pub unsafe fn init(argc: isize, argv: *const *const u8, _sigpipe: u8) { unsafe { - args::init(argc, argv); + crate::sys::args::init(argc, argv); } } diff --git a/library/std/src/sys/pal/solid/mod.rs b/library/std/src/sys/pal/solid/mod.rs index 22052a168fd1..c41dc848a1b4 100644 --- a/library/std/src/sys/pal/solid/mod.rs +++ b/library/std/src/sys/pal/solid/mod.rs @@ -16,8 +16,6 @@ pub mod itron { use super::unsupported; } -#[path = "../unsupported/args.rs"] -pub mod args; pub mod env; // `error` is `pub(crate)` so that it can be accessed by `itron/error.rs` as // `crate::sys::error` diff --git a/library/std/src/sys/pal/teeos/mod.rs b/library/std/src/sys/pal/teeos/mod.rs index c1921a2f40df..b8095cec3e97 100644 --- a/library/std/src/sys/pal/teeos/mod.rs +++ b/library/std/src/sys/pal/teeos/mod.rs @@ -6,8 +6,6 @@ #![allow(unused_variables)] #![allow(dead_code)] -#[path = "../unsupported/args.rs"] -pub mod args; #[path = "../unsupported/env.rs"] pub mod env; //pub mod fd; diff --git a/library/std/src/sys/pal/trusty/mod.rs b/library/std/src/sys/pal/trusty/mod.rs index 5295d3fdc914..04e6b4c81868 100644 --- a/library/std/src/sys/pal/trusty/mod.rs +++ b/library/std/src/sys/pal/trusty/mod.rs @@ -1,7 +1,5 @@ //! System bindings for the Trusty OS. -#[path = "../unsupported/args.rs"] -pub mod args; #[path = "../unsupported/common.rs"] #[deny(unsafe_op_in_unsafe_fn)] mod common; diff --git a/library/std/src/sys/pal/uefi/mod.rs b/library/std/src/sys/pal/uefi/mod.rs index 9760a23084aa..cd901f48b76f 100644 --- a/library/std/src/sys/pal/uefi/mod.rs +++ b/library/std/src/sys/pal/uefi/mod.rs @@ -13,7 +13,6 @@ //! [`OsString`]: crate::ffi::OsString #![forbid(unsafe_op_in_unsafe_fn)] -pub mod args; pub mod env; pub mod helpers; pub mod os; diff --git a/library/std/src/sys/pal/unix/mod.rs b/library/std/src/sys/pal/unix/mod.rs index d7106c339747..3a790d9c868c 100644 --- a/library/std/src/sys/pal/unix/mod.rs +++ b/library/std/src/sys/pal/unix/mod.rs @@ -6,7 +6,6 @@ use crate::io::ErrorKind; #[macro_use] pub mod weak; -pub mod args; pub mod env; #[cfg(target_os = "fuchsia")] pub mod fuchsia; @@ -27,6 +26,7 @@ pub mod time; pub fn init(_argc: isize, _argv: *const *const u8, _sigpipe: u8) {} #[cfg(not(target_os = "espidf"))] +#[cfg_attr(target_os = "vita", allow(unused_variables))] // SAFETY: must be called only once during runtime initialization. // NOTE: this is not guaranteed to run, for example when Rust code is called externally. // See `fn init()` in `library/std/src/rt.rs` for docs on `sigpipe`. @@ -47,7 +47,8 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) { reset_sigpipe(sigpipe); stack_overflow::init(); - args::init(argc, argv); + #[cfg(not(target_os = "vita"))] + crate::sys::args::init(argc, argv); // Normally, `thread::spawn` will call `Thread::set_name` but since this thread // already exists, we have to call it ourselves. We only do this on Apple targets @@ -273,6 +274,7 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind { libc::ETXTBSY => ExecutableFileBusy, libc::EXDEV => CrossesDevices, libc::EINPROGRESS => InProgress, + libc::EOPNOTSUPP => Unsupported, libc::EACCES | libc::EPERM => PermissionDenied, diff --git a/library/std/src/sys/pal/unix/thread.rs b/library/std/src/sys/pal/unix/thread.rs index 9078dd1c2316..4cdc2eaf0e53 100644 --- a/library/std/src/sys/pal/unix/thread.rs +++ b/library/std/src/sys/pal/unix/thread.rs @@ -8,14 +8,19 @@ use crate::sys::weak::weak; use crate::sys::{os, stack_overflow}; use crate::time::Duration; use crate::{cmp, io, ptr}; -#[cfg(not(any(target_os = "l4re", target_os = "vxworks", target_os = "espidf")))] +#[cfg(not(any( + target_os = "l4re", + target_os = "vxworks", + target_os = "espidf", + target_os = "nuttx" +)))] pub const DEFAULT_MIN_STACK_SIZE: usize = 2 * 1024 * 1024; #[cfg(target_os = "l4re")] pub const DEFAULT_MIN_STACK_SIZE: usize = 1024 * 1024; #[cfg(target_os = "vxworks")] pub const DEFAULT_MIN_STACK_SIZE: usize = 256 * 1024; -#[cfg(target_os = "espidf")] -pub const DEFAULT_MIN_STACK_SIZE: usize = 0; // 0 indicates that the stack size configured in the ESP-IDF menuconfig system should be used +#[cfg(any(target_os = "espidf", target_os = "nuttx"))] +pub const DEFAULT_MIN_STACK_SIZE: usize = 0; // 0 indicates that the stack size configured in the ESP-IDF/NuttX menuconfig system should be used #[cfg(target_os = "fuchsia")] mod zircon { @@ -52,10 +57,10 @@ impl Thread { let mut attr: mem::MaybeUninit = mem::MaybeUninit::uninit(); assert_eq!(libc::pthread_attr_init(attr.as_mut_ptr()), 0); - #[cfg(target_os = "espidf")] + #[cfg(any(target_os = "espidf", target_os = "nuttx"))] if stack > 0 { // Only set the stack if a non-zero value is passed - // 0 is used as an indication that the default stack size configured in the ESP-IDF menuconfig system should be used + // 0 is used as an indication that the default stack size configured in the ESP-IDF/NuttX menuconfig system should be used assert_eq!( libc::pthread_attr_setstacksize( attr.as_mut_ptr(), @@ -65,7 +70,7 @@ impl Thread { ); } - #[cfg(not(target_os = "espidf"))] + #[cfg(not(any(target_os = "espidf", target_os = "nuttx")))] { let stack_size = cmp::max(stack, min_stack_size(attr.as_ptr())); @@ -189,9 +194,6 @@ impl Thread { } #[cfg(any(target_os = "solaris", target_os = "illumos", target_os = "nto"))] - // FIXME(#115199): Rust currently omits weak function definitions - // and its metadata from LLVM IR. - #[no_sanitize(cfi)] pub fn set_name(name: &CStr) { weak!( fn pthread_setname_np( diff --git a/library/std/src/sys/pal/unix/time.rs b/library/std/src/sys/pal/unix/time.rs index b8469b1681f0..0074d7674741 100644 --- a/library/std/src/sys/pal/unix/time.rs +++ b/library/std/src/sys/pal/unix/time.rs @@ -96,17 +96,6 @@ impl Timespec { } } - // FIXME(#115199): Rust currently omits weak function definitions - // and its metadata from LLVM IR. - #[cfg_attr( - all( - target_os = "linux", - target_env = "gnu", - target_pointer_width = "32", - not(target_arch = "riscv32") - ), - no_sanitize(cfi) - )] pub fn now(clock: libc::clockid_t) -> Timespec { use crate::mem::MaybeUninit; use crate::sys::cvt; diff --git a/library/std/src/sys/pal/unix/weak.rs b/library/std/src/sys/pal/unix/weak.rs index e4c814fba8ce..a034995e6525 100644 --- a/library/std/src/sys/pal/unix/weak.rs +++ b/library/std/src/sys/pal/unix/weak.rs @@ -155,9 +155,6 @@ unsafe fn fetch(name: &str) -> *mut libc::c_void { #[cfg(not(any(target_os = "linux", target_os = "android")))] pub(crate) macro syscall { (fn $name:ident($($param:ident : $t:ty),* $(,)?) -> $ret:ty;) => ( - // FIXME(#115199): Rust currently omits weak function definitions - // and its metadata from LLVM IR. - #[no_sanitize(cfi)] unsafe fn $name($($param: $t),*) -> $ret { weak!(fn $name($($param: $t),*) -> $ret;); diff --git a/library/std/src/sys/pal/unsupported/mod.rs b/library/std/src/sys/pal/unsupported/mod.rs index 38838b915b5c..dea42a95dcc6 100644 --- a/library/std/src/sys/pal/unsupported/mod.rs +++ b/library/std/src/sys/pal/unsupported/mod.rs @@ -1,6 +1,5 @@ #![deny(unsafe_op_in_unsafe_fn)] -pub mod args; pub mod env; pub mod os; pub mod pipe; diff --git a/library/std/src/sys/pal/wasi/args.rs b/library/std/src/sys/pal/wasi/args.rs deleted file mode 100644 index 52cfa202af82..000000000000 --- a/library/std/src/sys/pal/wasi/args.rs +++ /dev/null @@ -1,61 +0,0 @@ -#![forbid(unsafe_op_in_unsafe_fn)] - -use crate::ffi::{CStr, OsStr, OsString}; -use crate::os::wasi::ffi::OsStrExt; -use crate::{fmt, vec}; - -pub struct Args { - iter: vec::IntoIter, -} - -impl !Send for Args {} -impl !Sync for Args {} - -/// Returns the command line arguments -pub fn args() -> Args { - Args { iter: maybe_args().unwrap_or(Vec::new()).into_iter() } -} - -fn maybe_args() -> Option> { - unsafe { - let (argc, buf_size) = wasi::args_sizes_get().ok()?; - let mut argv = Vec::with_capacity(argc); - let mut buf = Vec::with_capacity(buf_size); - wasi::args_get(argv.as_mut_ptr(), buf.as_mut_ptr()).ok()?; - argv.set_len(argc); - let mut ret = Vec::with_capacity(argc); - for ptr in argv { - let s = CStr::from_ptr(ptr.cast()); - ret.push(OsStr::from_bytes(s.to_bytes()).to_owned()); - } - Some(ret) - } -} - -impl fmt::Debug for Args { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.iter.as_slice().fmt(f) - } -} - -impl Iterator for Args { - type Item = OsString; - fn next(&mut self) -> Option { - self.iter.next() - } - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } -} - -impl ExactSizeIterator for Args { - fn len(&self) -> usize { - self.iter.len() - } -} - -impl DoubleEndedIterator for Args { - fn next_back(&mut self) -> Option { - self.iter.next_back() - } -} diff --git a/library/std/src/sys/pal/wasi/mod.rs b/library/std/src/sys/pal/wasi/mod.rs index 80853e7b5a26..4ea42b1082b1 100644 --- a/library/std/src/sys/pal/wasi/mod.rs +++ b/library/std/src/sys/pal/wasi/mod.rs @@ -13,7 +13,6 @@ //! compiling for wasm. That way it's a compile time error for something that's //! guaranteed to be a runtime error! -pub mod args; pub mod env; #[allow(unused)] #[path = "../wasm/atomics/futex.rs"] diff --git a/library/std/src/sys/pal/wasip2/mod.rs b/library/std/src/sys/pal/wasip2/mod.rs index 504b947d09e2..6445bf2cc0d2 100644 --- a/library/std/src/sys/pal/wasip2/mod.rs +++ b/library/std/src/sys/pal/wasip2/mod.rs @@ -6,8 +6,6 @@ //! To begin with, this target mirrors the wasi target 1 to 1, but over //! time this will change significantly. -#[path = "../wasi/args.rs"] -pub mod args; #[path = "../wasi/env.rs"] pub mod env; #[allow(unused)] diff --git a/library/std/src/sys/pal/wasm/mod.rs b/library/std/src/sys/pal/wasm/mod.rs index 8d39b70d0397..af370020d96a 100644 --- a/library/std/src/sys/pal/wasm/mod.rs +++ b/library/std/src/sys/pal/wasm/mod.rs @@ -16,8 +16,6 @@ #![deny(unsafe_op_in_unsafe_fn)] -#[path = "../unsupported/args.rs"] -pub mod args; pub mod env; #[path = "../unsupported/os.rs"] pub mod os; diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs index 004cbee52f62..ac1c5e9932e1 100644 --- a/library/std/src/sys/pal/windows/c.rs +++ b/library/std/src/sys/pal/windows/c.rs @@ -44,8 +44,8 @@ impl UNICODE_STRING { } } -impl Default for OBJECT_ATTRIBUTES { - fn default() -> Self { +impl OBJECT_ATTRIBUTES { + pub fn with_length() -> Self { Self { Length: size_of::() as _, RootDirectory: ptr::null_mut(), diff --git a/library/std/src/sys/pal/windows/c/bindings.txt b/library/std/src/sys/pal/windows/c/bindings.txt index e2c216332796..d5fbb453c6f9 100644 --- a/library/std/src/sys/pal/windows/c/bindings.txt +++ b/library/std/src/sys/pal/windows/c/bindings.txt @@ -1,7 +1,8 @@ --out windows_sys.rs --flat --sys ---no-core +--no-deps +--link windows_targets --filter !INVALID_HANDLE_VALUE ABOVE_NORMAL_PRIORITY_CLASS @@ -19,7 +20,6 @@ ALL_PROCESSOR_GROUPS ARM64_NT_NEON128 BELOW_NORMAL_PRIORITY_CLASS bind -BOOL BY_HANDLE_FILE_INFORMATION CALLBACK_CHUNK_FINISHED CALLBACK_STREAM_SWITCH diff --git a/library/std/src/sys/pal/windows/c/windows_sys.rs b/library/std/src/sys/pal/windows/c/windows_sys.rs index 1d0e89f5d0f0..eb2914b86447 100644 --- a/library/std/src/sys/pal/windows/c/windows_sys.rs +++ b/library/std/src/sys/pal/windows/c/windows_sys.rs @@ -1,4 +1,4 @@ -// Bindings generated by `windows-bindgen` 0.59.0 +// Bindings generated by `windows-bindgen` 0.61.0 #![allow(non_snake_case, non_upper_case_globals, non_camel_case_types, dead_code, clippy::all)] @@ -141,7 +141,7 @@ windows_targets::link!("ws2_32.dll" "system" fn setsockopt(s : SOCKET, level : i windows_targets::link!("ws2_32.dll" "system" fn shutdown(s : SOCKET, how : WINSOCK_SHUTDOWN_HOW) -> i32); pub const ABOVE_NORMAL_PRIORITY_CLASS: PROCESS_CREATION_FLAGS = 32768u32; #[repr(C)] -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Default)] pub struct ACL { pub AclRevision: u8, pub Sbz1: u8, @@ -162,6 +162,11 @@ pub struct ADDRINFOA { pub ai_addr: *mut SOCKADDR, pub ai_next: *mut ADDRINFOA, } +impl Default for ADDRINFOA { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} pub const AF_INET: ADDRESS_FAMILY = 2u16; pub const AF_INET6: ADDRESS_FAMILY = 23u16; pub const AF_UNIX: u16 = 1u16; @@ -176,8 +181,13 @@ pub union ARM64_NT_NEON128 { pub H: [u16; 8], pub B: [u8; 16], } +impl Default for ARM64_NT_NEON128 { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[repr(C)] -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Default)] pub struct ARM64_NT_NEON128_0 { pub Low: u64, pub High: i64, @@ -185,7 +195,7 @@ pub struct ARM64_NT_NEON128_0 { pub const BELOW_NORMAL_PRIORITY_CLASS: PROCESS_CREATION_FLAGS = 16384u32; pub type BOOL = i32; #[repr(C)] -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Default)] pub struct BY_HANDLE_FILE_INFORMATION { pub dwFileAttributes: u32, pub ftCreationTime: FILETIME, @@ -206,9 +216,14 @@ pub type COMPARESTRING_RESULT = i32; pub struct CONDITION_VARIABLE { pub Ptr: *mut core::ffi::c_void, } +impl Default for CONDITION_VARIABLE { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} pub type CONSOLE_MODE = u32; #[repr(C)] -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Default)] pub struct CONSOLE_READCONSOLE_CONTROL { pub nLength: u32, pub nInitialChars: u32, @@ -245,6 +260,12 @@ pub struct CONTEXT { pub SegSs: u32, pub ExtendedRegisters: [u8; 512], } +#[cfg(target_arch = "x86")] +impl Default for CONTEXT { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[repr(C)] #[cfg(any(target_arch = "arm64ec", target_arch = "x86_64"))] #[derive(Clone, Copy)] @@ -296,6 +317,12 @@ pub struct CONTEXT { pub LastExceptionToRip: u64, pub LastExceptionFromRip: u64, } +#[cfg(any(target_arch = "arm64ec", target_arch = "x86_64"))] +impl Default for CONTEXT { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[repr(C)] #[cfg(any(target_arch = "arm64ec", target_arch = "x86_64"))] #[derive(Clone, Copy)] @@ -303,6 +330,12 @@ pub union CONTEXT_0 { pub FltSave: XSAVE_FORMAT, pub Anonymous: CONTEXT_0_0, } +#[cfg(any(target_arch = "arm64ec", target_arch = "x86_64"))] +impl Default for CONTEXT_0 { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[repr(C)] #[cfg(any(target_arch = "arm64ec", target_arch = "x86_64"))] #[derive(Clone, Copy)] @@ -326,6 +359,12 @@ pub struct CONTEXT_0_0 { pub Xmm14: M128A, pub Xmm15: M128A, } +#[cfg(any(target_arch = "arm64ec", target_arch = "x86_64"))] +impl Default for CONTEXT_0_0 { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[repr(C)] #[cfg(target_arch = "aarch64")] #[derive(Clone, Copy)] @@ -343,6 +382,12 @@ pub struct CONTEXT { pub Wcr: [u32; 2], pub Wvr: [u64; 2], } +#[cfg(target_arch = "aarch64")] +impl Default for CONTEXT { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[repr(C)] #[cfg(target_arch = "aarch64")] #[derive(Clone, Copy)] @@ -350,9 +395,15 @@ pub union CONTEXT_0 { pub Anonymous: CONTEXT_0_0, pub X: [u64; 31], } +#[cfg(target_arch = "aarch64")] +impl Default for CONTEXT_0 { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[repr(C)] #[cfg(target_arch = "aarch64")] -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Default)] pub struct CONTEXT_0_0 { pub X0: u64, pub X1: u64, @@ -2305,6 +2356,11 @@ pub struct EXCEPTION_POINTERS { pub ExceptionRecord: *mut EXCEPTION_RECORD, pub ContextRecord: *mut CONTEXT, } +impl Default for EXCEPTION_POINTERS { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[repr(C)] #[derive(Clone, Copy)] pub struct EXCEPTION_RECORD { @@ -2315,6 +2371,11 @@ pub struct EXCEPTION_RECORD { pub NumberParameters: u32, pub ExceptionInformation: [usize; 15], } +impl Default for EXCEPTION_RECORD { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} pub const EXCEPTION_STACK_OVERFLOW: NTSTATUS = 0xC00000FD_u32 as _; pub const EXTENDED_STARTUPINFO_PRESENT: PROCESS_CREATION_FLAGS = 524288u32; pub const E_NOTIMPL: HRESULT = 0x80004001_u32 as _; @@ -2333,8 +2394,13 @@ pub struct FD_SET { pub fd_count: u32, pub fd_array: [SOCKET; 64], } +impl Default for FD_SET { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[repr(C)] -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Default)] pub struct FILETIME { pub dwLowDateTime: u32, pub dwHighDateTime: u32, @@ -2343,7 +2409,7 @@ pub type FILE_ACCESS_RIGHTS = u32; pub const FILE_ADD_FILE: FILE_ACCESS_RIGHTS = 2u32; pub const FILE_ADD_SUBDIRECTORY: FILE_ACCESS_RIGHTS = 4u32; #[repr(C)] -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Default)] pub struct FILE_ALLOCATION_INFO { pub AllocationSize: i64, } @@ -2369,7 +2435,7 @@ pub const FILE_ATTRIBUTE_REPARSE_POINT: FILE_FLAGS_AND_ATTRIBUTES = 1024u32; pub const FILE_ATTRIBUTE_SPARSE_FILE: FILE_FLAGS_AND_ATTRIBUTES = 512u32; pub const FILE_ATTRIBUTE_SYSTEM: FILE_FLAGS_AND_ATTRIBUTES = 4u32; #[repr(C)] -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Default)] pub struct FILE_ATTRIBUTE_TAG_INFO { pub FileAttributes: u32, pub ReparseTag: u32, @@ -2378,7 +2444,7 @@ pub const FILE_ATTRIBUTE_TEMPORARY: FILE_FLAGS_AND_ATTRIBUTES = 256u32; pub const FILE_ATTRIBUTE_UNPINNED: FILE_FLAGS_AND_ATTRIBUTES = 1048576u32; pub const FILE_ATTRIBUTE_VIRTUAL: FILE_FLAGS_AND_ATTRIBUTES = 65536u32; #[repr(C)] -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Default)] pub struct FILE_BASIC_INFO { pub CreationTime: i64, pub LastAccessTime: i64, @@ -2405,19 +2471,19 @@ pub const FILE_DISPOSITION_FLAG_IGNORE_READONLY_ATTRIBUTE: FILE_DISPOSITION_INFO pub const FILE_DISPOSITION_FLAG_ON_CLOSE: FILE_DISPOSITION_INFO_EX_FLAGS = 8u32; pub const FILE_DISPOSITION_FLAG_POSIX_SEMANTICS: FILE_DISPOSITION_INFO_EX_FLAGS = 2u32; #[repr(C)] -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Default)] pub struct FILE_DISPOSITION_INFO { pub DeleteFile: bool, } #[repr(C)] -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Default)] pub struct FILE_DISPOSITION_INFO_EX { pub Flags: FILE_DISPOSITION_INFO_EX_FLAGS, } pub type FILE_DISPOSITION_INFO_EX_FLAGS = u32; pub const FILE_END: SET_FILE_POINTER_MOVE_METHOD = 2u32; #[repr(C)] -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Default)] pub struct FILE_END_OF_FILE_INFO { pub EndOfFile: i64, } @@ -2457,9 +2523,14 @@ pub struct FILE_ID_BOTH_DIR_INFO { pub FileId: i64, pub FileName: [u16; 1], } +impl Default for FILE_ID_BOTH_DIR_INFO { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} pub type FILE_INFO_BY_HANDLE_CLASS = i32; #[repr(C)] -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Default)] pub struct FILE_IO_PRIORITY_HINT_INFO { pub PriorityHint: PRIORITY_HINT, } @@ -2494,12 +2565,22 @@ pub struct FILE_RENAME_INFO { pub FileNameLength: u32, pub FileName: [u16; 1], } +impl Default for FILE_RENAME_INFO { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[repr(C)] #[derive(Clone, Copy)] pub union FILE_RENAME_INFO_0 { pub ReplaceIfExists: bool, pub Flags: u32, } +impl Default for FILE_RENAME_INFO_0 { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} pub const FILE_RESERVE_OPFILTER: NTCREATEFILE_CREATE_OPTIONS = 1048576u32; pub const FILE_SEQUENTIAL_ONLY: NTCREATEFILE_CREATE_OPTIONS = 4u32; pub const FILE_SESSION_AWARE: NTCREATEFILE_CREATE_OPTIONS = 262144u32; @@ -2509,7 +2590,7 @@ pub const FILE_SHARE_NONE: FILE_SHARE_MODE = 0u32; pub const FILE_SHARE_READ: FILE_SHARE_MODE = 1u32; pub const FILE_SHARE_WRITE: FILE_SHARE_MODE = 2u32; #[repr(C)] -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Default)] pub struct FILE_STANDARD_INFO { pub AllocationSize: i64, pub EndOfFile: i64, @@ -2549,6 +2630,12 @@ pub struct FLOATING_SAVE_AREA { pub RegisterArea: [u8; 80], pub Spare0: u32, } +#[cfg(target_arch = "x86")] +impl Default for FLOATING_SAVE_AREA { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[repr(C)] #[cfg(any(target_arch = "aarch64", target_arch = "arm64ec", target_arch = "x86_64"))] #[derive(Clone, Copy)] @@ -2563,6 +2650,12 @@ pub struct FLOATING_SAVE_AREA { pub RegisterArea: [u8; 80], pub Cr0NpxState: u32, } +#[cfg(any(target_arch = "aarch64", target_arch = "arm64ec", target_arch = "x86_64"))] +impl Default for FLOATING_SAVE_AREA { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} pub const FORMAT_MESSAGE_ALLOCATE_BUFFER: FORMAT_MESSAGE_OPTIONS = 256u32; pub const FORMAT_MESSAGE_ARGUMENT_ARRAY: FORMAT_MESSAGE_OPTIONS = 8192u32; pub const FORMAT_MESSAGE_FROM_HMODULE: FORMAT_MESSAGE_OPTIONS = 2048u32; @@ -2639,12 +2732,22 @@ pub const IDLE_PRIORITY_CLASS: PROCESS_CREATION_FLAGS = 64u32; pub struct IN6_ADDR { pub u: IN6_ADDR_0, } +impl Default for IN6_ADDR { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[repr(C)] #[derive(Clone, Copy)] pub union IN6_ADDR_0 { pub Byte: [u8; 16], pub Word: [u16; 8], } +impl Default for IN6_ADDR_0 { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} pub const INFINITE: u32 = 4294967295u32; pub const INHERIT_CALLER_PRIORITY: PROCESS_CREATION_FLAGS = 131072u32; pub const INHERIT_PARENT_AFFINITY: PROCESS_CREATION_FLAGS = 65536u32; @@ -2653,6 +2756,11 @@ pub const INHERIT_PARENT_AFFINITY: PROCESS_CREATION_FLAGS = 65536u32; pub union INIT_ONCE { pub Ptr: *mut core::ffi::c_void, } +impl Default for INIT_ONCE { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} pub const INIT_ONCE_INIT_FAILED: u32 = 4u32; pub const INVALID_FILE_ATTRIBUTES: u32 = 4294967295u32; pub const INVALID_SOCKET: SOCKET = -1i32 as _; @@ -2661,6 +2769,11 @@ pub const INVALID_SOCKET: SOCKET = -1i32 as _; pub struct IN_ADDR { pub S_un: IN_ADDR_0, } +impl Default for IN_ADDR { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[repr(C)] #[derive(Clone, Copy)] pub union IN_ADDR_0 { @@ -2668,8 +2781,13 @@ pub union IN_ADDR_0 { pub S_un_w: IN_ADDR_0_1, pub S_addr: u32, } +impl Default for IN_ADDR_0 { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[repr(C)] -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Default)] pub struct IN_ADDR_0_0 { pub s_b1: u8, pub s_b2: u8, @@ -2677,7 +2795,7 @@ pub struct IN_ADDR_0_0 { pub s_b4: u8, } #[repr(C)] -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Default)] pub struct IN_ADDR_0_1 { pub s_w1: u16, pub s_w2: u16, @@ -2690,12 +2808,22 @@ pub struct IO_STATUS_BLOCK { pub Anonymous: IO_STATUS_BLOCK_0, pub Information: usize, } +impl Default for IO_STATUS_BLOCK { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[repr(C)] #[derive(Clone, Copy)] pub union IO_STATUS_BLOCK_0 { pub Status: NTSTATUS, pub Pointer: *mut core::ffi::c_void, } +impl Default for IO_STATUS_BLOCK_0 { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} pub type IPPROTO = i32; pub const IPPROTO_AH: IPPROTO = 51i32; pub const IPPROTO_CBT: IPPROTO = 7i32; @@ -2742,6 +2870,11 @@ pub struct IPV6_MREQ { pub ipv6mr_multiaddr: IN6_ADDR, pub ipv6mr_interface: u32, } +impl Default for IPV6_MREQ { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} pub const IPV6_MULTICAST_LOOP: i32 = 11i32; pub const IPV6_V6ONLY: i32 = 27i32; pub const IP_ADD_MEMBERSHIP: i32 = 12i32; @@ -2752,11 +2885,16 @@ pub struct IP_MREQ { pub imr_multiaddr: IN_ADDR, pub imr_interface: IN_ADDR, } +impl Default for IP_MREQ { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} pub const IP_MULTICAST_LOOP: i32 = 11i32; pub const IP_MULTICAST_TTL: i32 = 10i32; pub const IP_TTL: i32 = 4i32; #[repr(C)] -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Default)] pub struct LINGER { pub l_onoff: u16, pub l_linger: u16, @@ -2797,7 +2935,7 @@ pub type LPWSAOVERLAPPED_COMPLETION_ROUTINE = Option< ), >; #[repr(C)] -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Default)] pub struct M128A { pub Low: u64, pub High: i64, @@ -2838,6 +2976,11 @@ pub struct OBJECT_ATTRIBUTES { pub SecurityDescriptor: *const SECURITY_DESCRIPTOR, pub SecurityQualityOfService: *const SECURITY_QUALITY_OF_SERVICE, } +impl Default for OBJECT_ATTRIBUTES { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} pub type OBJECT_ATTRIBUTE_FLAGS = u32; pub const OBJ_DONT_REPARSE: OBJECT_ATTRIBUTE_FLAGS = 4096u32; pub const OPEN_ALWAYS: FILE_CREATION_DISPOSITION = 4u32; @@ -2850,14 +2993,24 @@ pub struct OVERLAPPED { pub Anonymous: OVERLAPPED_0, pub hEvent: HANDLE, } +impl Default for OVERLAPPED { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[repr(C)] #[derive(Clone, Copy)] pub union OVERLAPPED_0 { pub Anonymous: OVERLAPPED_0_0, pub Pointer: *mut core::ffi::c_void, } +impl Default for OVERLAPPED_0 { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[repr(C)] -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Default)] pub struct OVERLAPPED_0_0 { pub Offset: u32, pub OffsetHigh: u32, @@ -2895,6 +3048,11 @@ pub struct PROCESS_INFORMATION { pub dwProcessId: u32, pub dwThreadId: u32, } +impl Default for PROCESS_INFORMATION { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} pub const PROCESS_MODE_BACKGROUND_BEGIN: PROCESS_CREATION_FLAGS = 1048576u32; pub const PROCESS_MODE_BACKGROUND_END: PROCESS_CREATION_FLAGS = 2097152u32; pub const PROFILE_KERNEL: PROCESS_CREATION_FLAGS = 536870912u32; @@ -2926,6 +3084,11 @@ pub struct SECURITY_ATTRIBUTES { pub lpSecurityDescriptor: *mut core::ffi::c_void, pub bInheritHandle: BOOL, } +impl Default for SECURITY_ATTRIBUTES { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} pub const SECURITY_CONTEXT_TRACKING: FILE_FLAGS_AND_ATTRIBUTES = 262144u32; pub const SECURITY_DELEGATION: FILE_FLAGS_AND_ATTRIBUTES = 196608u32; #[repr(C)] @@ -2939,13 +3102,18 @@ pub struct SECURITY_DESCRIPTOR { pub Sacl: *mut ACL, pub Dacl: *mut ACL, } +impl Default for SECURITY_DESCRIPTOR { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} pub type SECURITY_DESCRIPTOR_CONTROL = u16; pub const SECURITY_EFFECTIVE_ONLY: FILE_FLAGS_AND_ATTRIBUTES = 524288u32; pub const SECURITY_IDENTIFICATION: FILE_FLAGS_AND_ATTRIBUTES = 65536u32; pub const SECURITY_IMPERSONATION: FILE_FLAGS_AND_ATTRIBUTES = 131072u32; pub type SECURITY_IMPERSONATION_LEVEL = i32; #[repr(C)] -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Default)] pub struct SECURITY_QUALITY_OF_SERVICE { pub Length: u32, pub ImpersonationLevel: SECURITY_IMPERSONATION_LEVEL, @@ -2962,6 +3130,11 @@ pub struct SOCKADDR { pub sa_family: ADDRESS_FAMILY, pub sa_data: [i8; 14], } +impl Default for SOCKADDR { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[repr(C)] #[derive(Clone, Copy)] pub struct SOCKADDR_STORAGE { @@ -2970,12 +3143,22 @@ pub struct SOCKADDR_STORAGE { pub __ss_align: i64, pub __ss_pad2: [i8; 112], } +impl Default for SOCKADDR_STORAGE { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[repr(C)] #[derive(Clone, Copy)] pub struct SOCKADDR_UN { pub sun_family: ADDRESS_FAMILY, pub sun_path: [i8; 108], } +impl Default for SOCKADDR_UN { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} pub type SOCKET = usize; pub const SOCKET_ERROR: i32 = -1i32; pub const SOCK_DGRAM: WINSOCK_SOCKET_TYPE = 2i32; @@ -2995,6 +3178,11 @@ pub const SPECIFIC_RIGHTS_ALL: FILE_ACCESS_RIGHTS = 65535u32; pub struct SRWLOCK { pub Ptr: *mut core::ffi::c_void, } +impl Default for SRWLOCK { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} pub const STACK_SIZE_PARAM_IS_A_RESERVATION: THREAD_CREATION_FLAGS = 65536u32; pub const STANDARD_RIGHTS_ALL: FILE_ACCESS_RIGHTS = 2031616u32; pub const STANDARD_RIGHTS_EXECUTE: FILE_ACCESS_RIGHTS = 131072u32; @@ -3021,6 +3209,11 @@ pub struct STARTUPINFOEXW { pub StartupInfo: STARTUPINFOW, pub lpAttributeList: LPPROC_THREAD_ATTRIBUTE_LIST, } +impl Default for STARTUPINFOEXW { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[repr(C)] #[derive(Clone, Copy)] pub struct STARTUPINFOW { @@ -3043,6 +3236,11 @@ pub struct STARTUPINFOW { pub hStdOutput: HANDLE, pub hStdError: HANDLE, } +impl Default for STARTUPINFOW { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} pub type STARTUPINFOW_FLAGS = u32; pub const STATUS_DELETE_PENDING: NTSTATUS = 0xC0000056_u32 as _; pub const STATUS_DIRECTORY_NOT_EMPTY: NTSTATUS = 0xC0000101_u32 as _; @@ -3078,14 +3276,24 @@ pub struct SYSTEM_INFO { pub wProcessorLevel: u16, pub wProcessorRevision: u16, } +impl Default for SYSTEM_INFO { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[repr(C)] #[derive(Clone, Copy)] pub union SYSTEM_INFO_0 { pub dwOemId: u32, pub Anonymous: SYSTEM_INFO_0_0, } +impl Default for SYSTEM_INFO_0 { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[repr(C)] -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Default)] pub struct SYSTEM_INFO_0_0 { pub wProcessorArchitecture: PROCESSOR_ARCHITECTURE, pub wReserved: u16, @@ -3097,7 +3305,7 @@ pub type THREAD_CREATION_FLAGS = u32; pub const TIMER_ALL_ACCESS: SYNCHRONIZATION_ACCESS_RIGHTS = 2031619u32; pub const TIMER_MODIFY_STATE: SYNCHRONIZATION_ACCESS_RIGHTS = 2u32; #[repr(C)] -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Default)] pub struct TIMEVAL { pub tv_sec: i32, pub tv_usec: i32, @@ -3134,6 +3342,11 @@ pub struct UNICODE_STRING { pub MaximumLength: u16, pub Buffer: PWSTR, } +impl Default for UNICODE_STRING { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} pub const VOLUME_NAME_DOS: GETFINALPATHNAMEBYHANDLE_FLAGS = 0u32; pub const VOLUME_NAME_GUID: GETFINALPATHNAMEBYHANDLE_FLAGS = 1u32; pub const VOLUME_NAME_NONE: GETFINALPATHNAMEBYHANDLE_FLAGS = 4u32; @@ -3160,6 +3373,11 @@ pub struct WIN32_FIND_DATAW { pub cFileName: [u16; 260], pub cAlternateFileName: [u16; 14], } +impl Default for WIN32_FIND_DATAW { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} pub type WINSOCK_SHUTDOWN_HOW = i32; pub type WINSOCK_SOCKET_TYPE = i32; pub const WRITE_DAC: FILE_ACCESS_RIGHTS = 262144u32; @@ -3171,6 +3389,11 @@ pub struct WSABUF { pub len: u32, pub buf: PSTR, } +impl Default for WSABUF { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[repr(C)] #[cfg(target_arch = "x86")] #[derive(Clone, Copy)] @@ -3183,6 +3406,12 @@ pub struct WSADATA { pub iMaxUdpDg: u16, pub lpVendorInfo: PSTR, } +#[cfg(target_arch = "x86")] +impl Default for WSADATA { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[repr(C)] #[cfg(any(target_arch = "aarch64", target_arch = "arm64ec", target_arch = "x86_64"))] #[derive(Clone, Copy)] @@ -3195,6 +3424,12 @@ pub struct WSADATA { pub szDescription: [i8; 257], pub szSystemStatus: [i8; 129], } +#[cfg(any(target_arch = "aarch64", target_arch = "arm64ec", target_arch = "x86_64"))] +impl Default for WSADATA { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} pub const WSAEACCES: WSA_ERROR = 10013i32; pub const WSAEADDRINUSE: WSA_ERROR = 10048i32; pub const WSAEADDRNOTAVAIL: WSA_ERROR = 10049i32; @@ -3255,6 +3490,11 @@ pub struct WSAPROTOCOLCHAIN { pub ChainLen: i32, pub ChainEntries: [u32; 7], } +impl Default for WSAPROTOCOLCHAIN { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[repr(C)] #[derive(Clone, Copy)] pub struct WSAPROTOCOL_INFOW { @@ -3279,6 +3519,11 @@ pub struct WSAPROTOCOL_INFOW { pub dwProviderReserved: u32, pub szProtocol: [u16; 256], } +impl Default for WSAPROTOCOL_INFOW { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} pub const WSASERVICE_NOT_FOUND: WSA_ERROR = 10108i32; pub const WSASYSCALLFAILURE: WSA_ERROR = 10107i32; pub const WSASYSNOTREADY: WSA_ERROR = 10091i32; @@ -3348,6 +3593,12 @@ pub struct XSAVE_FORMAT { pub XmmRegisters: [M128A; 8], pub Reserved4: [u8; 224], } +#[cfg(target_arch = "x86")] +impl Default for XSAVE_FORMAT { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[repr(C)] #[cfg(any(target_arch = "aarch64", target_arch = "arm64ec", target_arch = "x86_64"))] #[derive(Clone, Copy)] @@ -3369,6 +3620,12 @@ pub struct XSAVE_FORMAT { pub XmmRegisters: [M128A; 16], pub Reserved4: [u8; 96], } +#[cfg(any(target_arch = "aarch64", target_arch = "arm64ec", target_arch = "x86_64"))] +impl Default for XSAVE_FORMAT { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[cfg(target_arch = "arm")] #[repr(C)] diff --git a/library/std/src/sys/pal/windows/mod.rs b/library/std/src/sys/pal/windows/mod.rs index bdf0cc2c59cf..3c0a5c2de263 100644 --- a/library/std/src/sys/pal/windows/mod.rs +++ b/library/std/src/sys/pal/windows/mod.rs @@ -14,7 +14,6 @@ pub mod compat; pub mod api; -pub mod args; pub mod c; pub mod env; #[cfg(not(target_vendor = "win7"))] diff --git a/library/std/src/sys/pal/xous/args.rs b/library/std/src/sys/pal/xous/args.rs deleted file mode 100644 index 00c44ca220a9..000000000000 --- a/library/std/src/sys/pal/xous/args.rs +++ /dev/null @@ -1,53 +0,0 @@ -use crate::ffi::OsString; -use crate::sys::pal::xous::os::get_application_parameters; -use crate::sys::pal::xous::os::params::ArgumentList; -use crate::{fmt, vec}; - -pub struct Args { - parsed_args_list: vec::IntoIter, -} - -pub fn args() -> Args { - let Some(params) = get_application_parameters() else { - return Args { parsed_args_list: vec![].into_iter() }; - }; - - for param in params { - if let Ok(args) = ArgumentList::try_from(¶m) { - let mut parsed_args = vec![]; - for arg in args { - parsed_args.push(arg.into()); - } - return Args { parsed_args_list: parsed_args.into_iter() }; - } - } - Args { parsed_args_list: vec![].into_iter() } -} - -impl fmt::Debug for Args { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.parsed_args_list.as_slice().fmt(f) - } -} - -impl Iterator for Args { - type Item = OsString; - fn next(&mut self) -> Option { - self.parsed_args_list.next() - } - fn size_hint(&self) -> (usize, Option) { - self.parsed_args_list.size_hint() - } -} - -impl DoubleEndedIterator for Args { - fn next_back(&mut self) -> Option { - self.parsed_args_list.next_back() - } -} - -impl ExactSizeIterator for Args { - fn len(&self) -> usize { - self.parsed_args_list.len() - } -} diff --git a/library/std/src/sys/pal/xous/mod.rs b/library/std/src/sys/pal/xous/mod.rs index 58926e2beb1d..4f652d3f130d 100644 --- a/library/std/src/sys/pal/xous/mod.rs +++ b/library/std/src/sys/pal/xous/mod.rs @@ -1,6 +1,5 @@ #![forbid(unsafe_op_in_unsafe_fn)] -pub mod args; #[path = "../unsupported/env.rs"] pub mod env; pub mod os; diff --git a/library/std/src/sys/pal/zkvm/mod.rs b/library/std/src/sys/pal/zkvm/mod.rs index 4659dad16e85..ebd7b0367798 100644 --- a/library/std/src/sys/pal/zkvm/mod.rs +++ b/library/std/src/sys/pal/zkvm/mod.rs @@ -8,11 +8,9 @@ //! will likely change over time. #![forbid(unsafe_op_in_unsafe_fn)] -const WORD_SIZE: usize = size_of::(); +pub const WORD_SIZE: usize = size_of::(); pub mod abi; -#[path = "../zkvm/args.rs"] -pub mod args; pub mod env; pub mod os; #[path = "../unsupported/pipe.rs"] diff --git a/library/std/src/sys/path/windows.rs b/library/std/src/sys/path/windows.rs index 1c5347219169..e0e003f6a819 100644 --- a/library/std/src/sys/path/windows.rs +++ b/library/std/src/sys/path/windows.rs @@ -10,6 +10,40 @@ mod tests; pub const MAIN_SEP_STR: &str = "\\"; pub const MAIN_SEP: char = '\\'; +/// A null terminated wide string. +#[repr(transparent)] +pub struct WCStr([u16]); + +impl WCStr { + /// Convert a slice to a WCStr without checks. + /// + /// Though it is memory safe, the slice should also not contain interior nulls + /// as this may lead to unwanted truncation. + /// + /// # Safety + /// + /// The slice must end in a null. + pub unsafe fn from_wchars_with_null_unchecked(s: &[u16]) -> &Self { + unsafe { &*(s as *const [u16] as *const Self) } + } + + pub fn as_ptr(&self) -> *const u16 { + self.0.as_ptr() + } + + pub fn count_bytes(&self) -> usize { + self.0.len() + } +} + +#[inline] +pub fn with_native_path(path: &Path, f: &dyn Fn(&WCStr) -> io::Result) -> io::Result { + let path = maybe_verbatim(path)?; + // SAFETY: maybe_verbatim returns null-terminated strings + let path = unsafe { WCStr::from_wchars_with_null_unchecked(&path) }; + f(path) +} + #[inline] pub fn is_sep_byte(b: u8) -> bool { b == b'/' || b == b'\\' @@ -350,3 +384,46 @@ pub(crate) fn absolute(path: &Path) -> io::Result { pub(crate) fn is_absolute(path: &Path) -> bool { path.has_root() && path.prefix().is_some() } + +/// Test that the path is absolute, fully qualified and unchanged when processed by the Windows API. +/// +/// For example: +/// +/// - `C:\path\to\file` will return true. +/// - `C:\path\to\nul` returns false because the Windows API will convert it to \\.\NUL +/// - `C:\path\to\..\file` returns false because it will be resolved to `C:\path\file`. +/// +/// This is a useful property because it means the path can be converted from and to and verbatim +/// path just by changing the prefix. +pub(crate) fn is_absolute_exact(path: &[u16]) -> bool { + // This is implemented by checking that passing the path through + // GetFullPathNameW does not change the path in any way. + + // Windows paths are limited to i16::MAX length + // though the API here accepts a u32 for the length. + if path.is_empty() || path.len() > u32::MAX as usize || path.last() != Some(&0) { + return false; + } + // The path returned by `GetFullPathNameW` must be the same length as the + // given path, otherwise they're not equal. + let buffer_len = path.len(); + let mut new_path = Vec::with_capacity(buffer_len); + let result = unsafe { + c::GetFullPathNameW( + path.as_ptr(), + new_path.capacity() as u32, + new_path.as_mut_ptr(), + crate::ptr::null_mut(), + ) + }; + // Note: if non-zero, the returned result is the length of the buffer without the null termination + if result == 0 || result as usize != buffer_len - 1 { + false + } else { + // SAFETY: `GetFullPathNameW` initialized `result` bytes and does not exceed `nBufferLength - 1` (capacity). + unsafe { + new_path.set_len((result as usize) + 1); + } + path == &new_path + } +} diff --git a/library/std/src/sys/path/windows/tests.rs b/library/std/src/sys/path/windows/tests.rs index f2a60e30bc61..9eb79203dcac 100644 --- a/library/std/src/sys/path/windows/tests.rs +++ b/library/std/src/sys/path/windows/tests.rs @@ -135,3 +135,15 @@ fn broken_unc_path() { assert_eq!(components.next(), Some(Component::Normal("foo".as_ref()))); assert_eq!(components.next(), Some(Component::Normal("bar".as_ref()))); } + +#[test] +fn test_is_absolute_exact() { + use crate::sys::pal::api::wide_str; + // These paths can be made verbatim by only changing their prefix. + assert!(is_absolute_exact(wide_str!(r"C:\path\to\file"))); + assert!(is_absolute_exact(wide_str!(r"\\server\share\path\to\file"))); + // These paths change more substantially + assert!(!is_absolute_exact(wide_str!(r"C:\path\to\..\file"))); + assert!(!is_absolute_exact(wide_str!(r"\\server\share\path\to\..\file"))); + assert!(!is_absolute_exact(wide_str!(r"C:\path\to\NUL"))); // Converts to \\.\NUL +} diff --git a/library/std/src/sys/process/uefi.rs b/library/std/src/sys/process/uefi.rs index b46418ae9bb6..5f922292d054 100644 --- a/library/std/src/sys/process/uefi.rs +++ b/library/std/src/sys/process/uefi.rs @@ -1,4 +1,4 @@ -use r_efi::protocols::simple_text_output; +use r_efi::protocols::{simple_text_input, simple_text_output}; use crate::collections::BTreeMap; pub use crate::ffi::OsString as EnvKey; @@ -23,6 +23,7 @@ pub struct Command { args: Vec, stdout: Option, stderr: Option, + stdin: Option, env: CommandEnv, } @@ -48,6 +49,7 @@ impl Command { args: Vec::new(), stdout: None, stderr: None, + stdin: None, env: Default::default(), } } @@ -64,8 +66,8 @@ impl Command { panic!("unsupported") } - pub fn stdin(&mut self, _stdin: Stdio) { - panic!("unsupported") + pub fn stdin(&mut self, stdin: Stdio) { + self.stdin = Some(stdin); } pub fn stdout(&mut self, stdout: Stdio) { @@ -122,6 +124,22 @@ impl Command { } } + fn create_stdin( + s: Stdio, + ) -> io::Result>> { + match s { + Stdio::Null => unsafe { + helpers::OwnedProtocol::create( + uefi_command_internal::InputProtocol::null(), + simple_text_input::PROTOCOL_GUID, + ) + } + .map(Some), + Stdio::Inherit => Ok(None), + Stdio::MakePipe => unsupported(), + } + } + pub fn output(&mut self) -> io::Result<(ExitStatus, Vec, Vec)> { let mut cmd = uefi_command_internal::Image::load_image(&self.prog)?; @@ -149,6 +167,15 @@ impl Command { cmd.stderr_inherit() }; + // Setup Stdin + let stdin = self.stdin.unwrap_or(Stdio::Null); + let stdin = Self::create_stdin(stdin)?; + if let Some(con) = stdin { + cmd.stdin_init(con) + } else { + cmd.stdin_inherit() + }; + let env = env_changes(&self.env); // Set any new vars @@ -334,7 +361,7 @@ impl<'a> fmt::Debug for CommandArgs<'a> { #[allow(dead_code)] mod uefi_command_internal { - use r_efi::protocols::{loaded_image, simple_text_output}; + use r_efi::protocols::{loaded_image, simple_text_input, simple_text_output}; use crate::ffi::{OsStr, OsString}; use crate::io::{self, const_error}; @@ -350,6 +377,7 @@ mod uefi_command_internal { handle: NonNull, stdout: Option>, stderr: Option>, + stdin: Option>, st: OwnedTable, args: Option<(*mut u16, usize)>, } @@ -384,7 +412,14 @@ mod uefi_command_internal { helpers::open_protocol(child_handle, loaded_image::PROTOCOL_GUID).unwrap(); let st = OwnedTable::from_table(unsafe { (*loaded_image.as_ptr()).system_table }); - Ok(Self { handle: child_handle, stdout: None, stderr: None, st, args: None }) + Ok(Self { + handle: child_handle, + stdout: None, + stderr: None, + stdin: None, + st, + args: None, + }) } } @@ -445,6 +480,17 @@ mod uefi_command_internal { } } + fn set_stdin( + &mut self, + handle: r_efi::efi::Handle, + protocol: *mut simple_text_input::Protocol, + ) { + unsafe { + (*self.st.as_mut_ptr()).console_in_handle = handle; + (*self.st.as_mut_ptr()).con_in = protocol; + } + } + pub fn stdout_init(&mut self, protocol: helpers::OwnedProtocol) { self.set_stdout( protocol.handle().as_ptr(), @@ -471,6 +517,19 @@ mod uefi_command_internal { unsafe { self.set_stderr((*st.as_ptr()).standard_error_handle, (*st.as_ptr()).std_err) } } + pub(crate) fn stdin_init(&mut self, protocol: helpers::OwnedProtocol) { + self.set_stdin( + protocol.handle().as_ptr(), + protocol.as_ref() as *const InputProtocol as *mut simple_text_input::Protocol, + ); + self.stdin = Some(protocol); + } + + pub(crate) fn stdin_inherit(&mut self) { + let st: NonNull = system_table().cast(); + unsafe { self.set_stdin((*st.as_ptr()).console_in_handle, (*st.as_ptr()).con_in) } + } + pub fn stderr(&self) -> io::Result> { match &self.stderr { Some(stderr) => stderr.as_ref().utf8(), @@ -722,6 +781,56 @@ mod uefi_command_internal { } } + #[repr(C)] + pub(crate) struct InputProtocol { + reset: simple_text_input::ProtocolReset, + read_key_stroke: simple_text_input::ProtocolReadKeyStroke, + wait_for_key: r_efi::efi::Event, + } + + impl InputProtocol { + pub(crate) fn null() -> Self { + let evt = helpers::OwnedEvent::new( + r_efi::efi::EVT_NOTIFY_WAIT, + r_efi::efi::TPL_CALLBACK, + Some(Self::empty_notify), + None, + ) + .unwrap(); + + Self { + reset: Self::null_reset, + read_key_stroke: Self::null_read_key, + wait_for_key: evt.into_raw(), + } + } + + extern "efiapi" fn null_reset( + _: *mut simple_text_input::Protocol, + _: r_efi::efi::Boolean, + ) -> r_efi::efi::Status { + r_efi::efi::Status::SUCCESS + } + + extern "efiapi" fn null_read_key( + _: *mut simple_text_input::Protocol, + _: *mut simple_text_input::InputKey, + ) -> r_efi::efi::Status { + r_efi::efi::Status::UNSUPPORTED + } + + extern "efiapi" fn empty_notify(_: r_efi::efi::Event, _: *mut crate::ffi::c_void) {} + } + + impl Drop for InputProtocol { + fn drop(&mut self) { + // Close wait_for_key + unsafe { + let _ = helpers::OwnedEvent::from_raw(self.wait_for_key); + } + } + } + pub fn create_args(prog: &OsStr, args: &[OsString]) -> Box<[u16]> { const QUOTE: u16 = 0x0022; const SPACE: u16 = 0x0020; diff --git a/library/std/src/sys/process/unix/unix.rs b/library/std/src/sys/process/unix/unix.rs index 191a09c8da91..3b04ec50db30 100644 --- a/library/std/src/sys/process/unix/unix.rs +++ b/library/std/src/sys/process/unix/unix.rs @@ -434,9 +434,6 @@ impl Command { target_os = "nto", target_vendor = "apple", ))] - // FIXME(#115199): Rust currently omits weak function definitions - // and its metadata from LLVM IR. - #[cfg_attr(target_os = "linux", no_sanitize(cfi))] fn posix_spawn( &mut self, stdio: &ChildPipes, diff --git a/library/std/src/sys/process/windows.rs b/library/std/src/sys/process/windows.rs index 06c15e08f3fb..4cfdf908c58d 100644 --- a/library/std/src/sys/process/windows.rs +++ b/library/std/src/sys/process/windows.rs @@ -19,7 +19,7 @@ use crate::sys::args::{self, Arg}; use crate::sys::c::{self, EXIT_FAILURE, EXIT_SUCCESS}; use crate::sys::fs::{File, OpenOptions}; use crate::sys::handle::Handle; -use crate::sys::pal::api::{self, WinError}; +use crate::sys::pal::api::{self, WinError, utf16}; use crate::sys::pal::{ensure_no_nuls, fill_utf16_buf}; use crate::sys::pipe::{self, AnonPipe}; use crate::sys::{cvt, path, stdio}; @@ -880,9 +880,33 @@ fn make_envp(maybe_env: Option>) -> io::Result<(*mut fn make_dirp(d: Option<&OsString>) -> io::Result<(*const u16, Vec)> { match d { Some(dir) => { - let mut dir_str: Vec = ensure_no_nuls(dir)?.encode_wide().collect(); - dir_str.push(0); - Ok((dir_str.as_ptr(), dir_str)) + let mut dir_str: Vec = ensure_no_nuls(dir)?.encode_wide().chain([0]).collect(); + // Try to remove the `\\?\` prefix, if any. + // This is necessary because the current directory does not support verbatim paths. + // However. this can only be done if it doesn't change how the path will be resolved. + let ptr = if dir_str.starts_with(utf16!(r"\\?\UNC")) { + // Turn the `C` in `UNC` into a `\` so we can then use `\\rest\of\path`. + let start = r"\\?\UN".len(); + dir_str[start] = b'\\' as u16; + if path::is_absolute_exact(&dir_str[start..]) { + dir_str[start..].as_ptr() + } else { + // Revert the above change. + dir_str[start] = b'C' as u16; + dir_str.as_ptr() + } + } else if dir_str.starts_with(utf16!(r"\\?\")) { + // Strip the leading `\\?\` + let start = r"\\?\".len(); + if path::is_absolute_exact(&dir_str[start..]) { + dir_str[start..].as_ptr() + } else { + dir_str.as_ptr() + } + } else { + dir_str.as_ptr() + }; + Ok((ptr, dir_str)) } None => Ok((ptr::null(), Vec::new())), } diff --git a/library/std/src/sys/stdio/uefi.rs b/library/std/src/sys/stdio/uefi.rs index 257e321dd03d..ccd6bf658b0f 100644 --- a/library/std/src/sys/stdio/uefi.rs +++ b/library/std/src/sys/stdio/uefi.rs @@ -142,8 +142,12 @@ impl io::Write for Stderr { // UTF-16 character should occupy 4 bytes at most in UTF-8 pub const STDIN_BUF_SIZE: usize = 4; -pub fn is_ebadf(_err: &io::Error) -> bool { - false +pub fn is_ebadf(err: &io::Error) -> bool { + if let Some(x) = err.raw_os_error() { + r_efi::efi::Status::UNSUPPORTED.as_usize() == x + } else { + false + } } pub fn panic_output() -> Option { diff --git a/library/std/src/sys/thread_local/destructors/linux_like.rs b/library/std/src/sys/thread_local/destructors/linux_like.rs index 817941229eef..d7cbaeb89f42 100644 --- a/library/std/src/sys/thread_local/destructors/linux_like.rs +++ b/library/std/src/sys/thread_local/destructors/linux_like.rs @@ -12,9 +12,6 @@ use crate::mem::transmute; -// FIXME: The Rust compiler currently omits weakly function definitions (i.e., -// __cxa_thread_atexit_impl) and its metadata from LLVM IR. -#[no_sanitize(cfi, kcfi)] pub unsafe fn register(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) { /// This is necessary because the __cxa_thread_atexit_impl implementation /// std links to by default may be a C or C++ implementation that was not diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index 3f3ba02361cc..2097f1e304ce 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -1676,6 +1676,7 @@ impl fmt::Debug for Thread { /// [`Result`]: crate::result::Result /// [`std::panic::resume_unwind`]: crate::panic::resume_unwind #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(bootstrap), doc(search_unbox))] pub type Result = crate::result::Result>; // This packet is used to communicate the return value between the spawned diff --git a/library/std/tests/sync/mpmc.rs b/library/std/tests/sync/mpmc.rs index 81b92297f76a..78abcb3bcbe1 100644 --- a/library/std/tests/sync/mpmc.rs +++ b/library/std/tests/sync/mpmc.rs @@ -63,6 +63,24 @@ fn smoke_port_gone() { assert!(tx.send(1).is_err()); } +#[test] +fn smoke_receiver_clone() { + let (tx, rx) = channel::(); + let rx2 = rx.clone(); + drop(rx); + tx.send(1).unwrap(); + assert_eq!(rx2.recv().unwrap(), 1); +} + +#[test] +fn smoke_receiver_clone_port_gone() { + let (tx, rx) = channel::(); + let rx2 = rx.clone(); + drop(rx); + drop(rx2); + assert!(tx.send(1).is_err()); +} + #[test] fn smoke_shared_port_gone() { let (tx, rx) = channel::(); @@ -124,6 +142,18 @@ fn chan_gone_concurrent() { while rx.recv().is_ok() {} } +#[test] +fn receiver_cloning() { + let (tx, rx) = channel::(); + let rx2 = rx.clone(); + + tx.send(1).unwrap(); + tx.send(2).unwrap(); + + assert_eq!(rx2.recv(), Ok(1)); + assert_eq!(rx.recv(), Ok(2)); +} + #[test] fn stress() { let count = if cfg!(miri) { 100 } else { 10000 }; diff --git a/library/stdarch b/library/stdarch index 9426bb56586c..4666c7376f25 160000 --- a/library/stdarch +++ b/library/stdarch @@ -1 +1 @@ -Subproject commit 9426bb56586c6ae4095a2dcbd66c570253e6fb32 +Subproject commit 4666c7376f25a265c74535585d622da3da6dfeb1 diff --git a/library/test/src/lib.rs b/library/test/src/lib.rs index 7ada3f269a00..acaf026c679b 100644 --- a/library/test/src/lib.rs +++ b/library/test/src/lib.rs @@ -666,10 +666,11 @@ fn run_test_in_process( io::set_output_capture(None); - let test_result = match result { - Ok(()) => calc_result(&desc, Ok(()), time_opts.as_ref(), exec_time.as_ref()), - Err(e) => calc_result(&desc, Err(e.as_ref()), time_opts.as_ref(), exec_time.as_ref()), - }; + // Determine whether the test passed or failed, by comparing its panic + // payload (if any) with its `ShouldPanic` value, and by checking for + // fatal timeout. + let test_result = + calc_result(&desc, result.err().as_deref(), time_opts.as_ref(), exec_time.as_ref()); let stdout = data.lock().unwrap_or_else(|e| e.into_inner()).to_vec(); let message = CompletedTest::new(id, desc, test_result, exec_time, stdout); monitor_ch.send(message).unwrap(); @@ -741,10 +742,7 @@ fn spawn_test_subprocess( fn run_test_in_spawned_subprocess(desc: TestDesc, runnable_test: RunnableTest) -> ! { let builtin_panic_hook = panic::take_hook(); let record_result = Arc::new(move |panic_info: Option<&'_ PanicHookInfo<'_>>| { - let test_result = match panic_info { - Some(info) => calc_result(&desc, Err(info.payload()), None, None), - None => calc_result(&desc, Ok(()), None, None), - }; + let test_result = calc_result(&desc, panic_info.map(|info| info.payload()), None, None); // We don't support serializing TrFailedMsg, so just // print the message out to stderr. diff --git a/library/test/src/test_result.rs b/library/test/src/test_result.rs index 73dcc2e2a0cc..a312894c25c4 100644 --- a/library/test/src/test_result.rs +++ b/library/test/src/test_result.rs @@ -39,15 +39,18 @@ pub enum TestResult { /// Creates a `TestResult` depending on the raw result of test execution /// and associated data. -pub(crate) fn calc_result<'a>( +pub(crate) fn calc_result( desc: &TestDesc, - task_result: Result<(), &'a (dyn Any + 'static + Send)>, + panic_payload: Option<&(dyn Any + Send)>, time_opts: Option<&time::TestTimeOptions>, exec_time: Option<&time::TestExecTime>, ) -> TestResult { - let result = match (&desc.should_panic, task_result) { - (&ShouldPanic::No, Ok(())) | (&ShouldPanic::Yes, Err(_)) => TestResult::TrOk, - (&ShouldPanic::YesWithMessage(msg), Err(err)) => { + let result = match (desc.should_panic, panic_payload) { + // The test did or didn't panic, as expected. + (ShouldPanic::No, None) | (ShouldPanic::Yes, Some(_)) => TestResult::TrOk, + + // Check the actual panic message against the expected message. + (ShouldPanic::YesWithMessage(msg), Some(err)) => { let maybe_panic_str = err .downcast_ref::() .map(|e| &**e) @@ -71,10 +74,19 @@ pub(crate) fn calc_result<'a>( )) } } - (&ShouldPanic::Yes, Ok(())) | (&ShouldPanic::YesWithMessage(_), Ok(())) => { - TestResult::TrFailedMsg("test did not panic as expected".to_string()) + + // The test should have panicked, but didn't panic. + (ShouldPanic::Yes, None) | (ShouldPanic::YesWithMessage(_), None) => { + let fn_location = if !desc.source_file.is_empty() { + &format!(" at {}:{}:{}", desc.source_file, desc.start_line, desc.start_col) + } else { + "" + }; + TestResult::TrFailedMsg(format!("test did not panic as expected{}", fn_location)) } - _ => TestResult::TrFailed, + + // The test should not have panicked, but did panic. + (ShouldPanic::No, Some(_)) => TestResult::TrFailed, }; // If test is already failed (or allowed to fail), do not change the result. diff --git a/rustfmt.toml b/rustfmt.toml index c884a33729c4..7c384b876bf7 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -53,4 +53,8 @@ ignore = [ # Code automatically generated and included. "compiler/rustc_codegen_gcc/src/intrinsic/archs.rs", "compiler/rustc_codegen_gcc/example", + + # Rustfmt doesn't support use closures yet + "tests/mir-opt/ergonomic-clones/closure.rs", + "tests/codegen/ergonomic-clones/closure.rs", ] diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 140f601253c3..42ad14a81d02 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -1331,7 +1331,7 @@ def bootstrap(args): build.check_vendored_status() if not os.path.exists(build.build_dir): - os.makedirs(build.build_dir) + os.makedirs(os.path.realpath(build.build_dir)) # Fetch/build the bootstrap build.download_toolchain() diff --git a/src/bootstrap/defaults/bootstrap.dist.toml b/src/bootstrap/defaults/bootstrap.dist.toml index 7b381b416ca8..f0cb34eb4585 100644 --- a/src/bootstrap/defaults/bootstrap.dist.toml +++ b/src/bootstrap/defaults/bootstrap.dist.toml @@ -7,6 +7,8 @@ test-stage = 2 doc-stage = 2 # When compiling from source, you usually want all tools. extended = true +# Use libtest built from the source tree instead of the precompiled one from stage 0. +compiletest-use-stage0-libtest = false # Most users installing from source want to build all parts of the project from source. [llvm] @@ -15,7 +17,7 @@ download-ci-llvm = false [rust] # We have several defaults in bootstrap that depend on whether the channel is `dev` (e.g. `omit-git-hash` and `download-ci-llvm`). # Make sure they don't get set when installing from source. -channel = "nightly" +channel = "auto-detect" # Never download a rustc, distributions must build a fresh compiler. download-rustc = false lld = true diff --git a/src/bootstrap/download-ci-llvm-stamp b/src/bootstrap/download-ci-llvm-stamp index e157ff233bbf..b70d452b427c 100644 --- a/src/bootstrap/download-ci-llvm-stamp +++ b/src/bootstrap/download-ci-llvm-stamp @@ -1,4 +1,4 @@ Change this file to make users of the `download-ci-llvm` configuration download a new version of LLVM from CI, even if the LLVM submodule hasn’t changed. -Last change is for: https://github.com/rust-lang/rust/pull/138784 +Last change is for: https://github.com/rust-lang/rust/pull/139931 diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs index e67bc62a6035..ae9511b78674 100644 --- a/src/bootstrap/src/core/build_steps/check.rs +++ b/src/bootstrap/src/core/build_steps/check.rs @@ -3,7 +3,7 @@ use crate::core::build_steps::compile::{ add_to_sysroot, run_cargo, rustc_cargo, rustc_cargo_env, std_cargo, std_crates_for_run_make, }; -use crate::core::build_steps::tool::{SourceType, prepare_tool_cargo}; +use crate::core::build_steps::tool::{COMPILETEST_ALLOW_FEATURES, SourceType, prepare_tool_cargo}; use crate::core::builder::{ self, Alias, Builder, Kind, RunConfig, ShouldRun, Step, crate_description, }; @@ -369,6 +369,69 @@ impl Step for RustAnalyzer { } } +/// Compiletest is implicitly "checked" when it gets built in order to run tests, +/// so this is mainly for people working on compiletest to run locally. +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct Compiletest { + pub target: TargetSelection, +} + +impl Step for Compiletest { + type Output = (); + const ONLY_HOSTS: bool = true; + const DEFAULT: bool = false; + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.path("src/tools/compiletest") + } + + fn make_run(run: RunConfig<'_>) { + run.builder.ensure(Compiletest { target: run.target }); + } + + fn run(self, builder: &Builder<'_>) { + let mode = if builder.config.compiletest_use_stage0_libtest { + Mode::ToolBootstrap + } else { + Mode::ToolStd + }; + + let compiler = builder.compiler( + if mode == Mode::ToolBootstrap { 0 } else { builder.top_stage }, + builder.config.build, + ); + + if mode != Mode::ToolBootstrap { + builder.ensure(Rustc::new(self.target, builder)); + } + + let mut cargo = prepare_tool_cargo( + builder, + compiler, + mode, + self.target, + builder.kind, + "src/tools/compiletest", + SourceType::InTree, + &[], + ); + + cargo.allow_features(COMPILETEST_ALLOW_FEATURES); + + // For ./x.py clippy, don't run with --all-targets because + // linting tests and benchmarks can produce very noisy results + if builder.kind != Kind::Clippy { + cargo.arg("--all-targets"); + } + + let stamp = BuildStamp::new(&builder.cargo_out(compiler, mode, self.target)) + .with_prefix("compiletest-check"); + + let _guard = builder.msg_check("compiletest artifacts", self.target); + run_cargo(builder, cargo, builder.config.free_args.clone(), &stamp, vec![], true, false); + } +} + macro_rules! tool_check_step { ( $name:ident { @@ -464,7 +527,3 @@ tool_check_step!(Bootstrap { path: "src/bootstrap", default: false }); // `run-make-support` will be built as part of suitable run-make compiletest test steps, but support // check to make it easier to work on. tool_check_step!(RunMakeSupport { path: "src/tools/run-make-support", default: false }); - -// Compiletest is implicitly "checked" when it gets built in order to run tests, -// so this is mainly for people working on compiletest to run locally. -tool_check_step!(Compiletest { path: "src/tools/compiletest", default: false }); diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 18b5d4426b1e..6a5b38dd5043 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -155,7 +155,7 @@ impl Step for Std { // When using `download-rustc`, we already have artifacts for the host available. Don't // recompile them. - if builder.download_rustc() && builder.is_builder_target(target) + if builder.download_rustc() && builder.config.is_host_target(target) // NOTE: the beta compiler may generate different artifacts than the downloaded compiler, so // its artifacts can't be reused. && compiler.stage != 0 @@ -229,7 +229,7 @@ impl Step for Std { // The LLD wrappers and `rust-lld` are self-contained linking components that can be // necessary to link the stdlib on some targets. We'll also need to copy these binaries to // the `stage0-sysroot` to ensure the linker is found when bootstrapping on such a target. - if compiler.stage == 0 && builder.is_builder_target(compiler.host) { + if compiler.stage == 0 && builder.config.is_host_target(compiler.host) { trace!( "(build == host) copying linking components to `stage0-sysroot` for bootstrapping" ); @@ -1374,7 +1374,7 @@ pub fn rustc_cargo_env( /// Pass down configuration from the LLVM build into the build of /// rustc_llvm and rustc_codegen_llvm. fn rustc_llvm_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetSelection) { - if builder.is_rust_llvm(target) { + if builder.config.is_rust_llvm(target) { cargo.env("LLVM_RUSTLLVM", "1"); } if builder.config.llvm_enzyme { @@ -2182,7 +2182,7 @@ impl Step for Assemble { debug!("copying codegen backends to sysroot"); copy_codegen_backends_to_sysroot(builder, build_compiler, target_compiler); - if builder.config.lld_enabled { + if builder.config.lld_enabled && !builder.config.is_system_llvm(target_compiler.host) { builder.ensure(crate::core::build_steps::tool::LldWrapper { build_compiler, target_compiler, @@ -2398,7 +2398,9 @@ pub fn run_cargo( // Ok now we need to actually find all the files listed in `toplevel`. We've // got a list of prefix/extensions and we basically just need to find the // most recent file in the `deps` folder corresponding to each one. - let contents = t!(target_deps_dir.read_dir()) + let contents = target_deps_dir + .read_dir() + .unwrap_or_else(|e| panic!("Couldn't read {}: {}", target_deps_dir.display(), e)) .map(|e| t!(e)) .map(|e| (e.path(), e.file_name().into_string().unwrap(), t!(e.metadata()))) .collect::>(); @@ -2530,7 +2532,9 @@ pub fn strip_debug(builder: &Builder<'_>, target: TargetSelection, path: &Path) // FIXME: to make things simpler for now, limit this to the host and target where we know // `strip -g` is both available and will fix the issue, i.e. on a x64 linux host that is not // cross-compiling. Expand this to other appropriate targets in the future. - if target != "x86_64-unknown-linux-gnu" || !builder.is_builder_target(target) || !path.exists() + if target != "x86_64-unknown-linux-gnu" + || !builder.config.is_host_target(target) + || !path.exists() { return; } diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index 83f71aeed720..ed90ede79362 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -612,7 +612,7 @@ impl Step for DebuggerScripts { fn skip_host_target_lib(builder: &Builder<'_>, compiler: Compiler) -> bool { // The only true set of target libraries came from the build triple, so // let's reduce redundant work by only producing archives from that host. - if !builder.is_builder_target(compiler.host) { + if !builder.config.is_host_target(compiler.host) { builder.info("\tskipping, not a build host"); true } else { @@ -671,7 +671,8 @@ fn copy_target_libs( &self_contained_dst.join(path.file_name().unwrap()), FileType::NativeLibrary, ); - } else if dependency_type == DependencyType::Target || builder.is_builder_target(target) { + } else if dependency_type == DependencyType::Target || builder.config.is_host_target(target) + { builder.copy_link(&path, &dst.join(path.file_name().unwrap()), FileType::NativeLibrary); } } @@ -824,7 +825,7 @@ impl Step for Analysis { fn run(self, builder: &Builder<'_>) -> Option { let compiler = self.compiler; let target = self.target; - if !builder.is_builder_target(compiler.host) { + if !builder.config.is_host_target(compiler.host) { return None; } @@ -2118,7 +2119,7 @@ fn maybe_install_llvm( // // If the LLVM is coming from ourselves (just from CI) though, we // still want to install it, as it otherwise won't be available. - if builder.is_system_llvm(target) { + if builder.config.is_system_llvm(target) { trace!("system LLVM requested, no install"); return false; } diff --git a/src/bootstrap/src/core/build_steps/format.rs b/src/bootstrap/src/core/build_steps/format.rs index b1a97bde97b5..9da8b27a9177 100644 --- a/src/bootstrap/src/core/build_steps/format.rs +++ b/src/bootstrap/src/core/build_steps/format.rs @@ -81,14 +81,19 @@ fn update_rustfmt_version(build: &Builder<'_>) { let Some((version, stamp_file)) = get_rustfmt_version(build) else { return; }; - t!(std::fs::write(stamp_file.path(), version)) + + t!(stamp_file.add_stamp(version).write()); } -/// Returns the Rust files modified between the `merge-base` of HEAD and -/// rust-lang/master and what is now on the disk. Does not include removed files. +/// Returns the Rust files modified between the last merge commit and what is now on the disk. +/// Does not include removed files. /// /// Returns `None` if all files should be formatted. fn get_modified_rs_files(build: &Builder<'_>) -> Result>, String> { + // In CI `get_git_modified_files` returns something different to normal environment. + // This shouldn't be called in CI anyway. + assert!(!build.config.is_running_on_ci); + if !verify_rustfmt_version(build) { return Ok(None); } @@ -103,7 +108,7 @@ struct RustfmtConfig { // Prints output describing a collection of paths, with lines such as "formatted modified file // foo/bar/baz" or "skipped 20 untracked files". -fn print_paths(build: &Builder<'_>, verb: &str, adjective: Option<&str>, paths: &[String]) { +fn print_paths(verb: &str, adjective: Option<&str>, paths: &[String]) { let len = paths.len(); let adjective = if let Some(adjective) = adjective { format!("{adjective} ") } else { String::new() }; @@ -114,9 +119,6 @@ fn print_paths(build: &Builder<'_>, verb: &str, adjective: Option<&str>, paths: } else { println!("fmt: {verb} {len} {adjective}files"); } - if len > 1000 && !build.config.is_running_on_ci { - println!("hint: if this number seems too high, try running `git fetch origin master`"); - } } pub fn format(build: &Builder<'_>, check: bool, all: bool, paths: &[PathBuf]) { @@ -189,7 +191,7 @@ pub fn format(build: &Builder<'_>, check: bool, all: bool, paths: &[PathBuf]) { ) .map(|x| x.to_string()) .collect(); - print_paths(build, "skipped", Some("untracked"), &untracked_paths); + print_paths("skipped", Some("untracked"), &untracked_paths); for untracked_path in untracked_paths { // The leading `/` makes it an exact match against the @@ -212,7 +214,13 @@ pub fn format(build: &Builder<'_>, check: bool, all: bool, paths: &[PathBuf]) { override_builder.add(&format!("/{file}")).expect(&file); } } - Ok(None) => {} + Ok(None) => { + // NOTE: `Ok(None)` signifies that we need to format all files. + // The tricky part here is that if `override_builder` isn't given any white + // list files (i.e. files to be formatted, added without leading `!`), it + // will instead look for *all* files. So, by doing nothing here, we are + // actually making it so we format all files. + } Err(err) => { eprintln!("fmt warning: Something went wrong running git commands:"); eprintln!("fmt warning: {err}"); @@ -318,7 +326,7 @@ pub fn format(build: &Builder<'_>, check: bool, all: bool, paths: &[PathBuf]) { }); let mut paths = formatted_paths.into_inner().unwrap(); paths.sort(); - print_paths(build, if check { "checked" } else { "formatted" }, adjective, &paths); + print_paths(if check { "checked" } else { "formatted" }, adjective, &paths); drop(tx); @@ -328,7 +336,10 @@ pub fn format(build: &Builder<'_>, check: bool, all: bool, paths: &[PathBuf]) { crate::exit!(1); } - if !check { - update_rustfmt_version(build); - } + // Update `build/.rustfmt-stamp`, allowing this code to ignore files which have not been changed + // since last merge. + // + // NOTE: Because of the exit above, this is only reachable if formatting / format checking + // succeeded. So we are not commiting the version if formatting was not good. + update_rustfmt_version(build); } diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index 69a8bd59f16c..6f6839ad15b0 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -370,8 +370,8 @@ impl Step for Llvm { cfg.define("LLVM_PROFDATA_FILE", path); } - // Libraries for ELF section compression. - if !target.is_windows() { + // Libraries for ELF section compression and profraw files merging. + if !target.is_msvc() { cfg.define("LLVM_ENABLE_ZLIB", "ON"); } else { cfg.define("LLVM_ENABLE_ZLIB", "OFF"); @@ -485,7 +485,7 @@ impl Step for Llvm { } // https://llvm.org/docs/HowToCrossCompileLLVM.html - if !builder.is_builder_target(target) { + if !builder.config.is_host_target(target) { let LlvmResult { llvm_config, .. } = builder.ensure(Llvm { target: builder.config.build }); if !builder.config.dry_run() { @@ -637,7 +637,7 @@ fn configure_cmake( } cfg.target(&target.triple).host(&builder.config.build.triple); - if !builder.is_builder_target(target) { + if !builder.config.is_host_target(target) { cfg.define("CMAKE_CROSSCOMPILING", "True"); // NOTE: Ideally, we wouldn't have to do this, and `cmake-rs` would just handle it for us. @@ -1098,7 +1098,7 @@ impl Step for Lld { .define("LLVM_CMAKE_DIR", llvm_cmake_dir) .define("LLVM_INCLUDE_TESTS", "OFF"); - if !builder.is_builder_target(target) { + if !builder.config.is_host_target(target) { // Use the host llvm-tblgen binary. cfg.define( "LLVM_TABLEGEN_EXE", diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 8e42e845a8cb..096f7de65975 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -15,7 +15,7 @@ use crate::core::build_steps::doc::DocumentationFormat; use crate::core::build_steps::gcc::{Gcc, add_cg_gcc_cargo_flags}; use crate::core::build_steps::llvm::get_llvm_version; use crate::core::build_steps::synthetic_targets::MirOptPanicAbortSyntheticTarget; -use crate::core::build_steps::tool::{self, SourceType, Tool}; +use crate::core::build_steps::tool::{self, COMPILETEST_ALLOW_FEATURES, SourceType, Tool}; use crate::core::build_steps::toolstate::ToolState; use crate::core::build_steps::{compile, dist, llvm}; use crate::core::builder::{ @@ -261,13 +261,7 @@ impl Step for Cargotest { .args(builder.config.test_args()) .env("RUSTC", builder.rustc(compiler)) .env("RUSTDOC", builder.rustdoc(compiler)); - add_rustdoc_cargo_linker_args( - &mut cmd, - builder, - compiler.host, - LldThreads::No, - compiler.stage, - ); + add_rustdoc_cargo_linker_args(&mut cmd, builder, compiler.host, LldThreads::No); cmd.delay_failure().run(builder); } } @@ -727,7 +721,7 @@ impl Step for CompiletestTest { SourceType::InTree, &[], ); - cargo.allow_features("test"); + cargo.allow_features(COMPILETEST_ALLOW_FEATURES); run_cargo_test(cargo, &[], &[], "compiletest self test", host, builder); } } @@ -845,7 +839,7 @@ impl Step for RustdocTheme { .env("CFG_RELEASE_CHANNEL", &builder.config.channel) .env("RUSTDOC_REAL", builder.rustdoc(self.compiler)) .env("RUSTC_BOOTSTRAP", "1"); - cmd.args(linker_args(builder, self.compiler.host, LldThreads::No, self.compiler.stage)); + cmd.args(linker_args(builder, self.compiler.host, LldThreads::No)); cmd.delay_failure().run(builder); } @@ -1021,13 +1015,7 @@ impl Step for RustdocGUI { cmd.env("RUSTDOC", builder.rustdoc(self.compiler)) .env("RUSTC", builder.rustc(self.compiler)); - add_rustdoc_cargo_linker_args( - &mut cmd, - builder, - self.compiler.host, - LldThreads::No, - self.compiler.stage, - ); + add_rustdoc_cargo_linker_args(&mut cmd, builder, self.compiler.host, LldThreads::No); for path in &builder.paths { if let Some(p) = helpers::is_valid_test_suite_arg(path, "tests/rustdoc-gui", builder) { @@ -1796,7 +1784,7 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the } let mut hostflags = flags.clone(); - hostflags.extend(linker_flags(builder, compiler.host, LldThreads::No, compiler.stage)); + hostflags.extend(linker_flags(builder, compiler.host, LldThreads::No)); let mut targetflags = flags; @@ -1906,7 +1894,7 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the .arg(llvm_components.trim()); llvm_components_passed = true; } - if !builder.is_rust_llvm(target) { + if !builder.config.is_rust_llvm(target) { cmd.arg("--system-llvm"); } @@ -2680,7 +2668,7 @@ impl Step for Crate { cargo } else { // Also prepare a sysroot for the target. - if !builder.is_builder_target(target) { + if !builder.config.is_host_target(target) { builder.ensure(compile::Std::new(compiler, target).force_recompile(true)); builder.ensure(RemoteCopyLibs { compiler, target }); } diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index cd57e06ae04a..3426da51a808 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -148,10 +148,9 @@ impl Step for ToolBuild { &self.extra_features, ); - if path.ends_with("/rustdoc") && - // rustdoc is performance sensitive, so apply LTO to it. - is_lto_stage(&self.compiler) - { + // Rustc tools (miri, clippy, cargo, rustfmt, rust-analyzer) + // could use the additional optimizations. + if self.mode == Mode::ToolRustc && is_lto_stage(&self.compiler) { let lto = match builder.config.rust_lto { RustcLto::Off => Some("off"), RustcLto::Thin => Some("thin"), @@ -425,11 +424,14 @@ macro_rules! bootstrap_tool { } )* + let is_unstable = false $(|| $unstable)*; + let compiletest_wants_stage0 = $tool_name == "compiletest" && builder.config.compiletest_use_stage0_libtest; + builder.ensure(ToolBuild { compiler: self.compiler, target: self.target, tool: $tool_name, - mode: if false $(|| $unstable)* { + mode: if is_unstable && !compiletest_wants_stage0 { // use in-tree libraries for unstable features Mode::ToolStd } else { @@ -442,7 +444,11 @@ macro_rules! bootstrap_tool { SourceType::InTree }, extra_features: vec![], - allow_features: concat!($($allow_features)*), + allow_features: { + let mut _value = ""; + $( _value = $allow_features; )? + _value + }, cargo_args: vec![], artifact_kind: if false $(|| $artifact_kind == ToolArtifactKind::Library)* { ToolArtifactKind::Library @@ -456,6 +462,8 @@ macro_rules! bootstrap_tool { } } +pub(crate) const COMPILETEST_ALLOW_FEATURES: &str = "test,internal_output_capture"; + bootstrap_tool!( // This is marked as an external tool because it includes dependencies // from submodules. Trying to keep the lints in sync between all the repos @@ -466,7 +474,7 @@ bootstrap_tool!( Tidy, "src/tools/tidy", "tidy"; Linkchecker, "src/tools/linkchecker", "linkchecker"; CargoTest, "src/tools/cargotest", "cargotest"; - Compiletest, "src/tools/compiletest", "compiletest", is_unstable_tool = true, allow_features = "test"; + Compiletest, "src/tools/compiletest", "compiletest", is_unstable_tool = true, allow_features = COMPILETEST_ALLOW_FEATURES; BuildManifest, "src/tools/build-manifest", "build-manifest"; RemoteTestClient, "src/tools/remote-test-client", "remote-test-client"; RustInstaller, "src/tools/rust-installer", "rust-installer"; @@ -481,7 +489,8 @@ bootstrap_tool!( GenerateCopyright, "src/tools/generate-copyright", "generate-copyright"; SuggestTests, "src/tools/suggest-tests", "suggest-tests"; GenerateWindowsSys, "src/tools/generate-windows-sys", "generate-windows-sys"; - RustdocGUITest, "src/tools/rustdoc-gui-test", "rustdoc-gui-test", is_unstable_tool = true, allow_features = "test"; + // rustdoc-gui-test has a crate dependency on compiletest, so it needs the same unstable features. + RustdocGUITest, "src/tools/rustdoc-gui-test", "rustdoc-gui-test", is_unstable_tool = true, allow_features = COMPILETEST_ALLOW_FEATURES; CoverageDump, "src/tools/coverage-dump", "coverage-dump"; WasmComponentLd, "src/tools/wasm-component-ld", "wasm-component-ld", is_unstable_tool = true, allow_features = "min_specialization"; UnicodeTableGenerator, "src/tools/unicode-table-generator", "unicode-table-generator"; @@ -814,7 +823,6 @@ impl Step for LldWrapper { fields(build_compiler = ?self.build_compiler, target_compiler = ?self.target_compiler), ), )] - fn run(self, builder: &Builder<'_>) -> ToolBuildResult { if builder.config.dry_run() { return ToolBuildResult { diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs index a96ccdd12c2c..e4503b264562 100644 --- a/src/bootstrap/src/core/builder/cargo.rs +++ b/src/bootstrap/src/core/builder/cargo.rs @@ -260,7 +260,7 @@ impl Cargo { } } - for arg in linker_args(builder, compiler.host, LldThreads::Yes, 0) { + for arg in linker_args(builder, compiler.host, LldThreads::Yes) { self.hostflags.arg(&arg); } @@ -270,10 +270,10 @@ impl Cargo { } // We want to set -Clinker using Cargo, therefore we only call `linker_flags` and not // `linker_args` here. - for flag in linker_flags(builder, target, LldThreads::Yes, compiler.stage) { + for flag in linker_flags(builder, target, LldThreads::Yes) { self.rustflags.arg(&flag); } - for arg in linker_args(builder, target, LldThreads::Yes, compiler.stage) { + for arg in linker_args(builder, target, LldThreads::Yes) { self.rustdocflags.arg(&arg); } diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs index a9058f888d38..c32d9c2870cf 100644 --- a/src/bootstrap/src/core/builder/mod.rs +++ b/src/bootstrap/src/core/builder/mod.rs @@ -101,13 +101,13 @@ pub trait Step: 'static + Clone + Debug + PartialEq + Eq + Hash { /// Primary function to implement `Step` logic. /// /// This function can be triggered in two ways: - /// 1. Directly from [`Builder::execute_cli`]. - /// 2. Indirectly by being called from other `Step`s using [`Builder::ensure`]. + /// 1. Directly from [`Builder::execute_cli`]. + /// 2. Indirectly by being called from other `Step`s using [`Builder::ensure`]. /// - /// When called with [`Builder::execute_cli`] (as done by `Build::build`), this function executed twice: - /// - First in "dry-run" mode to validate certain things (like cyclic Step invocations, - /// directory creation, etc) super quickly. - /// - Then it's called again to run the actual, very expensive process. + /// When called with [`Builder::execute_cli`] (as done by `Build::build`), this function is executed twice: + /// - First in "dry-run" mode to validate certain things (like cyclic Step invocations, + /// directory creation, etc) super quickly. + /// - Then it's called again to run the actual, very expensive process. /// /// When triggered indirectly from other `Step`s, it may still run twice (as dry-run and real mode) /// depending on the `Step::run` implementation of the caller. @@ -1276,7 +1276,6 @@ impl<'a> Builder<'a> { ), ), )] - /// FIXME: This function is unnecessary (and dangerous, see ). /// We already have uplifting logic for the compiler, so remove this. pub fn compiler_for( @@ -1480,7 +1479,7 @@ impl<'a> Builder<'a> { cmd.arg("-Dwarnings"); } cmd.arg("-Znormalize-docs"); - cmd.args(linker_args(self, compiler.host, LldThreads::Yes, compiler.stage)); + cmd.args(linker_args(self, compiler.host, LldThreads::Yes)); cmd } diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index fd3b28e4e6ab..5de824ebab23 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -1107,8 +1107,8 @@ fn test_is_builder_target() { let build = Build::new(config); let builder = Builder::new(&build); - assert!(builder.is_builder_target(target1)); - assert!(!builder.is_builder_target(target2)); + assert!(builder.config.is_host_target(target1)); + assert!(!builder.config.is_host_target(target2)); } } diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 1712be7f947f..cd9706646ac7 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -189,7 +189,7 @@ pub enum GccCiMode { /// /// Note that this structure is not decoded directly into, but rather it is /// filled out from the decoded forms of the structs below. For documentation -/// each field, see the corresponding fields in +/// on each field, see the corresponding fields in /// `bootstrap.example.toml`. #[derive(Default, Clone)] pub struct Config { @@ -417,6 +417,9 @@ pub struct Config { /// Command for visual diff display, e.g. `diff-tool --color=always`. pub compiletest_diff_tool: Option, + /// Whether to use the precompiled stage0 libtest with compiletest. + pub compiletest_use_stage0_libtest: bool, + pub is_running_on_ci: bool, } @@ -983,6 +986,7 @@ define_config! { optimized_compiler_builtins: Option = "optimized-compiler-builtins", jobs: Option = "jobs", compiletest_diff_tool: Option = "compiletest-diff-tool", + compiletest_use_stage0_libtest: Option = "compiletest-use-stage0-libtest", ccache: Option = "ccache", exclude: Option> = "exclude", } @@ -1540,9 +1544,6 @@ impl Config { } } - let file_content = t!(fs::read_to_string(config.src.join("src/ci/channel"))); - let ci_channel = file_content.trim_end(); - // Give a hard error if `--config` or `RUST_BOOTSTRAP_CONFIG` are set to a missing path, // but not if `bootstrap.toml` hasn't been created. let mut toml = if !using_default_path || toml_path.exists() { @@ -1682,6 +1683,7 @@ impl Config { optimized_compiler_builtins, jobs, compiletest_diff_tool, + compiletest_use_stage0_libtest, mut ccache, exclude, } = toml.build.unwrap_or_default(); @@ -1847,17 +1849,21 @@ impl Config { let mut lld_enabled = None; let mut std_features = None; - let is_user_configured_rust_channel = - if let Some(channel) = toml.rust.as_ref().and_then(|r| r.channel.clone()) { - if channel == "auto-detect" { - config.channel = ci_channel.into(); - } else { - config.channel = channel; - } + let file_content = t!(fs::read_to_string(config.src.join("src/ci/channel"))); + let ci_channel = file_content.trim_end(); + + let toml_channel = toml.rust.as_ref().and_then(|r| r.channel.clone()); + let is_user_configured_rust_channel = match toml_channel { + Some(channel) if channel == "auto-detect" => { + config.channel = ci_channel.into(); true - } else { - false - }; + } + Some(channel) => { + config.channel = channel; + true + } + None => false, + }; let default = config.channel == "dev"; config.omit_git_hash = toml.rust.as_ref().and_then(|r| r.omit_git_hash).unwrap_or(default); @@ -1882,6 +1888,10 @@ impl Config { && config.src.join(".cargo/config.toml").exists(), ); + if !is_user_configured_rust_channel && config.rust_info.is_from_tarball() { + config.channel = ci_channel.into(); + } + if let Some(rust) = toml.rust { let Rust { optimize: optimize_toml, @@ -2085,8 +2095,6 @@ impl Config { config.channel = channel; } - } else if config.rust_info.is_from_tarball() && !is_user_configured_rust_channel { - ci_channel.clone_into(&mut config.channel); } if let Some(llvm) = toml.llvm { @@ -2389,6 +2397,12 @@ impl Config { ); } + if config.lld_enabled && config.is_system_llvm(config.build) { + eprintln!( + "Warning: LLD is enabled when using external llvm-config. LLD will not be built and copied to the sysroot." + ); + } + let default_std_features = BTreeSet::from([String::from("panic-unwind")]); config.rust_std_features = std_features.unwrap_or(default_std_features); @@ -2415,6 +2429,7 @@ impl Config { config.optimized_compiler_builtins = optimized_compiler_builtins.unwrap_or(config.channel != "dev"); config.compiletest_diff_tool = compiletest_diff_tool; + config.compiletest_use_stage0_libtest = compiletest_use_stage0_libtest.unwrap_or(true); let download_rustc = config.download_rustc_commit.is_some(); config.explicit_stage_from_cli = flags.stage.is_some(); @@ -2879,6 +2894,13 @@ impl Config { let absolute_path = self.src.join(relative_path); + // NOTE: This check is required because `jj git clone` doesn't create directories for + // submodules, they are completely ignored. The code below assumes this directory exists, + // so create it here. + if !absolute_path.exists() { + t!(fs::create_dir_all(&absolute_path)); + } + // NOTE: The check for the empty directory is here because when running x.py the first time, // the submodule won't be checked out. Check it out now so we can build it. if !GitInfo::new(false, &absolute_path).is_managed_git_subrepository() @@ -3224,6 +3246,42 @@ impl Config { Some(commit.to_string()) } + + /// Checks if the given target is the same as the host target. + pub fn is_host_target(&self, target: TargetSelection) -> bool { + self.build == target + } + + /// Returns `true` if this is an external version of LLVM not managed by bootstrap. + /// In particular, we expect llvm sources to be available when this is false. + /// + /// NOTE: this is not the same as `!is_rust_llvm` when `llvm_has_patches` is set. + pub fn is_system_llvm(&self, target: TargetSelection) -> bool { + match self.target_config.get(&target) { + Some(Target { llvm_config: Some(_), .. }) => { + let ci_llvm = self.llvm_from_ci && self.is_host_target(target); + !ci_llvm + } + // We're building from the in-tree src/llvm-project sources. + Some(Target { llvm_config: None, .. }) => false, + None => false, + } + } + + /// Returns `true` if this is our custom, patched, version of LLVM. + /// + /// This does not necessarily imply that we're managing the `llvm-project` submodule. + pub fn is_rust_llvm(&self, target: TargetSelection) -> bool { + match self.target_config.get(&target) { + // We're using a user-controlled version of LLVM. The user has explicitly told us whether the version has our patches. + // (They might be wrong, but that's not a supported use-case.) + // In particular, this tries to support `submodules = false` and `patches = false`, for using a newer version of LLVM that's not through `rust-lang/llvm-project`. + Some(Target { llvm_has_rust_patches: Some(patched), .. }) => *patched, + // The user hasn't promised the patches match. + // This only has our patches if it's downloaded from CI or built from source. + _ => !self.is_system_llvm(target), + } + } } /// Compares the current `Llvm` options against those in the CI LLVM builder and detects any incompatible options. diff --git a/src/bootstrap/src/core/download.rs b/src/bootstrap/src/core/download.rs index 5bd947f6e636..4e4b948a8fd6 100644 --- a/src/bootstrap/src/core/download.rs +++ b/src/bootstrap/src/core/download.rs @@ -417,7 +417,7 @@ enum DownloadSource { Dist, } -/// Functions that are only ever called once, but named for clarify and to avoid thousand-line functions. +/// Functions that are only ever called once, but named for clarity and to avoid thousand-line functions. impl Config { pub(crate) fn download_clippy(&self) -> PathBuf { self.verbose(|| println!("downloading stage0 clippy artifacts")); diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs index dbfebd11f828..eb0bf1d166a1 100644 --- a/src/bootstrap/src/core/sanity.rs +++ b/src/bootstrap/src/core/sanity.rs @@ -34,7 +34,7 @@ pub struct Finder { // Targets can be removed from this list once they are present in the stage0 compiler (usually by updating the beta compiler of the bootstrap). const STAGE0_MISSING_TARGETS: &[&str] = &[ // just a dummy comment so the list doesn't get onelined - "wasm32-wali-linux-musl", + "x86_64-lynx-lynxos178", ]; /// Minimum version threshold for libstdc++ required when using prebuilt LLVM @@ -326,7 +326,7 @@ than building it. if target.contains("musl") && !target.contains("unikraft") { // If this is a native target (host is also musl) and no musl-root is given, // fall back to the system toolchain in /usr before giving up - if build.musl_root(*target).is_none() && build.is_builder_target(*target) { + if build.musl_root(*target).is_none() && build.config.is_host_target(*target) { let target = build.config.target_config.entry(*target).or_default(); target.musl_root = Some("/usr".into()); } diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index 7c60e0421421..88d181532a7f 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -35,7 +35,7 @@ use utils::channel::GitInfo; use crate::core::builder; use crate::core::builder::Kind; -use crate::core::config::{DryRun, LldMode, LlvmLibunwind, Target, TargetSelection, flags}; +use crate::core::config::{DryRun, LldMode, LlvmLibunwind, TargetSelection, flags}; use crate::utils::exec::{BehaviorOnFailure, BootstrapCommand, CommandOutput, OutputMode, command}; use crate::utils::helpers::{ self, dir_is_empty, exe, libdir, output, set_file_times, split_debuginfo, symlink_dir, @@ -803,7 +803,7 @@ impl Build { /// Note that if LLVM is configured externally then the directory returned /// will likely be empty. fn llvm_out(&self, target: TargetSelection) -> PathBuf { - if self.config.llvm_from_ci && self.is_builder_target(target) { + if self.config.llvm_from_ci && self.config.is_host_target(target) { self.config.ci_llvm_root() } else { self.out.join(target).join("llvm") @@ -851,37 +851,6 @@ impl Build { if self.config.vendor { Some(self.src.join(VENDOR_DIR)) } else { None } } - /// Returns `true` if this is an external version of LLVM not managed by bootstrap. - /// In particular, we expect llvm sources to be available when this is false. - /// - /// NOTE: this is not the same as `!is_rust_llvm` when `llvm_has_patches` is set. - fn is_system_llvm(&self, target: TargetSelection) -> bool { - match self.config.target_config.get(&target) { - Some(Target { llvm_config: Some(_), .. }) => { - let ci_llvm = self.config.llvm_from_ci && self.is_builder_target(target); - !ci_llvm - } - // We're building from the in-tree src/llvm-project sources. - Some(Target { llvm_config: None, .. }) => false, - None => false, - } - } - - /// Returns `true` if this is our custom, patched, version of LLVM. - /// - /// This does not necessarily imply that we're managing the `llvm-project` submodule. - fn is_rust_llvm(&self, target: TargetSelection) -> bool { - match self.config.target_config.get(&target) { - // We're using a user-controlled version of LLVM. The user has explicitly told us whether the version has our patches. - // (They might be wrong, but that's not a supported use-case.) - // In particular, this tries to support `submodules = false` and `patches = false`, for using a newer version of LLVM that's not through `rust-lang/llvm-project`. - Some(Target { llvm_has_rust_patches: Some(patched), .. }) => *patched, - // The user hasn't promised the patches match. - // This only has our patches if it's downloaded from CI or built from source. - _ => !self.is_system_llvm(target), - } - } - /// Returns the path to `FileCheck` binary for the specified target fn llvm_filecheck(&self, target: TargetSelection) -> PathBuf { let target_config = self.config.target_config.get(&target); @@ -1356,7 +1325,7 @@ Executed at: {executed_at}"#, // need to use CXX compiler as linker to resolve the exception functions // that are only existed in CXX libraries Some(self.cxx.borrow()[&target].path().into()) - } else if !self.is_builder_target(target) + } else if !self.config.is_host_target(target) && helpers::use_host_linker(target) && !target.is_msvc() { @@ -1557,7 +1526,7 @@ Executed at: {executed_at}"#, !self.config.full_bootstrap && !self.config.download_rustc() && stage >= 2 - && (self.hosts.iter().any(|h| *h == target) || target == self.build) + && (self.hosts.contains(&target) || target == self.build) } /// Checks whether the `compiler` compiling for `target` should be forced to @@ -2025,11 +1994,6 @@ to download LLVM rather than building it. stream.reset().unwrap(); result } - - /// Checks if the given target is the same as the builder target. - fn is_builder_target(&self, target: TargetSelection) -> bool { - self.config.build == target - } } #[cfg(unix)] diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs index 244391739f38..48b6f77e8a58 100644 --- a/src/bootstrap/src/utils/change_tracker.rs +++ b/src/bootstrap/src/utils/change_tracker.rs @@ -391,4 +391,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[ severity: ChangeSeverity::Info, summary: "You can now use `change-id = \"ignore\"` to suppress `change-id ` warnings in the console.", }, + ChangeInfo { + change_id: 139386, + severity: ChangeSeverity::Info, + summary: "Added a new option `build.compiletest-use-stage0-libtest` to force `compiletest` to use the stage 0 libtest.", + }, ]; diff --git a/src/bootstrap/src/utils/helpers.rs b/src/bootstrap/src/utils/helpers.rs index 78dcdcbd1874..1299fbb7d629 100644 --- a/src/bootstrap/src/utils/helpers.rs +++ b/src/bootstrap/src/utils/helpers.rs @@ -432,9 +432,7 @@ pub fn dir_is_empty(dir: &Path) -> bool { /// the "y" part from the string. pub fn extract_beta_rev(version: &str) -> Option { let parts = version.splitn(2, "-beta.").collect::>(); - let count = parts.get(1).and_then(|s| s.find(' ').map(|p| s[..p].to_string())); - - count + parts.get(1).and_then(|s| s.find(' ').map(|p| s[..p].to_string())) } pub enum LldThreads { @@ -447,9 +445,8 @@ pub fn linker_args( builder: &Builder<'_>, target: TargetSelection, lld_threads: LldThreads, - stage: u32, ) -> Vec { - let mut args = linker_flags(builder, target, lld_threads, stage); + let mut args = linker_flags(builder, target, lld_threads); if let Some(linker) = builder.linker(target) { args.push(format!("-Clinker={}", linker.display())); @@ -464,18 +461,12 @@ pub fn linker_flags( builder: &Builder<'_>, target: TargetSelection, lld_threads: LldThreads, - stage: u32, ) -> Vec { let mut args = vec![]; if !builder.is_lld_direct_linker(target) && builder.config.lld_mode.is_used() { match builder.config.lld_mode { LldMode::External => { - // cfg(bootstrap) - remove after updating bootstrap compiler (#137498) - if stage == 0 && target.is_windows() { - args.push("-Clink-arg=-fuse-ld=lld".to_string()); - } else { - args.push("-Zlinker-features=+lld".to_string()); - } + args.push("-Zlinker-features=+lld".to_string()); // FIXME(kobzol): remove this flag once MCP510 gets stabilized args.push("-Zunstable-options".to_string()); } @@ -503,9 +494,8 @@ pub fn add_rustdoc_cargo_linker_args( builder: &Builder<'_>, target: TargetSelection, lld_threads: LldThreads, - stage: u32, ) { - let args = linker_args(builder, target, lld_threads, stage); + let args = linker_args(builder, target, lld_threads); let mut flags = cmd .get_envs() .find_map(|(k, v)| if k == OsStr::new("RUSTDOCFLAGS") { v } else { None }) diff --git a/src/bootstrap/src/utils/proc_macro_deps.rs b/src/bootstrap/src/utils/proc_macro_deps.rs index dbfd6f47dc67..7cf1af1c3e2d 100644 --- a/src/bootstrap/src/utils/proc_macro_deps.rs +++ b/src/bootstrap/src/utils/proc_macro_deps.rs @@ -5,6 +5,7 @@ pub static CRATES: &[&str] = &[ // tidy-alphabetical-start "annotate-snippets", "anstyle", + "askama_parser", "basic-toml", "block-buffer", "bumpalo", @@ -31,7 +32,6 @@ pub static CRATES: &[&str] = &[ "mime_guess", "minimal-lexical", "nom", - "num-conv", "once_cell", "pest", "pest_generator", @@ -49,7 +49,6 @@ pub static CRATES: &[&str] = &[ "syn", "synstructure", "thiserror", - "time-core", "tinystr", "type-map", "typenum", @@ -64,6 +63,7 @@ pub static CRATES: &[&str] = &[ "wasm-bindgen-backend", "wasm-bindgen-macro-support", "wasm-bindgen-shared", + "winnow", "yoke", "zerofrom", "zerovec", diff --git a/src/build_helper/src/fs/mod.rs b/src/build_helper/src/fs/mod.rs index 02029846fd14..123df76e6a2e 100644 --- a/src/build_helper/src/fs/mod.rs +++ b/src/build_helper/src/fs/mod.rs @@ -22,21 +22,27 @@ where /// A wrapper around [`std::fs::remove_dir_all`] that can also be used on *non-directory entries*, /// including files and symbolic links. /// -/// - This will produce an error if the target path is not found. +/// - This will not produce an error if the target path is not found. /// - Like [`std::fs::remove_dir_all`], this helper does not traverse symbolic links, will remove /// symbolic link itself. /// - This helper is **not** robust against races on the underlying filesystem, behavior is /// unspecified if this helper is called concurrently. /// - This helper is not robust against TOCTOU problems. /// -/// FIXME: this implementation is insufficiently robust to replace bootstrap's clean `rm_rf` -/// implementation: -/// -/// - This implementation currently does not perform retries. +/// FIXME: Audit whether this implementation is robust enough to replace bootstrap's clean `rm_rf`. #[track_caller] pub fn recursive_remove>(path: P) -> io::Result<()> { let path = path.as_ref(); - let metadata = fs::symlink_metadata(path)?; + + // If the path doesn't exist, we treat it as a successful no-op. + // From the caller's perspective, the goal is simply "ensure this file/dir is gone" — + // if it's already not there, that's a success, not an error. + let metadata = match fs::symlink_metadata(path) { + Ok(m) => m, + Err(e) if e.kind() == io::ErrorKind::NotFound => return Ok(()), + Err(e) => return Err(e), + }; + #[cfg(windows)] let is_dir_like = |meta: &fs::Metadata| { use std::os::windows::fs::FileTypeExt; @@ -45,11 +51,35 @@ pub fn recursive_remove>(path: P) -> io::Result<()> { #[cfg(not(windows))] let is_dir_like = fs::Metadata::is_dir; - if is_dir_like(&metadata) { - fs::remove_dir_all(path) - } else { - try_remove_op_set_perms(fs::remove_file, path, metadata) + const MAX_RETRIES: usize = 5; + const RETRY_DELAY_MS: u64 = 100; + + let try_remove = || { + if is_dir_like(&metadata) { + fs::remove_dir_all(path) + } else { + try_remove_op_set_perms(fs::remove_file, path, metadata.clone()) + } + }; + + // Retry deletion a few times to handle transient filesystem errors. + // This is unusual for local file operations, but it's a mitigation + // against unlikely events where malware scanners may be holding a + // file beyond our control, to give the malware scanners some opportunity + // to release their hold. + for attempt in 0..MAX_RETRIES { + match try_remove() { + Ok(()) => return Ok(()), + Err(e) if e.kind() == io::ErrorKind::NotFound => return Ok(()), + Err(_) if attempt < MAX_RETRIES - 1 => { + std::thread::sleep(std::time::Duration::from_millis(RETRY_DELAY_MS)); + continue; + } + Err(e) => return Err(e), + } } + + Ok(()) } fn try_remove_op_set_perms<'p, Op>(mut op: Op, path: &'p Path, metadata: Metadata) -> io::Result<()> @@ -67,3 +97,9 @@ where Err(e) => Err(e), } } + +pub fn remove_and_create_dir_all>(path: P) -> io::Result<()> { + let path = path.as_ref(); + recursive_remove(path)?; + fs::create_dir_all(path) +} diff --git a/src/build_helper/src/fs/tests.rs b/src/build_helper/src/fs/tests.rs index 1e694393127c..7ce1d8928d1c 100644 --- a/src/build_helper/src/fs/tests.rs +++ b/src/build_helper/src/fs/tests.rs @@ -14,7 +14,7 @@ mod recursive_remove_tests { let tmpdir = env::temp_dir(); let path = tmpdir.join("__INTERNAL_BOOTSTRAP_nonexistent_path"); assert!(fs::symlink_metadata(&path).is_err_and(|e| e.kind() == io::ErrorKind::NotFound)); - assert!(recursive_remove(&path).is_err_and(|e| e.kind() == io::ErrorKind::NotFound)); + assert!(recursive_remove(&path).is_ok()); } #[test] diff --git a/src/build_helper/src/git.rs b/src/build_helper/src/git.rs index 693e0fc8f46d..f5347c308241 100644 --- a/src/build_helper/src/git.rs +++ b/src/build_helper/src/git.rs @@ -114,7 +114,9 @@ fn git_upstream_merge_base( Ok(output_result(git.arg("merge-base").arg(&updated_master).arg("HEAD"))?.trim().to_owned()) } -/// Searches for the nearest merge commit in the repository that also exists upstream. +/// Searches for the nearest merge commit in the repository. +/// +/// **In CI** finds the nearest merge commit that *also exists upstream*. /// /// It looks for the most recent commit made by the merge bot by matching the author's email /// address with the merge bot's email. @@ -165,7 +167,7 @@ pub fn get_closest_merge_commit( Ok(output_result(&mut git)?.trim().to_owned()) } -/// Returns the files that have been modified in the current branch compared to the master branch. +/// Returns the files that have been modified in the current branch compared to the last merge. /// The `extensions` parameter can be used to filter the files by their extension. /// Does not include removed files. /// If `extensions` is empty, all files will be returned. diff --git a/src/ci/citool/Cargo.lock b/src/ci/citool/Cargo.lock index 800eaae07665..2fe219f368b9 100644 --- a/src/ci/citool/Cargo.lock +++ b/src/ci/citool/Cargo.lock @@ -563,9 +563,9 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "miniz_oxide" -version = "0.8.5" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e3e04debbb59698c15bacbb6d93584a8c0ca9cc3213cb423d31f760d8843ce5" +checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" dependencies = [ "adler2", ] diff --git a/src/ci/citool/src/analysis.rs b/src/ci/citool/src/analysis.rs index 7fbfad467c64..9fc7c309bfbd 100644 --- a/src/ci/citool/src/analysis.rs +++ b/src/ci/citool/src/analysis.rs @@ -7,6 +7,7 @@ use build_helper::metrics::{ format_build_steps, }; +use crate::github::JobInfoResolver; use crate::metrics; use crate::metrics::{JobMetrics, JobName, get_test_suites}; use crate::utils::{output_details, pluralize}; @@ -185,13 +186,19 @@ fn render_table(suites: BTreeMap) -> String { } /// Outputs a report of test differences between the `parent` and `current` commits. -pub fn output_test_diffs(job_metrics: &HashMap) { +pub fn output_test_diffs( + job_metrics: &HashMap, + job_info_resolver: &mut JobInfoResolver, +) { let aggregated_test_diffs = aggregate_test_diffs(&job_metrics); - report_test_diffs(aggregated_test_diffs); + report_test_diffs(aggregated_test_diffs, job_metrics, job_info_resolver); } /// Prints the ten largest differences in bootstrap durations. -pub fn output_largest_duration_changes(job_metrics: &HashMap) { +pub fn output_largest_duration_changes( + job_metrics: &HashMap, + job_info_resolver: &mut JobInfoResolver, +) { struct Entry<'a> { job: &'a JobName, before: Duration, @@ -225,14 +232,14 @@ pub fn output_largest_duration_changes(job_metrics: &HashMap {:.1}s ({:.1}%)", + "{}. {}: {:.1}s -> {:.1}s ({:.1}%)", index + 1, - entry.job, + format_job_link(job_info_resolver, job_metrics, entry.job), entry.before.as_secs_f64(), entry.after.as_secs_f64(), entry.change @@ -400,7 +407,11 @@ fn generate_test_name(name: &str) -> String { } /// Prints test changes in Markdown format to stdout. -fn report_test_diffs(diff: AggregatedTestDiffs) { +fn report_test_diffs( + diff: AggregatedTestDiffs, + job_metrics: &HashMap, + job_info_resolver: &mut JobInfoResolver, +) { println!("# Test differences"); if diff.diffs.is_empty() { println!("No test diffs found"); @@ -509,21 +520,42 @@ fn report_test_diffs(diff: AggregatedTestDiffs) { } if doctest_count > 0 { + let prefix = + if doctest_count < original_diff_count { "Additionally, " } else { "" }; println!( - "\nAdditionally, {doctest_count} doctest {} were found. These are ignored, as they are noisy.", + "\n{prefix}{doctest_count} doctest {} were found. These are ignored, as they are noisy.", pluralize("diff", doctest_count) ); } // Now print the job group index - println!("\n**Job group index**\n"); - for (group, jobs) in job_index.into_iter().enumerate() { - println!( - "- {}: {}", - format_job_group(group as u64), - jobs.iter().map(|j| format!("`{j}`")).collect::>().join(", ") - ); + if !job_index.is_empty() { + println!("\n**Job group index**\n"); + for (group, jobs) in job_index.into_iter().enumerate() { + println!( + "- {}: {}", + format_job_group(group as u64), + jobs.iter() + .map(|j| format_job_link(job_info_resolver, job_metrics, j)) + .collect::>() + .join(", ") + ); + } } }, ); } + +/// Tries to get a GitHub Actions job summary URL from the resolver. +/// If it is not available, just wraps the job name in backticks. +fn format_job_link( + job_info_resolver: &mut JobInfoResolver, + job_metrics: &HashMap, + job_name: &str, +) -> String { + job_metrics + .get(job_name) + .and_then(|metrics| job_info_resolver.get_job_summary_link(job_name, &metrics.current)) + .map(|summary_url| format!("[{job_name}]({summary_url})")) + .unwrap_or_else(|| format!("`{job_name}`")) +} diff --git a/src/ci/citool/src/github.rs b/src/ci/citool/src/github.rs new file mode 100644 index 000000000000..35e4c3f9599d --- /dev/null +++ b/src/ci/citool/src/github.rs @@ -0,0 +1,109 @@ +use std::collections::HashMap; + +use anyhow::Context; +use build_helper::metrics::{CiMetadata, JsonRoot}; + +pub struct GitHubClient; + +impl GitHubClient { + fn get_workflow_run_jobs( + &self, + repo: &str, + workflow_run_id: u64, + ) -> anyhow::Result> { + let req = ureq::get(format!( + "https://api.github.com/repos/{repo}/actions/runs/{workflow_run_id}/jobs?per_page=100" + )) + .header("User-Agent", "rust-lang/rust/citool") + .header("Accept", "application/vnd.github+json") + .header("X-GitHub-Api-Version", "2022-11-28") + .call() + .context("cannot get workflow job list")?; + + let status = req.status(); + let mut body = req.into_body(); + if status.is_success() { + // This API response is actually paged, but we assume for now that there are at + // most 100 jobs per workflow. + let response = body + .read_json::() + .context("cannot deserialize workflow run jobs response")?; + // The CI job names have a prefix, e.g. `auto - foo`. We remove the prefix here to + // normalize the job name. + Ok(response + .jobs + .into_iter() + .map(|mut job| { + job.name = job + .name + .split_once(" - ") + .map(|res| res.1.to_string()) + .unwrap_or_else(|| job.name); + job + }) + .collect()) + } else { + Err(anyhow::anyhow!( + "Cannot get jobs of workflow run {workflow_run_id}: {status}\n{}", + body.read_to_string()? + )) + } + } +} + +#[derive(serde::Deserialize)] +struct WorkflowRunJobsResponse { + jobs: Vec, +} + +#[derive(serde::Deserialize)] +struct GitHubJob { + name: String, + id: u64, +} + +/// Can be used to resolve information about GitHub Actions jobs. +/// Caches results internally to avoid too unnecessary GitHub API calls. +pub struct JobInfoResolver { + client: GitHubClient, + // Workflow run ID -> jobs + workflow_job_cache: HashMap>, +} + +impl JobInfoResolver { + pub fn new() -> Self { + Self { client: GitHubClient, workflow_job_cache: Default::default() } + } + + /// Get a link to a job summary for the given job name and bootstrap execution. + pub fn get_job_summary_link(&mut self, job_name: &str, metrics: &JsonRoot) -> Option { + metrics.ci_metadata.as_ref().and_then(|metadata| { + self.get_job_id(metadata, job_name).map(|job_id| { + format!( + "https://github.com/{}/actions/runs/{}#summary-{job_id}", + metadata.repository, metadata.workflow_run_id + ) + }) + }) + } + + fn get_job_id(&mut self, ci_metadata: &CiMetadata, job_name: &str) -> Option { + if let Some(job) = self + .workflow_job_cache + .get(&ci_metadata.workflow_run_id) + .and_then(|jobs| jobs.iter().find(|j| j.name == job_name)) + { + return Some(job.id); + } + + let jobs = self + .client + .get_workflow_run_jobs(&ci_metadata.repository, ci_metadata.workflow_run_id) + .inspect_err(|e| eprintln!("Cannot download workflow jobs: {e:?}")) + .ok()?; + let job_id = jobs.iter().find(|j| j.name == job_name).map(|j| j.id); + // Save the cache even if the job name was not found, it could be useful for further lookups + self.workflow_job_cache.insert(ci_metadata.workflow_run_id, jobs); + job_id + } +} diff --git a/src/ci/citool/src/main.rs b/src/ci/citool/src/main.rs index 6db5eab458cc..a1956da352f5 100644 --- a/src/ci/citool/src/main.rs +++ b/src/ci/citool/src/main.rs @@ -1,6 +1,7 @@ mod analysis; mod cpu_usage; mod datadog; +mod github; mod jobs; mod metrics; mod utils; @@ -18,6 +19,7 @@ use serde_yaml::Value; use crate::analysis::{output_largest_duration_changes, output_test_diffs}; use crate::cpu_usage::load_cpu_usage; use crate::datadog::upload_datadog_metric; +use crate::github::JobInfoResolver; use crate::jobs::RunType; use crate::metrics::{JobMetrics, download_auto_job_metrics, download_job_metrics, load_metrics}; use crate::utils::load_env_var; @@ -145,6 +147,7 @@ fn postprocess_metrics( ) -> anyhow::Result<()> { let metrics = load_metrics(&metrics_path)?; + let mut job_info_resolver = JobInfoResolver::new(); if let (Some(parent), Some(job_name)) = (parent, job_name) { // This command is executed also on PR builds, which might not have parent metrics // available, because some PR jobs don't run on auto builds, and PR jobs do not upload metrics @@ -160,7 +163,7 @@ fn postprocess_metrics( job_name, JobMetrics { parent: Some(parent_metrics), current: metrics }, )]); - output_test_diffs(&job_metrics); + output_test_diffs(&job_metrics, &mut job_info_resolver); return Ok(()); } Err(error) => { @@ -180,8 +183,10 @@ fn post_merge_report(db: JobDatabase, current: String, parent: String) -> anyhow let metrics = download_auto_job_metrics(&db, &parent, ¤t)?; println!("\nComparing {parent} (parent) -> {current} (this PR)\n"); - output_test_diffs(&metrics); - output_largest_duration_changes(&metrics); + + let mut job_info_resolver = JobInfoResolver::new(); + output_test_diffs(&metrics, &mut job_info_resolver); + output_largest_duration_changes(&metrics, &mut job_info_resolver); Ok(()) } diff --git a/src/ci/citool/tests/test-jobs.yml b/src/ci/citool/tests/test-jobs.yml index 3593b3f7df63..d81be88b7087 100644 --- a/src/ci/citool/tests/test-jobs.yml +++ b/src/ci/citool/tests/test-jobs.yml @@ -27,7 +27,7 @@ runners: <<: *base-job envs: env-x86_64-apple-tests: &env-x86_64-apple-tests - SCRIPT: ./x.py --stage 2 test --skip tests/ui --skip tests/rustdoc -- --exact + SCRIPT: ./x.py check compiletest --set build.compiletest-use-stage0-libtest=true && ./x.py --stage 2 test --skip tests/ui --skip tests/rustdoc -- --exact RUST_CONFIGURE_ARGS: --build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 # Ensure that host tooling is tested on our minimum supported macOS version. diff --git a/src/ci/docker/host-x86_64/mingw-check/Dockerfile b/src/ci/docker/host-x86_64/mingw-check/Dockerfile index 8bb7116c3ec5..418408e9242a 100644 --- a/src/ci/docker/host-x86_64/mingw-check/Dockerfile +++ b/src/ci/docker/host-x86_64/mingw-check/Dockerfile @@ -47,6 +47,7 @@ COPY host-x86_64/mingw-check/validate-error-codes.sh /scripts/ ENV SCRIPT \ python3 ../x.py check --stage 0 --set build.optimized-compiler-builtins=false core alloc std --target=aarch64-unknown-linux-gnu,i686-pc-windows-msvc,i686-unknown-linux-gnu,x86_64-apple-darwin,x86_64-pc-windows-gnu,x86_64-pc-windows-msvc && \ /scripts/check-default-config-profiles.sh && \ + python3 ../x.py check compiletest --set build.compiletest-use-stage0-libtest=true && \ python3 ../x.py check --target=x86_64-pc-windows-gnu --host=x86_64-pc-windows-gnu && \ python3 ../x.py clippy ci && \ python3 ../x.py build --stage 0 src/tools/build-manifest && \ diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-20/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-20/Dockerfile new file mode 100644 index 000000000000..408b87125e0c --- /dev/null +++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-20/Dockerfile @@ -0,0 +1,69 @@ +FROM ubuntu:25.04 + +ARG DEBIAN_FRONTEND=noninteractive + +RUN apt-get update && apt-get install -y --no-install-recommends \ + bzip2 \ + g++ \ + gcc-multilib \ + make \ + ninja-build \ + file \ + curl \ + ca-certificates \ + python3 \ + git \ + cmake \ + sudo \ + gdb \ + llvm-20-tools \ + llvm-20-dev \ + libedit-dev \ + libssl-dev \ + pkg-config \ + zlib1g-dev \ + xz-utils \ + nodejs \ + mingw-w64 \ + # libgccjit dependencies + flex \ + libmpfr-dev \ + libgmp-dev \ + libmpc3 \ + libmpc-dev \ + && rm -rf /var/lib/apt/lists/* + +# Install powershell (universal package) so we can test x.ps1 on Linux +# FIXME: need a "universal" version that supports libicu74, but for now it still works to ignore that dep. +RUN curl -sL "https://github.com/PowerShell/PowerShell/releases/download/v7.3.1/powershell_7.3.1-1.deb_amd64.deb" > powershell.deb && \ + dpkg --ignore-depends=libicu72 -i powershell.deb && \ + rm -f powershell.deb + +COPY scripts/sccache.sh /scripts/ +RUN sh /scripts/sccache.sh + +# We are disabling CI LLVM since this builder is intentionally using a host +# LLVM, rather than the typical src/llvm-project LLVM. +ENV NO_DOWNLOAD_CI_LLVM 1 +ENV EXTERNAL_LLVM 1 + +# Using llvm-link-shared due to libffi issues -- see #34486 +ENV RUST_CONFIGURE_ARGS \ + --build=x86_64-unknown-linux-gnu \ + --llvm-root=/usr/lib/llvm-20 \ + --enable-llvm-link-shared \ + --set rust.randomize-layout=true \ + --set rust.thin-lto-import-instr-limit=10 + +COPY scripts/shared.sh /scripts/ + +ARG SCRIPT_ARG + +COPY scripts/add_dummy_commit.sh /tmp/ +COPY scripts/x86_64-gnu-llvm.sh /tmp/ +COPY scripts/x86_64-gnu-llvm2.sh /tmp/ +COPY scripts/x86_64-gnu-llvm3.sh /tmp/ +COPY scripts/stage_2_test_set1.sh /tmp/ +COPY scripts/stage_2_test_set2.sh /tmp/ + +ENV SCRIPT "/tmp/add_dummy_commit.sh && /tmp/${SCRIPT_ARG}" diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile index 89806634c6c2..05c90af78073 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile @@ -101,4 +101,5 @@ COPY scripts/shared.sh /scripts/ # the local version of the package is different than the one used by the CI. ENV SCRIPT /tmp/checktools.sh ../x.py && \ npm install browser-ui-test@$(head -n 1 /tmp/browser-ui-test.version) --unsafe-perm=true && \ + python3 ../x.py check compiletest --set build.compiletest-use-stage0-libtest=true && \ python3 ../x.py test tests/rustdoc-gui --stage 2 --test-args "'--jobs 1'" diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index 68e680a1b1b7..cb2bec5a9dfa 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -23,8 +23,8 @@ runners: os: ubuntu-24.04-16core-64gb <<: *base-job - - &job-macos-xl - os: macos-13 # We use the standard runner for now + - &job-macos + os: macos-13 <<: *base-job - &job-macos-m1 @@ -58,7 +58,7 @@ runners: <<: *base-job envs: env-x86_64-apple-tests: &env-x86_64-apple-tests - SCRIPT: ./x.py --stage 2 test --skip tests/ui --skip tests/rustdoc -- --exact + SCRIPT: ./x.py check compiletest --set build.compiletest-use-stage0-libtest=true && ./x.py --stage 2 test --skip tests/ui --skip tests/rustdoc -- --exact RUST_CONFIGURE_ARGS: --build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 # Ensure that host tooling is tested on our minimum supported macOS version. @@ -304,6 +304,31 @@ auto: - name: x86_64-gnu-distcheck <<: *job-linux-8c + # The x86_64-gnu-llvm-20 job is split into multiple jobs to run tests in parallel. + # x86_64-gnu-llvm-20-1 skips tests that run in x86_64-gnu-llvm-20-{2,3}. + - name: x86_64-gnu-llvm-20-1 + env: + RUST_BACKTRACE: 1 + IMAGE: x86_64-gnu-llvm-20 + DOCKER_SCRIPT: stage_2_test_set1.sh + <<: *job-linux-4c + + # Skip tests that run in x86_64-gnu-llvm-20-{1,3} + - name: x86_64-gnu-llvm-20-2 + env: + RUST_BACKTRACE: 1 + IMAGE: x86_64-gnu-llvm-20 + DOCKER_SCRIPT: x86_64-gnu-llvm2.sh + <<: *job-linux-4c + + # Skip tests that run in x86_64-gnu-llvm-20-{1,2} + - name: x86_64-gnu-llvm-20-3 + env: + RUST_BACKTRACE: 1 + IMAGE: x86_64-gnu-llvm-20 + DOCKER_SCRIPT: x86_64-gnu-llvm3.sh + <<: *job-linux-4c + # The x86_64-gnu-llvm-19 job is split into multiple jobs to run tests in parallel. # x86_64-gnu-llvm-19-1 skips tests that run in x86_64-gnu-llvm-19-{2,3}. - name: x86_64-gnu-llvm-19-1 @@ -355,7 +380,7 @@ auto: NO_OVERFLOW_CHECKS: 1 DIST_REQUIRE_ALL_TOOLS: 1 CODEGEN_BACKENDS: llvm,cranelift - <<: *job-macos-xl + <<: *job-macos - name: dist-apple-various env: @@ -372,18 +397,18 @@ auto: NO_LLVM_ASSERTIONS: 1 NO_DEBUG_ASSERTIONS: 1 NO_OVERFLOW_CHECKS: 1 - <<: *job-macos-xl + <<: *job-macos - name: x86_64-apple-1 env: <<: *env-x86_64-apple-tests - <<: *job-macos-xl + <<: *job-macos - name: x86_64-apple-2 env: SCRIPT: ./x.py --stage 2 test tests/ui tests/rustdoc <<: *env-x86_64-apple-tests - <<: *job-macos-xl + <<: *job-macos - name: dist-aarch64-apple env: diff --git a/src/doc/book b/src/doc/book index 45f05367360f..d33916341d48 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit 45f05367360f033f89235eacbbb54e8d73ce6b70 +Subproject commit d33916341d480caede1d0ae57cbeae23aab23e88 diff --git a/src/doc/edition-guide b/src/doc/edition-guide index 1e27e5e6d513..467f45637b73 160000 --- a/src/doc/edition-guide +++ b/src/doc/edition-guide @@ -1 +1 @@ -Subproject commit 1e27e5e6d5133ae4612f5cc195c15fc8d51b1c9c +Subproject commit 467f45637b73ec6aa70fb36bc3054bb50b8967ea diff --git a/src/doc/nomicon b/src/doc/nomicon index b4448fa406a6..0c10c30cc547 160000 --- a/src/doc/nomicon +++ b/src/doc/nomicon @@ -1 +1 @@ -Subproject commit b4448fa406a6dccde62d1e2f34f70fc51814cdcc +Subproject commit 0c10c30cc54736c5c194ce98c50e2de84eeb6e79 diff --git a/src/doc/reference b/src/doc/reference index e95ebdfee025..3340922df189 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit e95ebdfee02514d93f79ec92ae310a804e87f01f +Subproject commit 3340922df189bddcbaad17dc3927d51a76bcd5ed diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example index 6f69823c28ae..0d7964d5b22c 160000 --- a/src/doc/rust-by-example +++ b/src/doc/rust-by-example @@ -1 +1 @@ -Subproject commit 6f69823c28ae8d929d6c815181c73d3e99ef16d3 +Subproject commit 0d7964d5b22cf920237ef1282d869564b4883b88 diff --git a/src/doc/rustc-dev-guide/rust-version b/src/doc/rustc-dev-guide/rust-version index a6f295108797..67de4a981655 100644 --- a/src/doc/rustc-dev-guide/rust-version +++ b/src/doc/rustc-dev-guide/rust-version @@ -1 +1 @@ -25a615bf829b9f6d6f22da537e3851043f92e5f2 +a7c39b68616668a45f0afd62849a1da7c8ad2516 diff --git a/src/doc/rustc-dev-guide/src/appendix/glossary.md b/src/doc/rustc-dev-guide/src/appendix/glossary.md index a7c3236d356b..1837b59e850a 100644 --- a/src/doc/rustc-dev-guide/src/appendix/glossary.md +++ b/src/doc/rustc-dev-guide/src/appendix/glossary.md @@ -31,7 +31,6 @@ Term | Meaning generics | The list of generic parameters defined on an item. There are three kinds of generic parameters: Type, lifetime and const parameters. HIR | The _high-level [IR](#ir)_, created by lowering and desugaring the AST. ([see more](../hir.md)) `HirId` | Identifies a particular node in the HIR by combining a def-id with an "intra-definition offset". See [the HIR chapter for more](../hir.md#identifiers-in-the-hir). -HIR map | The HIR map, accessible via `tcx.hir()`, allows you to quickly navigate the HIR and convert between various forms of identifiers. ICE | Short for _internal compiler error_, this is when the compiler crashes. ICH | Short for _incremental compilation hash_, these are used as fingerprints for things such as HIR and crate metadata, to check if changes have been made. This is useful in incremental compilation to see if part of a crate has changed and should be recompiled. `infcx` | The type inference context (`InferCtxt`). (see `rustc_middle::infer`) diff --git a/src/doc/rustc-dev-guide/src/building/optimized-build.md b/src/doc/rustc-dev-guide/src/building/optimized-build.md index 0849464eab36..62dfaca89d24 100644 --- a/src/doc/rustc-dev-guide/src/building/optimized-build.md +++ b/src/doc/rustc-dev-guide/src/building/optimized-build.md @@ -109,11 +109,16 @@ like Python or LLVM. Here is an example of how can `opt-dist` be used locally (outside of CI): -1. Build the tool with the following command: +1. Enable metrics in your `bootstrap.toml` file, because `opt-dist` expects it to be enabled: + ```toml + [build] + metrics = true + ``` +2. Build the tool with the following command: ```bash ./x build tools/opt-dist ``` -2. Run the tool with the `local` mode and provide necessary parameters: +3. Run the tool with the `local` mode and provide necessary parameters: ```bash ./build/host/stage0-tools-bin/opt-dist local \ --target-triple \ # select target, e.g. "x86_64-unknown-linux-gnu" diff --git a/src/doc/rustc-dev-guide/src/compiler-debugging.md b/src/doc/rustc-dev-guide/src/compiler-debugging.md index 47f397620222..102e20207792 100644 --- a/src/doc/rustc-dev-guide/src/compiler-debugging.md +++ b/src/doc/rustc-dev-guide/src/compiler-debugging.md @@ -301,7 +301,8 @@ Right below you can find elaborate explainers on a selected few. Some compiler options for debugging specific features yield graphviz graphs - e.g. the `#[rustc_mir(borrowck_graphviz_postflow="suffix.dot")]` attribute -dumps various borrow-checker dataflow graphs. +on a function dumps various borrow-checker dataflow graphs in conjunction with +`-Zdump-mir-dataflow`. These all produce `.dot` files. To view these files, install graphviz (e.g. `apt-get install graphviz`) and then run the following commands: diff --git a/src/doc/rustc-dev-guide/src/hir.md b/src/doc/rustc-dev-guide/src/hir.md index 75f5a9e20452..0c1c9941572d 100644 --- a/src/doc/rustc-dev-guide/src/hir.md +++ b/src/doc/rustc-dev-guide/src/hir.md @@ -100,7 +100,7 @@ The HIR uses a bunch of different identifiers that coexist and serve different p a wrapper around a [`HirId`]. For more info about HIR bodies, please refer to the [HIR chapter][hir-bodies]. -These identifiers can be converted into one another through the [HIR map][map]. +These identifiers can be converted into one another through the `TyCtxt`. [`DefId`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/def_id/struct.DefId.html [`LocalDefId`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/def_id/struct.LocalDefId.html @@ -110,30 +110,24 @@ These identifiers can be converted into one another through the [HIR map][map]. [`CrateNum`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/def_id/struct.CrateNum.html [`DefIndex`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/def_id/struct.DefIndex.html [`Body`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/struct.Body.html -[hir-map]: ./hir.md#the-hir-map [hir-bodies]: ./hir.md#hir-bodies -[map]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/map/struct.Map.html -## The HIR Map +## HIR Operations Most of the time when you are working with the HIR, you will do so via -the **HIR Map**, accessible in the tcx via [`tcx.hir()`] (and defined in -the [`hir::map`] module). The [HIR map] contains a [number of methods] to -convert between IDs of various kinds and to lookup data associated -with a HIR node. +`TyCtxt`. It contains a number of methods, defined in the `hir::map` module and +mostly prefixed with `hir_`, to convert between IDs of various kinds and to +lookup data associated with a HIR node. -[`tcx.hir()`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html#method.hir -[`hir::map`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/map/index.html -[HIR map]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/map/struct.Map.html -[number of methods]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/map/struct.Map.html#methods +[`TyCtxt`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html For example, if you have a [`LocalDefId`], and you would like to convert it -to a [`HirId`], you can use [`tcx.hir().local_def_id_to_hir_id(def_id)`][local_def_id_to_hir_id]. +to a [`HirId`], you can use [`tcx.local_def_id_to_hir_id(def_id)`][local_def_id_to_hir_id]. You need a `LocalDefId`, rather than a `DefId`, since only local items have HIR nodes. -[local_def_id_to_hir_id]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/map/struct.Map.html#method.local_def_id_to_hir_id +[local_def_id_to_hir_id]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html#method.local_def_id_to_hir_id -Similarly, you can use [`tcx.hir().find(n)`][find] to lookup the node for a +Similarly, you can use [`tcx.hir_node(n)`][hir_node] to lookup the node for a [`HirId`]. This returns a `Option>`, where [`Node`] is an enum defined in the map. By matching on this, you can find out what sort of node the `HirId` referred to and also get a pointer to the data @@ -142,15 +136,16 @@ that `n` must be some HIR expression, you can do [`tcx.hir_expect_expr(n)`][expect_expr], which will extract and return the [`&hir::Expr`][Expr], panicking if `n` is not in fact an expression. -[find]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/map/struct.Map.html#method.find +[hir_node]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html#method.hir_node [`Node`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/enum.Node.html [expect_expr]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html#method.expect_expr [Expr]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/struct.Expr.html -Finally, you can use the HIR map to find the parents of nodes, via -calls like [`tcx.hir().get_parent(n)`][get_parent]. +Finally, you can find the parents of nodes, via +calls like [`tcx.parent_hir_node(n)`][parent_hir_node]. + +[parent_hir_node]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html#method.parent_hir_node -[get_parent]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/map/struct.Map.html#method.get_parent ## HIR Bodies @@ -158,10 +153,10 @@ A [`rustc_hir::Body`] represents some kind of executable code, such as the body of a function/closure or the definition of a constant. Bodies are associated with an **owner**, which is typically some kind of item (e.g. an `fn()` or `const`), but could also be a closure expression -(e.g. `|x, y| x + y`). You can use the HIR map to find the body -associated with a given def-id ([`maybe_body_owned_by`]) or to find -the owner of a body ([`body_owner_def_id`]). +(e.g. `|x, y| x + y`). You can use the `TyCtxt` to find the body +associated with a given def-id ([`hir_maybe_body_owned_by`]) or to find +the owner of a body ([`hir_body_owner_def_id`]). [`rustc_hir::Body`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/struct.Body.html -[`maybe_body_owned_by`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/map/struct.Map.html#method.maybe_body_owned_by -[`body_owner_def_id`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/map/struct.Map.html#method.body_owner_def_id +[`hir_maybe_body_owned_by`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html#method.hir_maybe_body_owned_by +[`hir_body_owner_def_id`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html#method.hir_body_owner_def_id diff --git a/src/doc/rustc-dev-guide/src/solve/opaque-types.md b/src/doc/rustc-dev-guide/src/solve/opaque-types.md index 672aab770801..509c34a4d3a7 100644 --- a/src/doc/rustc-dev-guide/src/solve/opaque-types.md +++ b/src/doc/rustc-dev-guide/src/solve/opaque-types.md @@ -33,7 +33,7 @@ For opaque types in the defining scope and in the implicit-negative coherence mo always done in two steps. Outside of the defining scope `normalizes-to` for opaques always returns `Err(NoSolution)`. -We start by trying to to assign the expected type as a hidden type. +We start by trying to assign the expected type as a hidden type. In the implicit-negative coherence mode, this currently always results in ambiguity without interacting with the opaque types storage. We could instead add allow 'defining' all opaque types, diff --git a/src/doc/rustc-dev-guide/src/tests/best-practices.md b/src/doc/rustc-dev-guide/src/tests/best-practices.md index 6905ee13283a..2bdc7f3a2431 100644 --- a/src/doc/rustc-dev-guide/src/tests/best-practices.md +++ b/src/doc/rustc-dev-guide/src/tests/best-practices.md @@ -175,6 +175,8 @@ See [compiletest directives] for a listing of directives. - For `ignore-*`/`needs-*`/`only-*` directives, unless extremely obvious, provide a brief remark on why the directive is needed. E.g. `"//@ ignore-wasi (wasi codegens the main symbol differently)"`. +- When using `//@ ignore-auxiliary`, specify the corresponding main test files, + e.g. ``//@ ignore-auxiliary (used by `./foo.rs`)``. ## FileCheck best practices diff --git a/src/doc/rustc-dev-guide/src/tests/directives.md b/src/doc/rustc-dev-guide/src/tests/directives.md index 8e4a710178ed..dae659e6317b 100644 --- a/src/doc/rustc-dev-guide/src/tests/directives.md +++ b/src/doc/rustc-dev-guide/src/tests/directives.md @@ -101,6 +101,7 @@ for more details. | `normalize-stdout` | Normalize actual stdout with a rule `"" -> ""` before comparing against snapshot | `ui`, `incremental` | `"" -> ""`, ``/`` is regex capture and replace syntax | | `dont-check-compiler-stderr` | Don't check actual compiler stderr vs stderr snapshot | `ui` | N/A | | `dont-check-compiler-stdout` | Don't check actual compiler stdout vs stdout snapshot | `ui` | N/A | +| `dont-require-annotations` | Don't require line annotations for the given diagnostic kind (`//~ KIND`) to be exhaustive | `ui`, `incremental` | `ERROR`, `WARN`, `NOTE`, `HELP`, `SUGGESTION` | | `run-rustfix` | Apply all suggestions via `rustfix`, snapshot fixed output, and check fixed output builds | `ui` | N/A | | `rustfix-only-machine-applicable` | `run-rustfix` but only machine-applicable suggestions | `ui` | N/A | | `exec-env` | Env var to set when executing a test | `ui`, `crashes` | `=` | @@ -123,6 +124,9 @@ means the test won't be compiled or run. * `ignore-X` where `X` is a target detail or other criteria on which to ignore the test (see below) * `only-X` is like `ignore-X`, but will *only* run the test on that target or stage +* `ignore-auxiliary` is intended for files that *participate* in one or more other + main test files but that `compiletest` should not try to build the file itself. + Please backlink to which main test is actually using the auxiliary file. * `ignore-test` always ignores the test. This can be used to temporarily disable a test if it is currently not working, but you want to keep it in tree to re-enable it later. @@ -191,8 +195,13 @@ settings: specified atomic widths, e.g. the test with `//@ needs-target-has-atomic: 8, 16, ptr` will only run if it supports the comma-separated list of atomic widths. -- `needs-dynamic-linking` - ignores if target does not support dynamic linking +- `needs-dynamic-linking` — ignores if target does not support dynamic linking (which is orthogonal to it being unable to create `dylib` and `cdylib` crate types) +- `needs-crate-type` — ignores if target platform does not support one or more + of the comma-delimited list of specified crate types. For example, + `//@ needs-crate-type: cdylib, proc-macro` will cause the test to be ignored + on `wasm32-unknown-unknown` target because the target does not support the + `proc-macro` crate type. The following directives will check LLVM support: @@ -229,14 +238,14 @@ ignoring debuggers. ### Affecting how tests are built -| Directive | Explanation | Supported test suites | Possible values | -|---------------------|----------------------------------------------------------------------------------------------|---------------------------|------------------------------------------------------------------------------| -| `compile-flags` | Flags passed to `rustc` when building the test or aux file | All except for `run-make` | Any valid `rustc` flags, e.g. `-Awarnings -Dfoo`. Cannot be `-Cincremental`. | -| `edition` | Alias for `compile-flags: --edition=xxx` | All except for `run-make` | Any valid `--edition` value | -| `rustc-env` | Env var to set when running `rustc` | All except for `run-make` | `=` | -| `unset-rustc-env` | Env var to unset when running `rustc` | All except for `run-make` | Any env var name | -| `incremental` | Proper incremental support for tests outside of incremental test suite | `ui`, `crashes` | N/A | -| `no-prefer-dynamic` | Don't use `-C prefer-dynamic`, don't build as a dylib via a `--crate-type=dylib` preset flag | `ui`, `crashes` | N/A | +| Directive | Explanation | Supported test suites | Possible values | +|---------------------|----------------------------------------------------------------------------------------------|---------------------------|--------------------------------------------------------------------------------------------| +| `compile-flags` | Flags passed to `rustc` when building the test or aux file | All except for `run-make` | Any valid `rustc` flags, e.g. `-Awarnings -Dfoo`. Cannot be `-Cincremental` or `--edition` | +| `edition` | The edition used to build the test | All except for `run-make` | Any valid `--edition` value | +| `rustc-env` | Env var to set when running `rustc` | All except for `run-make` | `=` | +| `unset-rustc-env` | Env var to unset when running `rustc` | All except for `run-make` | Any env var name | +| `incremental` | Proper incremental support for tests outside of incremental test suite | `ui`, `crashes` | N/A | +| `no-prefer-dynamic` | Don't use `-C prefer-dynamic`, don't build as a dylib via a `--crate-type=dylib` preset flag | `ui`, `crashes` | N/A |

Tests (outside of `run-make`) that want to use incremental tests not in the diff --git a/src/doc/rustc-dev-guide/src/tests/ui.md b/src/doc/rustc-dev-guide/src/tests/ui.md index e10bc2daadd0..7c4e2a0fdae7 100644 --- a/src/doc/rustc-dev-guide/src/tests/ui.md +++ b/src/doc/rustc-dev-guide/src/tests/ui.md @@ -303,8 +303,7 @@ It should be preferred to using `error-pattern`, which is imprecise and non-exha ### `error-pattern` The `error-pattern` [directive](directives.md) can be used for runtime messages, which don't -have a specific span, or for compile time messages if imprecise matching is required due to -multi-line platform specific diagnostics. +have a specific span, or in exceptional cases for compile time messages. Let's think about this test: @@ -318,7 +317,7 @@ fn main() { ``` We want to ensure this shows "index out of bounds" but we cannot use the `ERROR` -annotation since the error doesn't have any span. Then it's time to use the +annotation since the runtime error doesn't have any span. Then it's time to use the `error-pattern` directive: ```rust,ignore @@ -331,29 +330,51 @@ fn main() { } ``` -But for strict testing, try to use the `ERROR` annotation as much as possible, -including `//~?` annotations for diagnostics without span. -For compile time diagnostics `error-pattern` should very rarely be necessary. +Use of `error-pattern` is not recommended in general. -Per-line annotations (`//~`) are still checked in tests using `error-pattern`. -To opt out of these checks, use `//@ compile-flags: --error-format=human`. -Do that only in exceptional cases. +For strict testing of compile time output, try to use the line annotations `//~` as much as +possible, including `//~?` annotations for diagnostics without span. -### Error levels +If the compile time output is target dependent or too verbose, use directive +`//@ dont-require-annotations: ` to make the line annotation checking +non-exhaustive, some of the compiler messages can stay uncovered by annotations in this mode. -The error levels that you can have are: +For checking runtime output `//@ check-run-results` may be preferable. + +Only use `error-pattern` if none of the above works. + +Line annotations `//~` are still checked in tests using `error-pattern`. +In exceptional cases use `//@ compile-flags: --error-format=human` to opt out of these checks. + +### Diagnostic kinds (error levels) + +The diagnostic kinds that you can have are: - `ERROR` -- `WARN` or `WARNING` +- `WARN` (or `WARNING`) - `NOTE` -- `HELP` and `SUGGESTION` +- `HELP` +- `SUGGESTION` -You are allowed to not include a level, but you should include it at least for -the primary message. - -The `SUGGESTION` level is used for specifying what the expected replacement text +The `SUGGESTION` kind is used for specifying what the expected replacement text should be for a diagnostic suggestion. +`ERROR` and `WARN` kinds are required to be exhaustively covered by line annotations +`//~` by default. + +Other kinds only need to be line-annotated if at least one annotation of that kind appears +in the test file. For example, one `//~ NOTE` will also require all other `//~ NOTE`s in the file +to be written out explicitly. + +Use directive `//@ dont-require-annotations` to opt out of exhaustive annotations. +E.g. use `//@ dont-require-annotations: NOTE` to annotate notes selectively. +Avoid using this directive for `ERROR`s and `WARN`ings, unless there's a serious reason, like +target-dependent compiler output. + +Missing diagnostic kinds (`//~ message`) are currently accepted, but are being phased away. +They will match any compiler output kind, but will not force exhaustive annotations for that kind. +Prefer explicit kind and `//@ dont-require-annotations` to achieve the same effect. + UI tests use the `-A unused` flag by default to ignore all unused warnings, as unused warnings are usually not the focus of a test. However, simple code samples often have unused warnings. If the test is specifically testing an diff --git a/src/doc/rustc-dev-guide/src/ty.md b/src/doc/rustc-dev-guide/src/ty.md index b33d54035864..ce6cffec1adb 100644 --- a/src/doc/rustc-dev-guide/src/ty.md +++ b/src/doc/rustc-dev-guide/src/ty.md @@ -61,11 +61,11 @@ Here is a summary: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Describe the *syntax* of a type: what the user wrote (with some desugaring). | Describe the *semantics* of a type: the meaning of what the user wrote. | | Each `rustc_hir::Ty` has its own spans corresponding to the appropriate place in the program. | Doesn’t correspond to a single place in the user’s program. | -| `rustc_hir::Ty` has generics and lifetimes; however, some of those lifetimes are special markers like [`LifetimeName::Implicit`][implicit]. | `ty::Ty` has the full type, including generics and lifetimes, even if the user left them out | +| `rustc_hir::Ty` has generics and lifetimes; however, some of those lifetimes are special markers like [`LifetimeKind::Implicit`][implicit]. | `ty::Ty` has the full type, including generics and lifetimes, even if the user left them out | | `fn foo(x: u32) → u32 { }` - Two `rustc_hir::Ty` representing each usage of `u32`, each has its own `Span`s, and `rustc_hir::Ty` doesn’t tell us that both are the same type | `fn foo(x: u32) → u32 { }` - One `ty::Ty` for all instances of `u32` throughout the program, and `ty::Ty` tells us that both usages of `u32` mean the same type. | -| `fn foo(x: &u32) -> &u32)` - Two `rustc_hir::Ty` again. Lifetimes for the references show up in the `rustc_hir::Ty`s using a special marker, [`LifetimeName::Implicit`][implicit]. | `fn foo(x: &u32) -> &u32)`- A single `ty::Ty`. The `ty::Ty` has the hidden lifetime param. | +| `fn foo(x: &u32) -> &u32)` - Two `rustc_hir::Ty` again. Lifetimes for the references show up in the `rustc_hir::Ty`s using a special marker, [`LifetimeKind::Implicit`][implicit]. | `fn foo(x: &u32) -> &u32)`- A single `ty::Ty`. The `ty::Ty` has the hidden lifetime param. | -[implicit]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/enum.LifetimeName.html#variant.Implicit +[implicit]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/enum.LifetimeKind.html#variant.Implicit **Order** @@ -323,4 +323,4 @@ When looking at the debug output of `Ty` or simply talking about different types - Generic parameters: `{name}/#{index}` e.g. `T/#0`, where `index` corresponds to its position in the list of generic parameters - Inference variables: `?{id}` e.g. `?x`/`?0`, where `id` identifies the inference variable - Variables from binders: `^{binder}_{index}` e.g. `^0_x`/`^0_2`, where `binder` and `index` identify which variable from which binder is being referred to -- Placeholders: `!{id}` or `!{id}_{universe}` e.g. `!x`/`!0`/`!x_2`/`!0_2`, representing some unique type in the specified universe. The universe is often elided when it is `0` \ No newline at end of file +- Placeholders: `!{id}` or `!{id}_{universe}` e.g. `!x`/`!0`/`!x_2`/`!0_2`, representing some unique type in the specified universe. The universe is often elided when it is `0` diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index 9bb64adfa786..cf41f5b86a85 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -78,6 +78,7 @@ - [illumos](platform-support/illumos.md) - [loongarch\*-unknown-linux-\*](platform-support/loongarch-linux.md) - [loongarch\*-unknown-none\*](platform-support/loongarch-none.md) + - [\*-lynxos178-\*](platform-support/lynxos178.md) - [m68k-unknown-linux-gnu](platform-support/m68k-unknown-linux-gnu.md) - [m68k-unknown-none-elf](platform-support/m68k-unknown-none-elf.md) - [mips64-openwrt-linux-musl](platform-support/mips64-openwrt-linux-musl.md) diff --git a/src/doc/rustc/src/codegen-options/index.md b/src/doc/rustc/src/codegen-options/index.md index 8c1769a8c772..a3b70e7f9771 100644 --- a/src/doc/rustc/src/codegen-options/index.md +++ b/src/doc/rustc/src/codegen-options/index.md @@ -110,6 +110,19 @@ It takes a path to [the dlltool executable](https://sourceware.org/binutils/docs If this flag is not specified, a dlltool executable will be inferred based on the host environment and target. +## 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 Android). +* `3`: DWARF version 3 (the default on certain platforms, like AIX). +* `4`: DWARF version 4 (the default on most platforms, like Linux & macOS). +* `5`: DWARF version 5. + +DWARF version 1 is not supported. + ## embed-bitcode This flag controls whether or not the compiler embeds LLVM bitcode into object diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 4149b4cb9202..9870e5011ebf 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -407,6 +407,7 @@ target | std | host | notes [`wasm32-wali-linux-musl`](platform-support/wasm32-wali-linux.md) | ? | | WebAssembly with [WALI](https://github.com/arjunr2/WALI) [`x86_64-apple-tvos`](platform-support/apple-tvos.md) | ✓ | | x86 64-bit tvOS [`x86_64-apple-watchos-sim`](platform-support/apple-watchos.md) | ✓ | | x86 64-bit Apple WatchOS simulator +[`x86_64-lynx-lynxos178`](platform-support/lynxos178.md) | | | x86_64 LynxOS-178 [`x86_64-pc-cygwin`](platform-support/x86_64-pc-cygwin.md) | ✓ | | 64-bit x86 Cygwin | [`x86_64-pc-nto-qnx710`](platform-support/nto-qnx.md) | ✓ | | x86 64-bit QNX Neutrino 7.1 RTOS with default network stack (io-pkt) | [`x86_64-pc-nto-qnx710_iosock`](platform-support/nto-qnx.md) | ✓ | | x86 64-bit QNX Neutrino 7.1 RTOS with new network stack (io-sock) | diff --git a/src/doc/rustc/src/platform-support/lynxos178.md b/src/doc/rustc/src/platform-support/lynxos178.md new file mode 100644 index 000000000000..6463f95a0b8e --- /dev/null +++ b/src/doc/rustc/src/platform-support/lynxos178.md @@ -0,0 +1,77 @@ +# `*-lynxos178-*` + +**Tier: 3** + +Targets for the LynxOS-178 operating system. + +[LynxOS-178](https://www.lynx.com/products/lynxos-178-do-178c-certified-posix-rtos) +is a commercial RTOS designed for safety-critical real-time systems. It is +developed by Lynx Software Technologies as part of the +[MOSA.ic](https://www.lynx.com/solutions/safe-and-secure-operating-environment) +product suite. + +Target triples available: +- `x86_64-lynx-lynxos178` + +## Target maintainers + +- Renat Fatykhov, https://github.com/rfatykhov-lynx + +## Requirements + +To build Rust programs for LynxOS-178, you must first have LYNX MOSA.ic +installed on the build machine. + +This target supports only cross-compilation, from the same hosts supported by +the Lynx CDK. + +Currently only `no_std` programs are supported. Work to support `std` is in +progress. + +## Building the target + +You can build Rust with support for x86_64-lynx-lynxos178 by adding that +to the `target` list in `config.toml`, and then running `./x build --target +x86_64-lynx-lynxos178 compiler`. + +## Building Rust programs + +Rust does not yet ship pre-compiled artifacts for this target. To compile for +this target, you will need to build Rust with the target enabled (see "Building +the target" above). + +Before executing `cargo`, you must configure the environment to build LynxOS-178 +binaries by running `source setup.sh` from the los178 directory. + +If your program/crates contain procedural macros, Rust must be able to build +binaries for the host as well. The host gcc is hidden by sourcing setup.sh. To +deal with this, add the following to your project's `.cargo/config.toml`: +```toml +[target.x86_64-unknown-linux-gnu] +linker = "lynx-host-gcc" +``` +(If necessary substitute your host target triple for x86_64-unknown-linux-gnu.) + +To point `cargo` at the correct rustc binary, set the RUSTC environment +variable. + +The core library should be usable. You can try by building it as part of your +project: +```bash +cargo +nightly build -Z build-std=core --target x86_64-lynx-lynxos178 +``` + +## Testing + +Binaries built with rust can be provided to a LynxOS-178 instance on its file +system, where they can be executed. Rust binaries tend to be large, so it may +be necessary to strip them first. + +It is possible to run the Rust testsuite by providing a test runner that takes +the test binary and executes it under LynxOS-178. Most (all?) tests won't run +without std support though, which is not yet supported. + +## Cross-compilation toolchains and C code + +LYNX MOSA.ic comes with all the tools required to cross-compile C code for +LynxOS-178. diff --git a/src/doc/style-guide/src/expressions.md b/src/doc/style-guide/src/expressions.md index 12037b5992ec..031e59d86e1d 100644 --- a/src/doc/style-guide/src/expressions.md +++ b/src/doc/style-guide/src/expressions.md @@ -521,8 +521,11 @@ self.pre_comment.as_ref().map_or( ## Control flow expressions -This section covers `if`, `if let`, `loop`, `while`, `while let`, and `for` -expressions. +This section covers `for` and `loop` expressions, as well as `if` and `while` +expressions with their sub-expression variants. This includes those with a +single `let` sub-expression (i.e. `if let` and `while let`) +as well as "let-chains": those with one or more `let` sub-expressions and +one or more bool-type conditions (i.e. `if a && let Some(b) = c`). Put the keyword, any initial clauses, and the opening brace of the block all on a single line, if they fit. Apply the usual rules for [block @@ -548,10 +551,11 @@ if let ... { } ``` -If the control line needs to be broken, prefer to break before the `=` in `* -let` expressions and before `in` in a `for` expression; block-indent the -following line. If the control line is broken for any reason, put the opening -brace on its own line, not indented. Examples: +If the control line needs to be broken, then prefer breaking after the `=` for any +`let` sub-expression in an `if` or `while` expression that does not fit, +and before `in` in a `for` expression; the following line should be block indented. +If the control line is broken for any reason, then the opening brace should be on its +own line and not indented. Examples: ```rust while let Some(foo) @@ -572,6 +576,68 @@ if a_long_expression { ... } + +if let Some(a) = b + && another_long_expression + && a_third_long_expression +{ + // ... +} + +if let Some(relatively_long_thing) + = a_long_expression + && another_long_expression + && a_third_long_expression +{ + // ... +} + +if some_expr + && another_long_expression + && let Some(relatively_long_thing) = + a_long_long_long_long_long_long_really_reallllllllllyyyyyyy_long_expression + && a_third_long_expression +{ + // ... +} +``` + +A let-chain control line is allowed to be formatted on a single line provided +it only consists of two clauses, with the first, left-hand side operand being a literal or an +`ident` (which can optionally be preceded by any number of unary prefix operators), +and the second, right-hand side operand being a single-line `let` clause. Otherwise, +the control line must be broken and formatted according to the above rules. For example: + +```rust +if a && let Some(b) = foo() { + // ... +} + +if true && let Some(b) = foo() { + // ... +} + +let operator = if !from_hir_call && let Some(p) = parent { + // ... +}; + +if let Some(b) = foo() + && a +{ + // .. +} + +if foo() + && let Some(b) = bar +{ + // ... +} + +if gen_pos != GenericArgPosition::Type + && let Some(b) = gen_args.bindings.first() +{ + // .. +} ``` Where the initial clause spans multiple lines and ends with one or more closing diff --git a/src/doc/unstable-book/src/compiler-flags/allow-features.md b/src/doc/unstable-book/src/compiler-flags/allow-features.md new file mode 100644 index 000000000000..84fa465c89b4 --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/allow-features.md @@ -0,0 +1,14 @@ +# `allow-features` + +This feature is perma-unstable and has no tracking issue. + +---- + +This flag allows limiting the features which can be enabled with `#![feature(...)]` attributes. +By default, all features are allowed on nightly and no features are allowed on stable or beta (but see [`RUSTC_BOOTSTRAP`]). + +Features are comma-separated, for example `-Z allow-features=ffi_pure,f16`. +If the flag is present, any feature listed will be allowed and any feature not listed will be disallowed. +Any unrecognized feature is ignored. + +[`RUSTC_BOOTSTRAP`]: ./rustc-bootstrap.html diff --git a/src/doc/unstable-book/src/compiler-flags/dwarf-version.md b/src/doc/unstable-book/src/compiler-flags/dwarf-version.md deleted file mode 100644 index e88799d2cf04..000000000000 --- a/src/doc/unstable-book/src/compiler-flags/dwarf-version.md +++ /dev/null @@ -1,13 +0,0 @@ -## `dwarf-version` - -The tracking issue for this feature is: - ----------------------------- - -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/rustc-bootstrap.md b/src/doc/unstable-book/src/compiler-flags/rustc-bootstrap.md new file mode 100644 index 000000000000..6895f2322386 --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/rustc-bootstrap.md @@ -0,0 +1,56 @@ +# `RUSTC_BOOTSTRAP` + +This feature is perma-unstable and has no tracking issue. + +---- + +The `RUSTC_BOOTSTRAP` environment variable tells rustc to act as if it is a nightly compiler; +in particular, it allows `#![feature(...)]` attributes and `-Z` flags even on the stable release channel. + +Setting `RUSTC_BOOTSTRAP=1` instructs rustc to enable this for all crates. +Setting `RUSTC_BOOTSTRAP=crate_name` instructs rustc to only apply this to crates named `crate_name`. +Setting `RUSTC_BOOTSTRAP=-1` instructs rustc to act as if it is a stable compiler, even on the nightly release channel. +Cargo disallows setting `cargo::rustc-env=RUSTC_BOOTSTRAP` in build scripts. +Build systems can limit the features they enable with [`-Z allow-features=feature1,feature2`][Z-allow-features]. +Crates can fully opt out of unstable features by using [`#![forbid(unstable_features)]`][unstable-features] at the crate root (or any other way of enabling lints, such as `-F unstable-features`). + +[Z-allow-features]: ./allow-features.html +[unstable-features]: ../../rustc/lints/listing/allowed-by-default.html#unstable-features + +## Why does this environment variable exist? + +`RUSTC_BOOTSTRAP`, as the name suggests, is used for bootstrapping the compiler from an earlier version. +In particular, nightly is built with beta, and beta is built with stable. +Since the standard library and compiler both use unstable features, `RUSTC_BOOTSTRAP` is required so that we can use the previous version to build them. + +## Why is this environment variable so easy to use for people not in the rust project? + +Originally, `RUSTC_BOOTSTRAP` required passing in a hash of the previous compiler version, to discourage using it for any purpose other than bootstrapping. +That constraint was later relaxed; see for the discussion that happened at that time. + +People have at various times proposed re-adding the technical constraints. +However, doing so is extremely disruptive for several major projects that we very much want to keep using the latest stable toolchain version, such as Firefox, Rust for Linux, and Chromium. +We continue to allow `RUSTC_BOOTSTRAP` until we can come up with an alternative that does not disrupt our largest constituents. + +## Stability policy + +Despite being usable on stable, this is an unstable feature. +Like any other unstable feature, we reserve the right to change or remove this feature in the future, as well as any other unstable feature that it enables. +Using this feature opts you out of the normal stability/backwards compatibility guarantee of stable. + +Although we do not take technical measures to prevent it from being used, we strongly discourage using this feature. +If at all possible, please contribute to stabilizing the features you care about instead of bypassing the Rust project's stability policy. + +For library crates, we especially discourage the use of this feature. +The crates depending on you do not know that you use this feature, have little recourse if it breaks, and can be used in contexts that are hard to predict. + +For libraries that do use this feature, please document the versions you support (including a *maximum* as well as minimum version), and a mechanism to disable it. +If you do not have a mechanism to disable the use of `RUSTC_BOOTSTRAP`, consider removing its use altogether, such that people can only use your library if they are already using a nightly toolchain. +This leaves the choice of whether to opt-out of Rust's stability guarantees up to the end user building their code. + +## History + +- [Allowed without a hash](https://github.com/rust-lang/rust/pull/37265) ([discussion](https://github.com/rust-lang/rust/issues/36548)) +- [Extended to crate names](https://github.com/rust-lang/rust/pull/77802) ([discussion](https://github.com/rust-lang/cargo/issues/7088)) +- [Disallowed for build scripts](https://github.com/rust-lang/cargo/pull/9181) ([discussion](https://github.com/rust-lang/compiler-team/issues/350)) +- [Extended to emulate stable](https://github.com/rust-lang/rust/pull/132993) ([discussion](https://github.com/rust-lang/rust/issues/123404)) diff --git a/src/doc/unstable-book/src/compiler-flags/rustc-override-version-string.md b/src/doc/unstable-book/src/compiler-flags/rustc-override-version-string.md new file mode 100644 index 000000000000..3d867b5f7146 --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/rustc-override-version-string.md @@ -0,0 +1,39 @@ +# `RUSTC_OVERRIDE_VERSION_STRING` + +This feature is perma-unstable and has no tracking issue. + +---- + +The `RUSTC_OVERRIDE_VERSION_STRING` environment variable overrides the version reported by `rustc --version`. For example: + +```console +$ rustc --version +rustc 1.87.0-nightly (43f0014ef 2025-03-25) +$ env RUSTC_OVERRIDE_VERSION_STRING=1.81.0-nightly rustc --version +rustc 1.81.0-nightly +``` + +Note that the version string is completely overwritten; i.e. rustc discards commit hash and commit date information unless it is explicitly included in the environment variable. The string only applies to the "release" part of the version; for example: +```console +$ RUSTC_OVERRIDE_VERSION_STRING="1.81.0-nightly (aaaaaaaaa 2025-03-22)" rustc -vV +rustc 1.81.0-nightly (aaaaaaaaa 2025-03-22) +binary: rustc +commit-hash: 43f0014ef0f242418674f49052ed39b70f73bc1c +commit-date: 2025-03-25 +host: x86_64-unknown-linux-gnu +release: 1.81.0-nightly (aaaaaaaaa 2025-03-22) +LLVM version: 20.1.1 +``` + +Note here that `commit-hash` and `commit-date` do not match the values in the string, and `release` includes the fake hash and date. + +This variable has no effect on whether or not unstable features are allowed to be used. It only affects the output of `--version`. + +## Why does this environment variable exist? + +Various library crates have incomplete or incorrect feature detection. +This environment variable allows bisecting crates that do incorrect detection with `version_check::supports_feature`. + +This is not intended to be used for any other case (and, except for bisection, is not particularly useful). + +See for further discussion. diff --git a/src/doc/unstable-book/src/language-features/box-patterns.md b/src/doc/unstable-book/src/language-features/box-patterns.md index a1ac09633b75..c8a15b8477ee 100644 --- a/src/doc/unstable-book/src/language-features/box-patterns.md +++ b/src/doc/unstable-book/src/language-features/box-patterns.md @@ -6,6 +6,8 @@ The tracking issue for this feature is: [#29641] ------------------------ +> **Note**: This feature will be superseded by [`deref_patterns`] in the future. + Box patterns let you match on `Box`s: @@ -28,3 +30,5 @@ fn main() { } } ``` + +[`deref_patterns`]: ./deref-patterns.md diff --git a/src/doc/unstable-book/src/language-features/cfg-boolean-literals.md b/src/doc/unstable-book/src/language-features/cfg-boolean-literals.md deleted file mode 100644 index ad795ff9d9b2..000000000000 --- a/src/doc/unstable-book/src/language-features/cfg-boolean-literals.md +++ /dev/null @@ -1,22 +0,0 @@ -# `cfg_boolean_literals` - -The tracking issue for this feature is: [#131204] - -[#131204]: https://github.com/rust-lang/rust/issues/131204 - ------------------------- - -The `cfg_boolean_literals` feature makes it possible to use the `true`/`false` -literal as cfg predicate. They always evaluate to true/false respectively. - -## Examples - -```rust -#![feature(cfg_boolean_literals)] - -#[cfg(true)] -const A: i32 = 5; - -#[cfg(all(false))] -const A: i32 = 58 * 89; -``` diff --git a/src/doc/unstable-book/src/language-features/deref-patterns.md b/src/doc/unstable-book/src/language-features/deref-patterns.md new file mode 100644 index 000000000000..d0102a665b0b --- /dev/null +++ b/src/doc/unstable-book/src/language-features/deref-patterns.md @@ -0,0 +1,57 @@ +# `deref_patterns` + +The tracking issue for this feature is: [#87121] + +[#87121]: https://github.com/rust-lang/rust/issues/87121 + +------------------------ + +> **Note**: This feature is incomplete. In the future, it is meant to supersede +> [`box_patterns`](./box-patterns.md) and [`string_deref_patterns`](./string-deref-patterns.md). + +This feature permits pattern matching on [smart pointers in the standard library] through their +`Deref` target types, either implicitly or with explicit `deref!(_)` patterns (the syntax of which +is currently a placeholder). + +```rust +#![feature(deref_patterns)] +#![allow(incomplete_features)] + +let mut v = vec![Box::new(Some(0))]; + +// Implicit dereferences are inserted when a pattern can match against the +// result of repeatedly dereferencing but can't match against a smart +// pointer itself. This works alongside match ergonomics for references. +if let [Some(x)] = &mut v { + *x += 1; +} + +// Explicit `deref!(_)` patterns may instead be used when finer control is +// needed, e.g. to dereference only a single smart pointer, or to bind the +// the result of dereferencing to a variable. +if let deref!([deref!(opt_x @ Some(1))]) = &mut v { + opt_x.as_mut().map(|x| *x += 1); +} + +assert_eq!(v, [Box::new(Some(2))]); +``` + +Without this feature, it may be necessary to introduce temporaries to represent dereferenced places +when matching on nested structures: + +```rust +let mut v = vec![Box::new(Some(0))]; +if let [b] = &mut *v { + if let Some(x) = &mut **b { + *x += 1; + } +} +if let [b] = &mut *v { + if let opt_x @ Some(1) = &mut **b { + opt_x.as_mut().map(|x| *x += 1); + } +} +assert_eq!(v, [Box::new(Some(2))]); +``` + +[smart pointers in the standard library]: https://doc.rust-lang.org/std/ops/trait.DerefPure.html#implementors diff --git a/src/doc/unstable-book/src/language-features/explicit-extern-abis.md b/src/doc/unstable-book/src/language-features/explicit-extern-abis.md new file mode 100644 index 000000000000..ba622466ba74 --- /dev/null +++ b/src/doc/unstable-book/src/language-features/explicit-extern-abis.md @@ -0,0 +1,23 @@ +# `explicit_extern_abis` + +The tracking issue for this feature is: #134986 + +------ + +Disallow `extern` without an explicit ABI. We should write `extern "C"` +(or another ABI) instead of just `extern`. + +By making the ABI explicit, it becomes much clearer that "C" is just one of the +possible choices, rather than the "standard" way for external functions. +Removing the default makes it easier to add a new ABI on equal footing as "C". + +```rust,editionfuture,compile_fail +#![feature(explicit_extern_abis)] + +extern fn function1() {} // ERROR `extern` declarations without an explicit ABI + // are disallowed + +extern "C" fn function2() {} // compiles + +extern "aapcs" fn function3() {} // compiles +``` diff --git a/src/doc/unstable-book/src/language-features/intrinsics.md b/src/doc/unstable-book/src/language-features/intrinsics.md index 975b400447eb..9e59dd889985 100644 --- a/src/doc/unstable-book/src/language-features/intrinsics.md +++ b/src/doc/unstable-book/src/language-features/intrinsics.md @@ -52,9 +52,9 @@ with any regular function. Various intrinsics have native MIR operations that they correspond to. Instead of requiring backends to implement both the intrinsic and the MIR operation, the `lower_intrinsics` pass will convert the calls to the MIR operation. Backends do not need to know about these intrinsics -at all. These intrinsics only make sense without a body, and can either be declared as a "rust-intrinsic" -or as a `#[rustc_intrinsic]`. The body is never used, as calls to the intrinsic do not exist -anymore after MIR analyses. +at all. These intrinsics only make sense without a body, and can be declared as a `#[rustc_intrinsic]`. +The body is never used as the lowering pass implements support for all backends, so we never have to +use the fallback logic. ## Intrinsics without fallback logic @@ -70,28 +70,3 @@ These are written without a body: #[rustc_intrinsic] pub fn abort() -> !; ``` - -### Legacy extern ABI based intrinsics - -*This style is deprecated, always prefer the above form.* - -These are imported as if they were FFI functions, with the special -`rust-intrinsic` ABI. For example, if one was in a freestanding -context, but wished to be able to `transmute` between types, and -perform efficient pointer arithmetic, one would import those functions -via a declaration like - -```rust -#![feature(intrinsics)] -#![allow(internal_features)] -# fn main() {} - -extern "rust-intrinsic" { - fn transmute(x: T) -> U; - - fn arith_offset(dst: *const T, offset: isize) -> *const T; -} -``` - -As with any other FFI functions, these are by default always `unsafe` to call. -You can add `#[rustc_safe_intrinsic]` to the intrinsic to make it safe to call. diff --git a/src/doc/unstable-book/src/language-features/macro-metavar-expr-concat.md b/src/doc/unstable-book/src/language-features/macro-metavar-expr-concat.md new file mode 100644 index 000000000000..b6dbdb144077 --- /dev/null +++ b/src/doc/unstable-book/src/language-features/macro-metavar-expr-concat.md @@ -0,0 +1,133 @@ +# `macro_metavar_expr_concat` + +The tracking issue for this feature is: [#124225] + +------------------------ + +In stable Rust, there is no way to create new identifiers by joining identifiers to literals or other identifiers without using procedural macros such as [`paste`]. + `#![feature(macro_metavar_expr_concat)]` introduces a way to do this, using the concat metavariable expression. + +> This feature uses the syntax from [`macro_metavar_expr`] but is otherwise +> independent. It replaces the old unstable feature [`concat_idents`]. + +> This is an experimental feature; it and its syntax will require a RFC before stabilization. + + +### Overview + +`#![feature(macro_metavar_expr_concat)]` provides the `concat` metavariable expression for creating new identifiers: + +```rust +#![feature(macro_metavar_expr_concat)] + +macro_rules! create_some_structs { + ($name:ident) => { + pub struct ${ concat(First, $name) }; + pub struct ${ concat(Second, $name) }; + pub struct ${ concat(Third, $name) }; + } +} + +create_some_structs!(Thing); +``` + +This macro invocation expands to: + +```rust +pub struct FirstThing; +pub struct SecondThing; +pub struct ThirdThing; +``` + +### Syntax + +This feature builds upon the metavariable expression syntax `${ .. }` as specified in [RFC 3086] ([`macro_metavar_expr`]). + `concat` is available like `${ concat(items) }`, where `items` is a comma separated sequence of idents and/or literals. + +### Examples + +#### Create a function or method with a concatenated name + +```rust +#![feature(macro_metavar_expr_concat)] + +macro_rules! make_getter { + ($name:ident, $field: ident, $ret:ty) => { + impl $name { + pub fn ${ concat(get_, $field) }(&self) -> &$ret { + &self.$field + } + } + } +} + +pub struct Thing { + description: String, +} + +make_getter!(Thing, description, String); +``` + +This expands to: + +```rust +pub struct Thing { + description: String, +} + +impl Thing { + pub fn get_description(&self) -> &String { + &self.description + } +} +``` + +#### Create names for macro generated tests + +```rust +#![feature(macro_metavar_expr_concat)] + +macro_rules! test_math { + ($integer:ident) => { + #[test] + fn ${ concat(test_, $integer, _, addition) } () { + let a: $integer = 73; + let b: $integer = 42; + assert_eq!(a + b, 115) + } + + #[test] + fn ${ concat(test_, $integer, _, subtraction) } () { + let a: $integer = 73; + let b: $integer = 42; + assert_eq!(a - b, 31) + } + } +} + +test_math!(i32); +test_math!(u64); +test_math!(u128); +``` + +Running this returns the following output: + +```text +running 6 tests +test test_i32_subtraction ... ok +test test_i32_addition ... ok +test test_u128_addition ... ok +test test_u128_subtraction ... ok +test test_u64_addition ... ok +test test_u64_subtraction ... ok + +test result: ok. 6 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s +``` + +[`paste`]: https://crates.io/crates/paste +[RFC 3086]: https://rust-lang.github.io/rfcs/3086-macro-metavar-expr.html +[`concat_idents!`]: https://doc.rust-lang.org/nightly/std/macro.concat_idents.html +[`macro_metavar_expr`]: ../language-features/macro-metavar-expr.md +[`concat_idents`]: ../library-features/concat-idents.md +[#124225]: https://github.com/rust-lang/rust/issues/124225 +[declarative macros]: https://doc.rust-lang.org/stable/reference/macros-by-example.html diff --git a/src/doc/unstable-book/src/language-features/macro-metavar-expr.md b/src/doc/unstable-book/src/language-features/macro-metavar-expr.md new file mode 100644 index 000000000000..7ce64c1a3549 --- /dev/null +++ b/src/doc/unstable-book/src/language-features/macro-metavar-expr.md @@ -0,0 +1,10 @@ +# `macro_metavar_expr` + +The tracking issue for this feature is: [#83527] + +------------------------ + +> This feature is not to be confused with [`macro_metavar_expr_concat`]. + +[`macro_metavar_expr_concat`]: ./macro-metavar-expr-concat.md +[#83527]: https://github.com/rust-lang/rust/issues/83527 diff --git a/src/doc/unstable-book/src/language-features/offset-of-enum.md b/src/doc/unstable-book/src/language-features/offset-of-enum.md index 1960d6299eb0..78c0d87f639e 100644 --- a/src/doc/unstable-book/src/language-features/offset-of-enum.md +++ b/src/doc/unstable-book/src/language-features/offset-of-enum.md @@ -1,4 +1,4 @@ -# `offset_of_slice` +# `offset_of_enum` The tracking issue for this feature is: [#120141] diff --git a/src/doc/unstable-book/src/language-features/string-deref-patterns.md b/src/doc/unstable-book/src/language-features/string-deref-patterns.md index 3723830751e8..366bb15d4ea8 100644 --- a/src/doc/unstable-book/src/language-features/string-deref-patterns.md +++ b/src/doc/unstable-book/src/language-features/string-deref-patterns.md @@ -6,6 +6,8 @@ The tracking issue for this feature is: [#87121] ------------------------ +> **Note**: This feature will be superseded by [`deref_patterns`] in the future. + This feature permits pattern matching `String` to `&str` through [its `Deref` implementation]. ```rust @@ -42,4 +44,5 @@ pub fn is_it_the_answer(value: Value) -> bool { } ``` +[`deref_patterns`]: ./deref-patterns.md [its `Deref` implementation]: https://doc.rust-lang.org/std/string/struct.String.html#impl-Deref-for-String diff --git a/src/doc/unstable-book/src/library-features/concat-idents.md b/src/doc/unstable-book/src/library-features/concat-idents.md index 73f6cfa21787..4366172fb996 100644 --- a/src/doc/unstable-book/src/library-features/concat-idents.md +++ b/src/doc/unstable-book/src/library-features/concat-idents.md @@ -6,6 +6,8 @@ The tracking issue for this feature is: [#29599] ------------------------ +> This feature is expected to be superseded by [`macro_metavar_expr_concat`](../language-features/macro-metavar-expr-concat.md). + The `concat_idents` feature adds a macro for concatenating multiple identifiers into one identifier. diff --git a/src/etc/natvis/libcore.natvis b/src/etc/natvis/libcore.natvis index 8a441cf20935..8fe87a999895 100644 --- a/src/etc/natvis/libcore.natvis +++ b/src/etc/natvis/libcore.natvis @@ -69,9 +69,9 @@ - Pin({(void*)__pointer}: {__pointer}) + Pin({(void*)pointer}: {pointer}) - __pointer + pointer diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index 909b81a723b4..27ae0553c60d 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -9,7 +9,7 @@ path = "lib.rs" [dependencies] arrayvec = { version = "0.7", default-features = false } -rinja = { version = "0.3", default-features = false, features = ["config"] } +askama = { version = "0.13", default-features = false, features = ["alloc", "config", "derive"] } base64 = "0.21.7" itertools = "0.12" indexmap = "2" diff --git a/src/librustdoc/rinja.toml b/src/librustdoc/askama.toml similarity index 100% rename from src/librustdoc/rinja.toml rename to src/librustdoc/askama.toml diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index a48f5c623cd2..138ac3c97f7b 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -182,7 +182,7 @@ fn clean_param_env<'tcx>( .is_some_and(|pred| tcx.lang_items().sized_trait() == Some(pred.def_id())) }) .map(|pred| { - fold_regions(tcx, pred, |r, _| match *r { + fold_regions(tcx, pred, |r, _| match r.kind() { // FIXME: Don't `unwrap_or`, I think we should panic if we encounter an infer var that // we can't map to a concrete region. However, `AutoTraitFinder` *does* leak those kinds // of `ReVar`s for some reason at the time of writing. See `rustdoc-ui/` tests. @@ -362,7 +362,7 @@ fn clean_region_outlives_constraints<'tcx>( } fn early_bound_region_name(region: Region<'_>) -> Option { - match *region { + match region.kind() { ty::ReEarlyParam(r) => Some(r.name), _ => None, } diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index e0e09b53fc28..55a116a018a8 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -67,9 +67,13 @@ pub(crate) fn try_inline( record_extern_fqn(cx, did, ItemType::Trait); cx.with_param_env(did, |cx| { build_impls(cx, did, attrs_without_docs, &mut ret); - clean::TraitItem(Box::new(build_external_trait(cx, did))) + clean::TraitItem(Box::new(build_trait(cx, did))) }) } + Res::Def(DefKind::TraitAlias, did) => { + record_extern_fqn(cx, did, ItemType::TraitAlias); + cx.with_param_env(did, |cx| clean::TraitAliasItem(build_trait_alias(cx, did))) + } Res::Def(DefKind::Fn, did) => { record_extern_fqn(cx, did, ItemType::Function); cx.with_param_env(did, |cx| { @@ -251,7 +255,7 @@ pub(crate) fn record_extern_fqn(cx: &mut DocContext<'_>, did: DefId, kind: ItemT } } -pub(crate) fn build_external_trait(cx: &mut DocContext<'_>, did: DefId) -> clean::Trait { +pub(crate) fn build_trait(cx: &mut DocContext<'_>, did: DefId) -> clean::Trait { let trait_items = cx .tcx .associated_items(did) @@ -263,11 +267,18 @@ pub(crate) fn build_external_trait(cx: &mut DocContext<'_>, did: DefId) -> clean let predicates = cx.tcx.predicates_of(did); let generics = clean_ty_generics(cx, cx.tcx.generics_of(did), predicates); let generics = filter_non_trait_generics(did, generics); - let (generics, supertrait_bounds) = separate_supertrait_bounds(generics); + let (generics, supertrait_bounds) = separate_self_bounds(generics); clean::Trait { def_id: did, generics, items: trait_items, bounds: supertrait_bounds } } -pub(crate) fn build_function(cx: &mut DocContext<'_>, def_id: DefId) -> Box { +fn build_trait_alias(cx: &mut DocContext<'_>, did: DefId) -> clean::TraitAlias { + let predicates = cx.tcx.predicates_of(did); + let generics = clean_ty_generics(cx, cx.tcx.generics_of(did), predicates); + let (generics, bounds) = separate_self_bounds(generics); + clean::TraitAlias { generics, bounds } +} + +pub(super) fn build_function(cx: &mut DocContext<'_>, def_id: DefId) -> Box { let sig = cx.tcx.fn_sig(def_id).instantiate_identity(); // The generics need to be cleaned before the signature. let mut generics = @@ -490,17 +501,17 @@ pub(crate) fn build_impl( return true; } if let Some(associated_trait) = associated_trait { - let assoc_kind = match item.kind { - hir::ImplItemKind::Const(..) => ty::AssocKind::Const, - hir::ImplItemKind::Fn(..) => ty::AssocKind::Fn, - hir::ImplItemKind::Type(..) => ty::AssocKind::Type, + let assoc_tag = match item.kind { + hir::ImplItemKind::Const(..) => ty::AssocTag::Const, + hir::ImplItemKind::Fn(..) => ty::AssocTag::Fn, + hir::ImplItemKind::Type(..) => ty::AssocTag::Type, }; let trait_item = tcx .associated_items(associated_trait.def_id) - .find_by_name_and_kind( + .find_by_ident_and_kind( tcx, item.ident, - assoc_kind, + assoc_tag, associated_trait.def_id, ) .unwrap(); // SAFETY: For all impl items there exists trait item that has the same name. @@ -524,10 +535,10 @@ pub(crate) fn build_impl( if let Some(associated_trait) = associated_trait { let trait_item = tcx .associated_items(associated_trait.def_id) - .find_by_name_and_kind( + .find_by_ident_and_kind( tcx, item.ident(tcx), - item.kind, + item.as_tag(), associated_trait.def_id, ) .unwrap(); // corresponding associated item has to exist @@ -788,12 +799,7 @@ fn filter_non_trait_generics(trait_did: DefId, mut g: clean::Generics) -> clean: g } -/// Supertrait bounds for a trait are also listed in the generics coming from -/// the metadata for a crate, so we want to separate those out and create a new -/// list of explicit supertrait bounds to render nicely. -fn separate_supertrait_bounds( - mut g: clean::Generics, -) -> (clean::Generics, Vec) { +fn separate_self_bounds(mut g: clean::Generics) -> (clean::Generics, Vec) { let mut ty_bounds = Vec::new(); g.where_predicates.retain(|pred| match *pred { clean::WherePredicate::BoundPredicate { ty: clean::SelfTy, ref bounds, .. } => { @@ -806,22 +812,17 @@ fn separate_supertrait_bounds( } pub(crate) fn record_extern_trait(cx: &mut DocContext<'_>, did: DefId) { - if did.is_local() { + if did.is_local() + || cx.external_traits.contains_key(&did) + || cx.active_extern_traits.contains(&did) + { return; } - { - if cx.external_traits.contains_key(&did) || cx.active_extern_traits.contains(&did) { - return; - } - } - - { - cx.active_extern_traits.insert(did); - } + cx.active_extern_traits.insert(did); debug!("record_extern_trait: {did:?}"); - let trait_ = build_external_trait(cx, did); + let trait_ = build_trait(cx, did); cx.external_traits.insert(did, trait_); cx.active_extern_traits.remove(&did); diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index c08ae168d692..034ecb2f6c1a 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -117,7 +117,14 @@ pub(crate) fn clean_doc_module<'tcx>(doc: &DocModule<'tcx>, cx: &mut DocContext< hir::ItemKind::Use(path, kind) => { let hir::UsePath { segments, span, .. } = *path; let path = hir::Path { segments, res: *res, span }; - clean_use_statement_inner(import, name, &path, kind, cx, &mut Default::default()) + clean_use_statement_inner( + import, + Some(name), + &path, + kind, + cx, + &mut Default::default(), + ) } _ => unreachable!(), } @@ -125,8 +132,7 @@ pub(crate) fn clean_doc_module<'tcx>(doc: &DocModule<'tcx>, cx: &mut DocContext< items.extend(doc.items.values().flat_map(|(item, renamed, _)| { // Now we actually lower the imports, skipping everything else. if let hir::ItemKind::Use(path, hir::UseKind::Glob) = item.kind { - let name = renamed.unwrap_or(kw::Empty); // using kw::Empty is a bit of a hack - clean_use_statement(item, name, path, hir::UseKind::Glob, cx, &mut inserted) + clean_use_statement(item, *renamed, path, hir::UseKind::Glob, cx, &mut inserted) } else { // skip everything else Vec::new() @@ -320,7 +326,7 @@ pub(crate) fn clean_middle_const<'tcx>( } pub(crate) fn clean_middle_region(region: ty::Region<'_>) -> Option { - match *region { + match region.kind() { ty::ReStatic => Some(Lifetime::statik()), _ if !region.has_name() => None, ty::ReBound(_, ty::BoundRegion { kind: ty::BoundRegionKind::Named(_, name), .. }) => { @@ -521,7 +527,7 @@ fn projection_to_path_segment<'tcx>( let item = cx.tcx.associated_item(def_id); let generics = cx.tcx.generics_of(def_id); PathSegment { - name: item.name, + name: item.name(), args: GenericArgs::AngleBracketed { args: clean_middle_generic_args( cx, @@ -1046,7 +1052,7 @@ fn clean_fn_or_proc_macro<'tcx>( match macro_kind { Some(kind) => clean_proc_macro(item, name, kind, cx), None => { - let mut func = clean_function(cx, sig, generics, FunctionArgs::Body(body_id)); + let mut func = clean_function(cx, sig, generics, ParamsSrc::Body(body_id)); clean_fn_decl_legacy_const_generics(&mut func, attrs); FunctionItem(func) } @@ -1065,17 +1071,12 @@ fn clean_fn_decl_legacy_const_generics(func: &mut Function, attrs: &[hir::Attrib for (pos, literal) in meta_item_list.iter().filter_map(|meta| meta.lit()).enumerate() { match literal.kind { ast::LitKind::Int(a, _) => { - let param = func.generics.params.remove(0); - if let GenericParamDef { - name, - kind: GenericParamDefKind::Const { ty, .. }, - .. - } = param - { - func.decl - .inputs - .values - .insert(a.get() as _, Argument { name, type_: *ty, is_const: true }); + let GenericParamDef { name, kind, .. } = func.generics.params.remove(0); + if let GenericParamDefKind::Const { ty, .. } = kind { + func.decl.inputs.insert( + a.get() as _, + Parameter { name: Some(name), type_: *ty, is_const: true }, + ); } else { panic!("unexpected non const in position {pos}"); } @@ -1086,95 +1087,71 @@ fn clean_fn_decl_legacy_const_generics(func: &mut Function, attrs: &[hir::Attrib } } -enum FunctionArgs<'tcx> { +enum ParamsSrc<'tcx> { Body(hir::BodyId), - Names(&'tcx [Option]), + Idents(&'tcx [Option]), } fn clean_function<'tcx>( cx: &mut DocContext<'tcx>, sig: &hir::FnSig<'tcx>, generics: &hir::Generics<'tcx>, - args: FunctionArgs<'tcx>, + params: ParamsSrc<'tcx>, ) -> Box { let (generics, decl) = enter_impl_trait(cx, |cx| { - // NOTE: generics must be cleaned before args + // NOTE: Generics must be cleaned before params. let generics = clean_generics(generics, cx); - let args = match args { - FunctionArgs::Body(body_id) => { - clean_args_from_types_and_body_id(cx, sig.decl.inputs, body_id) - } - FunctionArgs::Names(names) => { - clean_args_from_types_and_names(cx, sig.decl.inputs, names) - } + let params = match params { + ParamsSrc::Body(body_id) => clean_params_via_body(cx, sig.decl.inputs, body_id), + // Let's not perpetuate anon params from Rust 2015; use `_` for them. + ParamsSrc::Idents(idents) => clean_params(cx, sig.decl.inputs, idents, |ident| { + Some(ident.map_or(kw::Underscore, |ident| ident.name)) + }), }; - let decl = clean_fn_decl_with_args(cx, sig.decl, Some(&sig.header), args); + let decl = clean_fn_decl_with_params(cx, sig.decl, Some(&sig.header), params); (generics, decl) }); Box::new(Function { decl, generics }) } -fn clean_args_from_types_and_names<'tcx>( +fn clean_params<'tcx>( cx: &mut DocContext<'tcx>, types: &[hir::Ty<'tcx>], - names: &[Option], -) -> Arguments { - fn nonempty_name(ident: &Option) -> Option { - if let Some(ident) = ident - && ident.name != kw::Underscore - { - Some(ident.name) - } else { - None - } - } - - // If at least one argument has a name, use `_` as the name of unnamed - // arguments. Otherwise omit argument names. - let default_name = if names.iter().any(|ident| nonempty_name(ident).is_some()) { - kw::Underscore - } else { - kw::Empty - }; - - Arguments { - values: types - .iter() - .enumerate() - .map(|(i, ty)| Argument { - type_: clean_ty(ty, cx), - name: names.get(i).and_then(nonempty_name).unwrap_or(default_name), - is_const: false, - }) - .collect(), - } + idents: &[Option], + postprocess: impl Fn(Option) -> Option, +) -> Vec { + types + .iter() + .enumerate() + .map(|(i, ty)| Parameter { + name: postprocess(idents[i]), + type_: clean_ty(ty, cx), + is_const: false, + }) + .collect() } -fn clean_args_from_types_and_body_id<'tcx>( +fn clean_params_via_body<'tcx>( cx: &mut DocContext<'tcx>, types: &[hir::Ty<'tcx>], body_id: hir::BodyId, -) -> Arguments { - let body = cx.tcx.hir_body(body_id); - - Arguments { - values: types - .iter() - .zip(body.params) - .map(|(ty, param)| Argument { - name: name_from_pat(param.pat), - type_: clean_ty(ty, cx), - is_const: false, - }) - .collect(), - } +) -> Vec { + types + .iter() + .zip(cx.tcx.hir_body(body_id).params) + .map(|(ty, param)| Parameter { + name: Some(name_from_pat(param.pat)), + type_: clean_ty(ty, cx), + is_const: false, + }) + .collect() } -fn clean_fn_decl_with_args<'tcx>( +fn clean_fn_decl_with_params<'tcx>( cx: &mut DocContext<'tcx>, decl: &hir::FnDecl<'tcx>, header: Option<&hir::FnHeader>, - args: Arguments, + params: Vec, ) -> FnDecl { let mut output = match decl.output { hir::FnRetTy::Return(typ) => clean_ty(typ, cx), @@ -1185,7 +1162,7 @@ fn clean_fn_decl_with_args<'tcx>( { output = output.sugared_async_return_type(); } - FnDecl { inputs: args, output, c_variadic: decl.c_variadic } + FnDecl { inputs: params, output, c_variadic: decl.c_variadic } } fn clean_poly_fn_sig<'tcx>( @@ -1193,10 +1170,6 @@ fn clean_poly_fn_sig<'tcx>( did: Option, sig: ty::PolyFnSig<'tcx>, ) -> FnDecl { - let mut names = did.map_or(&[] as &[_], |did| cx.tcx.fn_arg_names(did)).iter(); - - // We assume all empty tuples are default return type. This theoretically can discard `-> ()`, - // but shouldn't change any code meaning. let mut output = clean_middle_ty(sig.output(), cx, None, None); // If the return type isn't an `impl Trait`, we can safely assume that this @@ -1209,25 +1182,25 @@ fn clean_poly_fn_sig<'tcx>( output = output.sugared_async_return_type(); } - FnDecl { - output, - c_variadic: sig.skip_binder().c_variadic, - inputs: Arguments { - values: sig - .inputs() - .iter() - .map(|t| Argument { - type_: clean_middle_ty(t.map_bound(|t| *t), cx, None, None), - name: if let Some(Some(ident)) = names.next() { - ident.name - } else { - kw::Underscore - }, - is_const: false, - }) - .collect(), - }, - } + let mut idents = did.map(|did| cx.tcx.fn_arg_idents(did)).unwrap_or_default().iter().copied(); + + // If this comes from a fn item, let's not perpetuate anon params from Rust 2015; use `_` for them. + // If this comes from a fn ptr ty, we just keep params unnamed since it's more conventional stylistically. + // Since the param name is not part of the semantic type, these params never bear a name unlike + // in the HIR case, thus we can't peform any fancy fallback logic unlike `clean_bare_fn_ty`. + let fallback = did.map(|_| kw::Underscore); + + let params = sig + .inputs() + .iter() + .map(|ty| Parameter { + name: idents.next().flatten().map(|ident| ident.name).or(fallback), + type_: clean_middle_ty(ty.map_bound(|ty| *ty), cx, None, None), + is_const: false, + }) + .collect(); + + FnDecl { inputs: params, output, c_variadic: sig.skip_binder().c_variadic } } fn clean_trait_ref<'tcx>(trait_ref: &hir::TraitRef<'tcx>, cx: &mut DocContext<'tcx>) -> Path { @@ -1267,11 +1240,11 @@ fn clean_trait_item<'tcx>(trait_item: &hir::TraitItem<'tcx>, cx: &mut DocContext RequiredAssocConstItem(generics, Box::new(clean_ty(ty, cx))) } hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => { - let m = clean_function(cx, sig, trait_item.generics, FunctionArgs::Body(body)); + let m = clean_function(cx, sig, trait_item.generics, ParamsSrc::Body(body)); MethodItem(m, None) } - hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Required(names)) => { - let m = clean_function(cx, sig, trait_item.generics, FunctionArgs::Names(names)); + hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Required(idents)) => { + let m = clean_function(cx, sig, trait_item.generics, ParamsSrc::Idents(idents)); RequiredMethodItem(m) } hir::TraitItemKind::Type(bounds, Some(default)) => { @@ -1312,7 +1285,7 @@ pub(crate) fn clean_impl_item<'tcx>( type_: clean_ty(ty, cx), })), hir::ImplItemKind::Fn(ref sig, body) => { - let m = clean_function(cx, sig, impl_.generics, FunctionArgs::Body(body)); + let m = clean_function(cx, sig, impl_.generics, ParamsSrc::Body(body)); let defaultness = cx.tcx.defaultness(impl_.owner_id); MethodItem(m, Some(defaultness)) } @@ -1340,7 +1313,7 @@ pub(crate) fn clean_impl_item<'tcx>( pub(crate) fn clean_middle_assoc_item(assoc_item: &ty::AssocItem, cx: &mut DocContext<'_>) -> Item { let tcx = cx.tcx; let kind = match assoc_item.kind { - ty::AssocKind::Const => { + ty::AssocKind::Const { .. } => { let ty = clean_middle_ty( ty::Binder::dummy(tcx.type_of(assoc_item.def_id).instantiate_identity()), cx, @@ -1374,24 +1347,24 @@ pub(crate) fn clean_middle_assoc_item(assoc_item: &ty::AssocItem, cx: &mut DocCo } } } - ty::AssocKind::Fn => { + ty::AssocKind::Fn { has_self, .. } => { let mut item = inline::build_function(cx, assoc_item.def_id); - if assoc_item.fn_has_self_parameter { + if has_self { let self_ty = match assoc_item.container { ty::AssocItemContainer::Impl => { tcx.type_of(assoc_item.container_id(tcx)).instantiate_identity() } ty::AssocItemContainer::Trait => tcx.types.self_param, }; - let self_arg_ty = + let self_param_ty = tcx.fn_sig(assoc_item.def_id).instantiate_identity().input(0).skip_binder(); - if self_arg_ty == self_ty { - item.decl.inputs.values[0].type_ = SelfTy; - } else if let ty::Ref(_, ty, _) = *self_arg_ty.kind() + if self_param_ty == self_ty { + item.decl.inputs[0].type_ = SelfTy; + } else if let ty::Ref(_, ty, _) = *self_param_ty.kind() && ty == self_ty { - match item.decl.inputs.values[0].type_ { + match item.decl.inputs[0].type_ { BorrowedRef { ref mut type_, .. } => **type_ = SelfTy, _ => unreachable!(), } @@ -1412,8 +1385,8 @@ pub(crate) fn clean_middle_assoc_item(assoc_item: &ty::AssocItem, cx: &mut DocCo RequiredMethodItem(item) } } - ty::AssocKind::Type => { - let my_name = assoc_item.name; + ty::AssocKind::Type { .. } => { + let my_name = assoc_item.name(); fn param_eq_arg(param: &GenericParamDef, arg: &GenericArg) -> bool { match (¶m.kind, arg) { @@ -1554,7 +1527,7 @@ pub(crate) fn clean_middle_assoc_item(assoc_item: &ty::AssocItem, cx: &mut DocCo } }; - Item::from_def_id_and_parts(assoc_item.def_id, Some(assoc_item.name), kind, cx) + Item::from_def_id_and_parts(assoc_item.def_id, Some(assoc_item.name()), kind, cx) } fn first_non_private_clean_path<'tcx>( @@ -1941,7 +1914,7 @@ fn clean_trait_object_lifetime_bound<'tcx>( // Since there is a semantic difference between an implicitly elided (i.e. "defaulted") object // lifetime and an explicitly elided object lifetime (`'_`), we intentionally don't hide the // latter contrary to `clean_middle_region`. - match *region { + match region.kind() { ty::ReStatic => Some(Lifetime::statik()), ty::ReEarlyParam(region) => Some(Lifetime(region.name)), ty::ReBound(_, ty::BoundRegion { kind: ty::BoundRegionKind::Named(_, name), .. }) => { @@ -1972,7 +1945,7 @@ fn can_elide_trait_object_lifetime_bound<'tcx>( // > If there is a unique bound from the containing type then that is the default // If there is a default object lifetime and the given region is lexically equal to it, elide it. match default { - ObjectLifetimeDefault::Static => return *region == ty::ReStatic, + ObjectLifetimeDefault::Static => return region.kind() == ty::ReStatic, // FIXME(fmease): Don't compare lexically but respect de Bruijn indices etc. to handle shadowing correctly. ObjectLifetimeDefault::Arg(default) => return region.get_name() == default.get_name(), // > If there is more than one bound from the containing type then an explicit bound must be specified @@ -1992,7 +1965,7 @@ fn can_elide_trait_object_lifetime_bound<'tcx>( // Note however that at the time of this writing it should be fine to disregard this subtlety // as we neither render const exprs faithfully anyway (hiding them in some places or using `_` instead) // nor show the contents of fn bodies. - [] => *region == ty::ReStatic, + [] => region.kind() == ty::ReStatic, // > If the trait is defined with a single lifetime bound then that bound is used. // > If 'static is used for any lifetime bound then 'static is used. // FIXME(fmease): Don't compare lexically but respect de Bruijn indices etc. to handle shadowing correctly. @@ -2223,7 +2196,7 @@ pub(crate) fn clean_middle_ty<'tcx>( Type::QPath(Box::new(QPathData { assoc: PathSegment { - name: cx.tcx.associated_item(def_id).name, + name: cx.tcx.associated_item(def_id).name(), args: GenericArgs::AngleBracketed { args: clean_middle_generic_args( cx, @@ -2605,15 +2578,25 @@ fn clean_bare_fn_ty<'tcx>( cx: &mut DocContext<'tcx>, ) -> BareFunctionDecl { let (generic_params, decl) = enter_impl_trait(cx, |cx| { - // NOTE: generics must be cleaned before args + // NOTE: Generics must be cleaned before params. let generic_params = bare_fn .generic_params .iter() .filter(|p| !is_elided_lifetime(p)) .map(|x| clean_generic_param(cx, None, x)) .collect(); - let args = clean_args_from_types_and_names(cx, bare_fn.decl.inputs, bare_fn.param_names); - let decl = clean_fn_decl_with_args(cx, bare_fn.decl, None, args); + // Since it's more conventional stylistically, elide the name of all params called `_` + // unless there's at least one interestingly named param in which case don't elide any + // name since mixing named and unnamed params is less legible. + let filter = |ident: Option| { + ident.map(|ident| ident.name).filter(|&ident| ident != kw::Underscore) + }; + let fallback = + bare_fn.param_idents.iter().copied().find_map(filter).map(|_| kw::Underscore); + let params = clean_params(cx, bare_fn.decl.inputs, bare_fn.param_idents, |ident| { + filter(ident).or(fallback) + }); + let decl = clean_fn_decl_with_params(cx, bare_fn.decl, None, params); (generic_params, decl) }); BareFunctionDecl { safety: bare_fn.safety, abi: bare_fn.abi, decl, generic_params } @@ -2623,7 +2606,6 @@ fn clean_unsafe_binder_ty<'tcx>( unsafe_binder_ty: &hir::UnsafeBinderTy<'tcx>, cx: &mut DocContext<'tcx>, ) -> UnsafeBinderTy { - // NOTE: generics must be cleaned before args let generic_params = unsafe_binder_ty .generic_params .iter() @@ -2792,10 +2774,7 @@ fn clean_maybe_renamed_item<'tcx>( use hir::ItemKind; let def_id = item.owner_id.to_def_id(); - let mut name = renamed.unwrap_or_else(|| { - // FIXME: using kw::Empty is a bit of a hack - cx.tcx.hir_opt_name(item.hir_id()).unwrap_or(kw::Empty) - }); + let mut name = if renamed.is_some() { renamed } else { cx.tcx.hir_opt_name(item.hir_id()) }; cx.with_param_env(def_id, |cx| { let kind = match item.kind { @@ -2836,7 +2815,7 @@ fn clean_maybe_renamed_item<'tcx>( item_type: Some(type_), })), item.owner_id.def_id.to_def_id(), - name, + name.unwrap(), import_id, renamed, )); @@ -2861,13 +2840,15 @@ fn clean_maybe_renamed_item<'tcx>( }), ItemKind::Impl(impl_) => return clean_impl(impl_, item.owner_id.def_id, cx), ItemKind::Macro(_, macro_def, MacroKind::Bang) => MacroItem(Macro { - source: display_macro_source(cx, name, macro_def), + source: display_macro_source(cx, name.unwrap(), macro_def), macro_rules: macro_def.macro_rules, }), - ItemKind::Macro(_, _, macro_kind) => clean_proc_macro(item, &mut name, macro_kind, cx), + ItemKind::Macro(_, _, macro_kind) => { + clean_proc_macro(item, name.as_mut().unwrap(), macro_kind, cx) + } // proc macros can have a name set by attributes ItemKind::Fn { ref sig, generics, body: body_id, .. } => { - clean_fn_or_proc_macro(item, sig, generics, body_id, &mut name, cx) + clean_fn_or_proc_macro(item, sig, generics, body_id, name.as_mut().unwrap(), cx) } ItemKind::Trait(_, _, _, generics, bounds, item_ids) => { let items = item_ids @@ -2883,7 +2864,7 @@ fn clean_maybe_renamed_item<'tcx>( })) } ItemKind::ExternCrate(orig_name, _) => { - return clean_extern_crate(item, name, orig_name, cx); + return clean_extern_crate(item, name.unwrap(), orig_name, cx); } ItemKind::Use(path, kind) => { return clean_use_statement(item, name, path, kind, cx, &mut FxHashSet::default()); @@ -2895,7 +2876,7 @@ fn clean_maybe_renamed_item<'tcx>( cx, kind, item.owner_id.def_id.to_def_id(), - name, + name.unwrap(), import_id, renamed, )] @@ -3006,7 +2987,7 @@ fn clean_extern_crate<'tcx>( fn clean_use_statement<'tcx>( import: &hir::Item<'tcx>, - name: Symbol, + name: Option, path: &hir::UsePath<'tcx>, kind: hir::UseKind, cx: &mut DocContext<'tcx>, @@ -3023,7 +3004,7 @@ fn clean_use_statement<'tcx>( fn clean_use_statement_inner<'tcx>( import: &hir::Item<'tcx>, - name: Symbol, + name: Option, path: &hir::Path<'tcx>, kind: hir::UseKind, cx: &mut DocContext<'tcx>, @@ -3042,7 +3023,7 @@ fn clean_use_statement_inner<'tcx>( let visibility = cx.tcx.visibility(import.owner_id); let attrs = cx.tcx.hir_attrs(import.hir_id()); let inline_attr = hir_attr_lists(attrs, sym::doc).get_word_attr(sym::inline); - let pub_underscore = visibility.is_public() && name == kw::Underscore; + let pub_underscore = visibility.is_public() && name == Some(kw::Underscore); let current_mod = cx.tcx.parent_module_from_def_id(import.owner_id.def_id); let import_def_id = import.owner_id.def_id; @@ -3108,6 +3089,7 @@ fn clean_use_statement_inner<'tcx>( } Import::new_glob(resolve_use_source(cx, path), true) } else { + let name = name.unwrap(); if inline_attr.is_none() && let Res::Def(DefKind::Mod, did) = path.res && !did.is_local() @@ -3148,8 +3130,8 @@ fn clean_maybe_renamed_foreign_item<'tcx>( let def_id = item.owner_id.to_def_id(); cx.with_param_env(def_id, |cx| { let kind = match item.kind { - hir::ForeignItemKind::Fn(sig, names, generics) => ForeignFunctionItem( - clean_function(cx, &sig, generics, FunctionArgs::Names(names)), + hir::ForeignItemKind::Fn(sig, idents, generics) => ForeignFunctionItem( + clean_function(cx, &sig, generics, ParamsSrc::Idents(idents)), sig.header.safety(), ), hir::ForeignItemKind::Static(ty, mutability, safety) => ForeignStaticItem( diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index d3ddb77c0b33..bbe11bf56af3 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -11,7 +11,6 @@ use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId}; use rustc_hir::lang_items::LangItem; use rustc_hir::{BodyId, Mutability}; -use rustc_hir_analysis::check::intrinsic::intrinsic_operation_unsafety; use rustc_index::IndexVec; use rustc_metadata::rendered_const; use rustc_middle::span_bug; @@ -518,7 +517,7 @@ impl Item { Some(RenderedLink { original_text: s.clone(), new_text: link_text.clone(), - tooltip: link_tooltip(*id, fragment, cx), + tooltip: link_tooltip(*id, fragment, cx).to_string(), href, }) } else { @@ -687,8 +686,6 @@ impl Item { hir::FnHeader { safety: if tcx.codegen_fn_attrs(def_id).safe_target_features { hir::HeaderSafety::SafeTargetFeatures - } else if abi == ExternAbi::RustIntrinsic { - intrinsic_operation_unsafety(tcx, def_id.expect_local()).into() } else { safety.into() }, @@ -791,7 +788,7 @@ impl Item { } _ => Some(rustc_hir_pretty::attribute_to_string(&tcx, attr)), } - } else if ALLOWED_ATTRIBUTES.contains(&attr.name_or_empty()) { + } else if attr.has_any_name(ALLOWED_ATTRIBUTES) { Some( rustc_hir_pretty::attribute_to_string(&tcx, attr) .replace("\\\n", "") @@ -1410,34 +1407,30 @@ pub(crate) struct Function { #[derive(Clone, PartialEq, Eq, Debug, Hash)] pub(crate) struct FnDecl { - pub(crate) inputs: Arguments, + pub(crate) inputs: Vec, pub(crate) output: Type, pub(crate) c_variadic: bool, } impl FnDecl { pub(crate) fn receiver_type(&self) -> Option<&Type> { - self.inputs.values.first().and_then(|v| v.to_receiver()) + self.inputs.first().and_then(|v| v.to_receiver()) } } +/// A function parameter. #[derive(Clone, PartialEq, Eq, Debug, Hash)] -pub(crate) struct Arguments { - pub(crate) values: Vec, -} - -#[derive(Clone, PartialEq, Eq, Debug, Hash)] -pub(crate) struct Argument { +pub(crate) struct Parameter { + pub(crate) name: Option, pub(crate) type_: Type, - pub(crate) name: Symbol, /// This field is used to represent "const" arguments from the `rustc_legacy_const_generics` /// feature. More information in . pub(crate) is_const: bool, } -impl Argument { +impl Parameter { pub(crate) fn to_receiver(&self) -> Option<&Type> { - if self.name == kw::SelfLower { Some(&self.type_) } else { None } + if self.name == Some(kw::SelfLower) { Some(&self.type_) } else { None } } } @@ -2507,7 +2500,7 @@ impl Impl { self.trait_ .as_ref() .map(|t| t.def_id()) - .map(|did| tcx.provided_trait_methods(did).map(|meth| meth.name).collect()) + .map(|did| tcx.provided_trait_methods(did).map(|meth| meth.name()).collect()) .unwrap_or_default() } diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index f81db58950cb..af7986d030ee 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -234,7 +234,7 @@ pub(super) fn clean_middle_path<'tcx>( args: ty::Binder<'tcx, GenericArgsRef<'tcx>>, ) -> Path { let def_kind = cx.tcx.def_kind(did); - let name = cx.tcx.opt_item_name(did).unwrap_or(kw::Empty); + let name = cx.tcx.opt_item_name(did).unwrap_or(sym::dummy); Path { res: Res::Def(def_kind, did), segments: thin_vec![PathSegment { @@ -303,12 +303,12 @@ pub(crate) fn name_from_pat(p: &hir::Pat<'_>) -> Symbol { debug!("trying to get a name from pattern: {p:?}"); Symbol::intern(&match &p.kind { - // FIXME(never_patterns): does this make sense? - PatKind::Wild - | PatKind::Err(_) + PatKind::Err(_) + | PatKind::Missing // Let's not perpetuate anon params from Rust 2015; use `_` for them. | PatKind::Never + | PatKind::Range(..) | PatKind::Struct(..) - | PatKind::Range(..) => { + | PatKind::Wild => { return kw::Underscore; } PatKind::Binding(_, _, ident, _) => return ident.name, diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index c47e42670c90..9d1c9ff00b14 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -27,7 +27,7 @@ use rustc_span::source_map; use rustc_span::symbol::sym; use tracing::{debug, info}; -use crate::clean::inline::build_external_trait; +use crate::clean::inline::build_trait; use crate::clean::{self, ItemId}; use crate::config::{Options as RustdocOptions, OutputFormat, RenderOptions}; use crate::formats::cache::Cache; @@ -321,6 +321,7 @@ pub(crate) fn create_config( (rustc_interface::DEFAULT_QUERY_PROVIDERS.typeck)(tcx, def_id) }; }), + extra_symbols: Vec::new(), make_codegen_backend: None, registry: rustc_driver::diagnostics_registry(), ice_file: None, @@ -384,7 +385,7 @@ pub(crate) fn run_global_ctxt( // // Note that in case of `#![no_core]`, the trait is not available. if let Some(sized_trait_did) = ctxt.tcx.lang_items().sized_trait() { - let sized_trait = build_external_trait(&mut ctxt, sized_trait_did); + let sized_trait = build_trait(&mut ctxt, sized_trait_did); ctxt.external_traits.insert(sized_trait_did, sized_trait); } @@ -411,9 +412,7 @@ pub(crate) fn run_global_ctxt( // Process all of the crate attributes, extracting plugin metadata along // with the passes which we are supposed to run. for attr in krate.module.attrs.lists(sym::doc) { - let name = attr.name_or_empty(); - - if attr.is_word() && name == sym::document_private_items { + if attr.is_word() && attr.has_name(sym::document_private_items) { ctxt.render_options.document_private = true; } } diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index a2808bddb3ac..88eaa52c6deb 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -191,6 +191,7 @@ pub(crate) fn run(dcx: DiagCtxtHandle<'_>, input: Input, options: RustdocOptions hash_untracked_state: None, register_lints: Some(Box::new(crate::lint::register_lints)), override_queries: None, + extra_symbols: Vec::new(), make_codegen_backend: None, registry: rustc_driver::diagnostics_registry(), ice_file: None, diff --git a/src/librustdoc/doctest/make.rs b/src/librustdoc/doctest/make.rs index 4edd5433de6c..d5c965f7053e 100644 --- a/src/librustdoc/doctest/make.rs +++ b/src/librustdoc/doctest/make.rs @@ -345,7 +345,7 @@ fn parse_source(source: &str, crate_name: &Option<&str>) -> Result) -> bool { let mut is_extern_crate = false; if !info.has_global_allocator - && item.attrs.iter().any(|attr| attr.name_or_empty() == sym::global_allocator) + && item.attrs.iter().any(|attr| attr.has_name(sym::global_allocator)) { info.has_global_allocator = true; } @@ -377,7 +377,7 @@ fn parse_source(source: &str, crate_name: &Option<&str>) -> Result) -> Result { for attr in &item.attrs { - let attr_name = attr.name_or_empty(); - - if attr.style == AttrStyle::Outer || not_crate_attrs.contains(&attr_name) { + if attr.style == AttrStyle::Outer || attr.has_any_name(not_crate_attrs) { // There is one exception to these attributes: // `#![allow(internal_features)]`. If this attribute is used, we need to // consider it only as a crate-level attribute. - if attr_name == sym::allow + if attr.has_name(sym::allow) && let Some(list) = attr.meta_item_list() - && list.iter().any(|sub_attr| { - sub_attr.name_or_empty().as_str() == "internal_features" - }) + && list.iter().any(|sub_attr| sub_attr.has_name(sym::internal_features)) { push_to_s(&mut info.crate_attrs, source, attr.span, &mut prev_span_hi); } else { diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 41e9a5a66516..299fd6b9adbb 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -11,6 +11,7 @@ use std::borrow::Cow; use std::cmp::Ordering; use std::fmt::{self, Display, Write}; use std::iter::{self, once}; +use std::slice; use itertools::Either; use rustc_abi::ExternAbi; @@ -650,33 +651,35 @@ pub(crate) fn href_relative_parts<'fqp>( } } -pub(crate) fn link_tooltip(did: DefId, fragment: &Option, cx: &Context<'_>) -> String { - let cache = cx.cache(); - let Some((fqp, shortty)) = cache.paths.get(&did).or_else(|| cache.external_paths.get(&did)) - else { - return String::new(); - }; - let mut buf = String::new(); - let fqp = if *shortty == ItemType::Primitive { - // primitives are documented in a crate, but not actually part of it - &fqp[fqp.len() - 1..] - } else { - fqp - }; - if let &Some(UrlFragment::Item(id)) = fragment { - write_str(&mut buf, format_args!("{} ", cx.tcx().def_descr(id))); - for component in fqp { - write_str(&mut buf, format_args!("{component}::")); +pub(crate) fn link_tooltip( + did: DefId, + fragment: &Option, + cx: &Context<'_>, +) -> impl fmt::Display { + fmt::from_fn(move |f| { + let cache = cx.cache(); + let Some((fqp, shortty)) = cache.paths.get(&did).or_else(|| cache.external_paths.get(&did)) + else { + return Ok(()); + }; + let fqp = if *shortty == ItemType::Primitive { + // primitives are documented in a crate, but not actually part of it + slice::from_ref(fqp.last().unwrap()) + } else { + fqp + }; + if let &Some(UrlFragment::Item(id)) = fragment { + write!(f, "{} ", cx.tcx().def_descr(id))?; + for component in fqp { + write!(f, "{component}::")?; + } + write!(f, "{}", cx.tcx().item_name(id))?; + } else if !fqp.is_empty() { + write!(f, "{shortty} ")?; + fqp.iter().joined("::", f)?; } - write_str(&mut buf, format_args!("{}", cx.tcx().item_name(id))); - } else if !fqp.is_empty() { - let mut fqp_it = fqp.iter(); - write_str(&mut buf, format_args!("{shortty} {}", fqp_it.next().unwrap())); - for component in fqp_it { - write_str(&mut buf, format_args!("::{component}")); - } - } - buf + Ok(()) + }) } /// Used to render a [`clean::Path`]. @@ -1183,8 +1186,8 @@ impl clean::Impl { { primitive_link(f, PrimitiveType::Array, format_args!("[{name}; N]"), cx)?; } else if let clean::BareFunction(bare_fn) = &type_ - && let [clean::Argument { type_: clean::Type::Generic(name), .. }] = - &bare_fn.decl.inputs.values[..] + && let [clean::Parameter { type_: clean::Type::Generic(name), .. }] = + &bare_fn.decl.inputs[..] && (self.kind.is_fake_variadic() || self.kind.is_auto()) { // Hardcoded anchor library/core/src/primitive_docs.rs @@ -1231,22 +1234,20 @@ impl clean::Impl { } } -impl clean::Arguments { - pub(crate) fn print(&self, cx: &Context<'_>) -> impl Display { - fmt::from_fn(move |f| { - self.values - .iter() - .map(|input| { - fmt::from_fn(|f| { - if !input.name.is_empty() { - write!(f, "{}: ", input.name)?; - } - input.type_.print(cx).fmt(f) - }) +pub(crate) fn print_params(params: &[clean::Parameter], cx: &Context<'_>) -> impl Display { + fmt::from_fn(move |f| { + params + .iter() + .map(|param| { + fmt::from_fn(|f| { + if let Some(name) = param.name { + write!(f, "{}: ", name)?; + } + param.type_.print(cx).fmt(f) }) - .joined(", ", f) - }) - } + }) + .joined(", ", f) + }) } // Implements Write but only counts the bytes "written". @@ -1278,16 +1279,16 @@ impl clean::FnDecl { if f.alternate() { write!( f, - "({args:#}{ellipsis}){arrow:#}", - args = self.inputs.print(cx), + "({params:#}{ellipsis}){arrow:#}", + params = print_params(&self.inputs, cx), ellipsis = ellipsis, arrow = self.print_output(cx) ) } else { write!( f, - "({args}{ellipsis}){arrow}", - args = self.inputs.print(cx), + "({params}{ellipsis}){arrow}", + params = print_params(&self.inputs, cx), ellipsis = ellipsis, arrow = self.print_output(cx) ) @@ -1333,14 +1334,14 @@ impl clean::FnDecl { write!(f, "(")?; if let Some(n) = line_wrapping_indent - && !self.inputs.values.is_empty() + && !self.inputs.is_empty() { write!(f, "\n{}", Indent(n + 4))?; } - let last_input_index = self.inputs.values.len().checked_sub(1); - for (i, input) in self.inputs.values.iter().enumerate() { - if let Some(selfty) = input.to_receiver() { + let last_input_index = self.inputs.len().checked_sub(1); + for (i, param) in self.inputs.iter().enumerate() { + if let Some(selfty) = param.to_receiver() { match selfty { clean::SelfTy => { write!(f, "self")?; @@ -1358,11 +1359,13 @@ impl clean::FnDecl { } } } else { - if input.is_const { + if param.is_const { write!(f, "const ")?; } - write!(f, "{}: ", input.name)?; - input.type_.print(cx).fmt(f)?; + if let Some(name) = param.name { + write!(f, "{}: ", name)?; + } + param.type_.print(cx).fmt(f)?; } match (line_wrapping_indent, last_input_index) { (_, None) => (), diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs index df70df062fe0..44b3be23914c 100644 --- a/src/librustdoc/html/layout.rs +++ b/src/librustdoc/html/layout.rs @@ -1,7 +1,7 @@ use std::fmt::{self, Display}; use std::path::PathBuf; -use rinja::Template; +use askama::Template; use rustc_data_structures::fx::FxIndexMap; use super::static_files::{STATIC_FILES, StaticFiles}; diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 334a7a86989a..44134bda5ea3 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -721,7 +721,7 @@ pub(crate) fn find_codes( extra_info: Option<&ExtraInfo<'_>>, include_non_rust: bool, ) { - let mut parser = Parser::new(doc).into_offset_iter(); + let mut parser = Parser::new_ext(doc, main_body_opts()).into_offset_iter(); let mut prev_offset = 0; let mut nb_lines = 0; let mut register_header = None; diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index 5f69e79f3ab1..f22935df96c8 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -5,7 +5,7 @@ use std::io; use std::path::{Path, PathBuf}; use std::sync::mpsc::{Receiver, channel}; -use rinja::Template; +use askama::Template; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use rustc_hir::def_id::{DefIdMap, LOCAL_CRATE}; use rustc_middle::ty::TyCtxt; @@ -521,23 +521,23 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { // Crawl the crate attributes looking for attributes which control how we're // going to emit HTML for attr in krate.module.attrs.lists(sym::doc) { - match (attr.name_or_empty(), attr.value_str()) { - (sym::html_favicon_url, Some(s)) => { + match (attr.name(), attr.value_str()) { + (Some(sym::html_favicon_url), Some(s)) => { layout.favicon = s.to_string(); } - (sym::html_logo_url, Some(s)) => { + (Some(sym::html_logo_url), Some(s)) => { layout.logo = s.to_string(); } - (sym::html_playground_url, Some(s)) => { + (Some(sym::html_playground_url), Some(s)) => { playground = Some(markdown::Playground { crate_name: Some(krate.name(tcx)), url: s.to_string(), }); } - (sym::issue_tracker_base_url, Some(s)) => { + (Some(sym::issue_tracker_base_url), Some(s)) => { issue_tracker_base_url = Some(s.to_string()); } - (sym::html_no_source, None) if attr.is_word() => { + (Some(sym::html_no_source), None) if attr.is_word() => { include_sources = false; } _ => {} @@ -650,15 +650,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { bar.render_into(&mut sidebar).unwrap(); - let v = layout::render( - &shared.layout, - &page, - sidebar, - BufDisplay(|buf: &mut String| { - all.print(buf); - }), - &shared.style_files, - ); + let v = layout::render(&shared.layout, &page, sidebar, all.print(), &shared.style_files); shared.fs.write(final_file, v)?; // if to avoid writing help, settings files to doc root unless we're on the final invocation diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 2237e0f987bc..7e17f09aecdc 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -13,6 +13,9 @@ //! is cloned per-thread and contains information about what is currently being //! rendered. //! +//! The main entry point to the rendering system is the implementation of +//! `FormatRenderer` on `Context`. +//! //! In order to speed up rendering (mostly because of markdown rendering), the //! rendering process has been parallelized. This parallelization is only //! exposed through the `crate` method on the context, and then also from the @@ -37,13 +40,15 @@ mod span_map; mod type_layout; mod write_shared; +use std::borrow::Cow; use std::collections::VecDeque; use std::fmt::{self, Display as _, Write}; use std::iter::Peekable; use std::path::PathBuf; use std::{fs, str}; -use rinja::Template; +use askama::Template; +use itertools::Either; use rustc_attr_parsing::{ ConstStability, DeprecatedSince, Deprecation, RustcVersion, StabilityLevel, StableSince, }; @@ -90,15 +95,28 @@ pub(crate) fn ensure_trailing_slash(v: &str) -> impl fmt::Display { /// Specifies whether rendering directly implemented trait items or ones from a certain Deref /// impl. #[derive(Copy, Clone, Debug)] -pub(crate) enum AssocItemRender<'a> { +enum AssocItemRender<'a> { All, DerefFor { trait_: &'a clean::Path, type_: &'a clean::Type, deref_mut_: bool }, } +impl AssocItemRender<'_> { + fn render_mode(&self) -> RenderMode { + match self { + Self::All => RenderMode::Normal, + &Self::DerefFor { deref_mut_, .. } => RenderMode::ForDeref { mut_: deref_mut_ }, + } + } + + fn class(&self) -> Option<&'static str> { + if let Self::DerefFor { .. } = self { Some("impl-items") } else { None } + } +} + /// For different handling of associated items from the Deref target of a type rather than the type /// itself. #[derive(Copy, Clone, PartialEq)] -pub(crate) enum RenderMode { +enum RenderMode { Normal, ForDeref { mut_: bool }, } @@ -126,7 +144,7 @@ pub(crate) struct IndexItem { /// A type used for the search index. #[derive(Debug, Eq, PartialEq)] -pub(crate) struct RenderType { +struct RenderType { id: Option, generics: Option>, bindings: Option)>>, @@ -137,7 +155,7 @@ impl RenderType { // The contents of the lists are always integers in self-terminating hex // form, handled by `RenderTypeId::write_to_string`, so no commas are // needed to separate the items. - pub fn write_to_string(&self, string: &mut String) { + fn write_to_string(&self, string: &mut String) { fn write_optional_id(id: Option, string: &mut String) { // 0 is a sentinel, everything else is one-indexed match id { @@ -177,7 +195,7 @@ impl RenderType { } #[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub(crate) enum RenderTypeId { +enum RenderTypeId { DefId(DefId), Primitive(clean::PrimitiveType), AssociatedType(Symbol), @@ -186,7 +204,7 @@ pub(crate) enum RenderTypeId { } impl RenderTypeId { - pub fn write_to_string(&self, string: &mut String) { + fn write_to_string(&self, string: &mut String) { let id: i32 = match &self { // 0 is a sentinel, everything else is one-indexed // concrete type @@ -205,11 +223,11 @@ pub(crate) struct IndexItemFunctionType { inputs: Vec, output: Vec, where_clause: Vec>, - param_names: Vec, + param_names: Vec>, } impl IndexItemFunctionType { - pub fn write_to_string<'a>( + fn write_to_string<'a>( &'a self, string: &mut String, backref_queue: &mut VecDeque<&'a IndexItemFunctionType>, @@ -309,7 +327,7 @@ impl ItemEntry { } impl ItemEntry { - pub(crate) fn print(&self) -> impl fmt::Display { + fn print(&self) -> impl fmt::Display { fmt::from_fn(move |f| write!(f, "{}", self.url, Escape(&self.name))) } } @@ -436,44 +454,49 @@ impl AllTypes { sections } - fn print(&self, f: &mut String) { - fn print_entries(f: &mut String, e: &FxIndexSet, kind: ItemSection) { - if !e.is_empty() { - let mut e: Vec<&ItemEntry> = e.iter().collect(); - e.sort(); - write_str( - f, - format_args!( - "

{title}

    ", - id = kind.id(), - title = kind.name(), - ), - ); - - for s in e.iter() { - write_str(f, format_args!("
  • {}
  • ", s.print())); + fn print(&self) -> impl fmt::Display { + fn print_entries(e: &FxIndexSet, kind: ItemSection) -> impl fmt::Display { + fmt::from_fn(move |f| { + if e.is_empty() { + return Ok(()); } - f.push_str("
"); - } + let mut e: Vec<&ItemEntry> = e.iter().collect(); + e.sort(); + write!( + f, + "

{title}

    ", + id = kind.id(), + title = kind.name(), + )?; + + for s in e.iter() { + write!(f, "
  • {}
  • ", s.print())?; + } + + f.write_str("
") + }) } - f.push_str("

List of all items

"); - // Note: print_entries does not escape the title, because we know the current set of titles - // doesn't require escaping. - print_entries(f, &self.structs, ItemSection::Structs); - print_entries(f, &self.enums, ItemSection::Enums); - print_entries(f, &self.unions, ItemSection::Unions); - print_entries(f, &self.primitives, ItemSection::PrimitiveTypes); - print_entries(f, &self.traits, ItemSection::Traits); - print_entries(f, &self.macros, ItemSection::Macros); - print_entries(f, &self.attribute_macros, ItemSection::AttributeMacros); - print_entries(f, &self.derive_macros, ItemSection::DeriveMacros); - print_entries(f, &self.functions, ItemSection::Functions); - print_entries(f, &self.type_aliases, ItemSection::TypeAliases); - print_entries(f, &self.trait_aliases, ItemSection::TraitAliases); - print_entries(f, &self.statics, ItemSection::Statics); - print_entries(f, &self.constants, ItemSection::Constants); + fmt::from_fn(|f| { + f.write_str("

List of all items

")?; + // Note: print_entries does not escape the title, because we know the current set of titles + // doesn't require escaping. + print_entries(&self.structs, ItemSection::Structs).fmt(f)?; + print_entries(&self.enums, ItemSection::Enums).fmt(f)?; + print_entries(&self.unions, ItemSection::Unions).fmt(f)?; + print_entries(&self.primitives, ItemSection::PrimitiveTypes).fmt(f)?; + print_entries(&self.traits, ItemSection::Traits).fmt(f)?; + print_entries(&self.macros, ItemSection::Macros).fmt(f)?; + print_entries(&self.attribute_macros, ItemSection::AttributeMacros).fmt(f)?; + print_entries(&self.derive_macros, ItemSection::DeriveMacros).fmt(f)?; + print_entries(&self.functions, ItemSection::Functions).fmt(f)?; + print_entries(&self.type_aliases, ItemSection::TypeAliases).fmt(f)?; + print_entries(&self.trait_aliases, ItemSection::TraitAliases).fmt(f)?; + print_entries(&self.statics, ItemSection::Statics).fmt(f)?; + print_entries(&self.constants, ItemSection::Constants).fmt(f)?; + Ok(()) + }) } } @@ -760,7 +783,7 @@ fn short_item_info( // Render the list of items inside one of the sections "Trait Implementations", // "Auto Trait Implementations," "Blanket Trait Implementations" (on struct/enum pages). -pub(crate) fn render_impls( +fn render_impls( cx: &Context<'_>, mut w: impl Write, impls: &[&Impl], @@ -1201,8 +1224,8 @@ impl<'a> AssocItemLink<'a> { } } -pub fn write_section_heading( - title: &str, +fn write_section_heading( + title: impl fmt::Display, id: &str, extra_class: Option<&str>, extra: impl fmt::Display, @@ -1222,11 +1245,11 @@ pub fn write_section_heading( }) } -fn write_impl_section_heading(title: &str, id: &str) -> impl fmt::Display { +fn write_impl_section_heading(title: impl fmt::Display, id: &str) -> impl fmt::Display { write_section_heading(title, id, None, "") } -pub(crate) fn render_all_impls( +fn render_all_impls( mut w: impl Write, cx: &Context<'_>, containing_item: &clean::Item, @@ -1299,20 +1322,17 @@ fn render_assoc_items_inner( let (mut non_trait, traits): (Vec<_>, _) = v.iter().partition(|i| i.inner_impl().trait_.is_none()); if !non_trait.is_empty() { - let mut close_tags = >::with_capacity(1); - let mut tmp_buf = String::new(); - let (render_mode, id, class_html) = match what { - AssocItemRender::All => { - write_str( - &mut tmp_buf, - format_args!( - "{}", - write_impl_section_heading("Implementations", "implementations") - ), - ); - (RenderMode::Normal, "implementations-list".to_owned(), "") - } - AssocItemRender::DerefFor { trait_, type_, deref_mut_ } => { + let render_mode = what.render_mode(); + let class_html = what + .class() + .map(|class| fmt::from_fn(move |f| write!(f, r#" class="{class}""#))) + .maybe_display(); + let (section_heading, id) = match what { + AssocItemRender::All => ( + Either::Left(write_impl_section_heading("Implementations", "implementations")), + Cow::Borrowed("implementations-list"), + ), + AssocItemRender::DerefFor { trait_, type_, .. } => { let id = cx.derive_id(small_url_encode(format!("deref-methods-{:#}", type_.print(cx)))); // the `impls.get` above only looks at the outermost type, @@ -1326,25 +1346,27 @@ fn render_assoc_items_inner( type_.is_doc_subtype_of(&impl_.inner_impl().for_, &cx.shared.cache) }); let derived_id = cx.derive_id(&id); - close_tags.push(""); - write_str( - &mut tmp_buf, - format_args!( - "
{}", - write_impl_section_heading( - &format!( - "Methods from {trait_}<Target = {type_}>", - trait_ = trait_.print(cx), - type_ = type_.print(cx), - ), - &id, - ) - ), - ); if let Some(def_id) = type_.def_id(cx.cache()) { - cx.deref_id_map.borrow_mut().insert(def_id, id); + cx.deref_id_map.borrow_mut().insert(def_id, id.clone()); } - (RenderMode::ForDeref { mut_: deref_mut_ }, derived_id, r#" class="impl-items""#) + ( + Either::Right(fmt::from_fn(move |f| { + write!( + f, + "
{}", + write_impl_section_heading( + fmt::from_fn(|f| write!( + f, + "Methods from {trait_}<Target = {type_}>", + trait_ = trait_.print(cx), + type_ = type_.print(cx), + )), + &id, + ) + ) + })), + Cow::Owned(derived_id), + ) } }; let mut impls_buf = String::new(); @@ -1372,10 +1394,14 @@ fn render_assoc_items_inner( ); } if !impls_buf.is_empty() { - write!(w, "{tmp_buf}
{impls_buf}
").unwrap(); - for tag in close_tags.into_iter().rev() { - w.write_str(tag).unwrap(); - } + write!( + w, + "{section_heading}
{impls_buf}
{}", + matches!(what, AssocItemRender::DerefFor { .. }) + .then_some("
") + .maybe_display(), + ) + .unwrap(); } } @@ -1473,10 +1499,7 @@ fn should_render_item(item: &clean::Item, deref_mut_: bool, tcx: TyCtxt<'_>) -> } } -pub(crate) fn notable_traits_button( - ty: &clean::Type, - cx: &Context<'_>, -) -> Option { +fn notable_traits_button(ty: &clean::Type, cx: &Context<'_>) -> Option { if ty.is_unit() { // Very common fast path. return None; @@ -1588,10 +1611,7 @@ fn notable_traits_decl(ty: &clean::Type, cx: &Context<'_>) -> (String, String) { (format!("{:#}", ty.print(cx)), out) } -pub(crate) fn notable_traits_json<'a>( - tys: impl Iterator, - cx: &Context<'_>, -) -> String { +fn notable_traits_json<'a>(tys: impl Iterator, cx: &Context<'_>) -> String { let mut mp: Vec<(String, String)> = tys.map(|ty| notable_traits_decl(ty, cx)).collect(); mp.sort_by(|(name1, _html1), (name2, _html2)| name1.cmp(name2)); struct NotableTraitsMap(Vec<(String, String)>); @@ -1642,8 +1662,8 @@ fn render_impl( // `containing_item` is used for rendering stability info. If the parent is a trait impl, // `containing_item` will the grandparent, since trait impls can't have stability attached. fn doc_impl_item( - boring: &mut String, - interesting: &mut String, + boring: impl fmt::Write, + interesting: impl fmt::Write, cx: &Context<'_>, item: &clean::Item, parent: &clean::Item, @@ -1652,7 +1672,7 @@ fn render_impl( is_default_item: bool, trait_: Option<&clean::Trait>, rendering_params: ImplRenderingParameters, - ) { + ) -> fmt::Result { let item_type = item.type_(); let name = item.name.as_ref().unwrap(); @@ -1727,15 +1747,16 @@ fn render_impl( ); } } - let w = if short_documented && trait_.is_some() { interesting } else { boring }; + let mut w = if short_documented && trait_.is_some() { + Either::Left(interesting) + } else { + Either::Right(boring) + }; let toggled = !doc_buffer.is_empty(); if toggled { let method_toggle_class = if item_type.is_method() { " method-toggle" } else { "" }; - write_str( - w, - format_args!("
"), - ); + write!(w, "
")?; } match &item.kind { clean::MethodItem(..) | clean::RequiredMethodItem(_) => { @@ -1750,172 +1771,151 @@ fn render_impl( .find(|item| item.name.map(|n| n == *name).unwrap_or(false)) }) .map(|item| format!("{}.{name}", item.type_())); - write_str( + write!( w, - format_args!( - "
\ + "
\ {}", - render_rightside(cx, item, render_mode) - ), - ); + render_rightside(cx, item, render_mode) + )?; if trait_.is_some() { // Anchors are only used on trait impls. - write_str(w, format_args!("§")); + write!(w, "§")?; } - write_str( + write!( w, - format_args!( - "

{}

", - render_assoc_item( - item, - link.anchor(source_id.as_ref().unwrap_or(&id)), - ItemType::Impl, - cx, - render_mode, - ), + "

{}

", + render_assoc_item( + item, + link.anchor(source_id.as_ref().unwrap_or(&id)), + ItemType::Impl, + cx, + render_mode, ), - ); + )?; } } clean::RequiredAssocConstItem(generics, ty) => { let source_id = format!("{item_type}.{name}"); let id = cx.derive_id(&source_id); - write_str( + write!( w, - format_args!( - "
\ + "
\ {}", - render_rightside(cx, item, render_mode) - ), - ); + render_rightside(cx, item, render_mode) + )?; if trait_.is_some() { // Anchors are only used on trait impls. - write_str(w, format_args!("§")); + write!(w, "§")?; } - write_str( + write!( w, - format_args!( - "

{}

", - assoc_const( - item, - generics, - ty, - AssocConstValue::None, - link.anchor(if trait_.is_some() { &source_id } else { &id }), - 0, - cx, - ) + "

{}

", + assoc_const( + item, + generics, + ty, + AssocConstValue::None, + link.anchor(if trait_.is_some() { &source_id } else { &id }), + 0, + cx, ), - ); + )?; } clean::ProvidedAssocConstItem(ci) | clean::ImplAssocConstItem(ci) => { let source_id = format!("{item_type}.{name}"); let id = cx.derive_id(&source_id); - write_str( + write!( w, - format_args!( - "
\ + "
\ {}", - render_rightside(cx, item, render_mode) - ), - ); + render_rightside(cx, item, render_mode), + )?; if trait_.is_some() { // Anchors are only used on trait impls. - write_str(w, format_args!("§")); + write!(w, "§")?; } - write_str( + write!( w, - format_args!( - "

{}

", - assoc_const( - item, - &ci.generics, - &ci.type_, - match item.kind { - clean::ProvidedAssocConstItem(_) => - AssocConstValue::TraitDefault(&ci.kind), - clean::ImplAssocConstItem(_) => AssocConstValue::Impl(&ci.kind), - _ => unreachable!(), - }, - link.anchor(if trait_.is_some() { &source_id } else { &id }), - 0, - cx, - ) + "

{}

", + assoc_const( + item, + &ci.generics, + &ci.type_, + match item.kind { + clean::ProvidedAssocConstItem(_) => + AssocConstValue::TraitDefault(&ci.kind), + clean::ImplAssocConstItem(_) => AssocConstValue::Impl(&ci.kind), + _ => unreachable!(), + }, + link.anchor(if trait_.is_some() { &source_id } else { &id }), + 0, + cx, ), - ); + )?; } clean::RequiredAssocTypeItem(generics, bounds) => { let source_id = format!("{item_type}.{name}"); let id = cx.derive_id(&source_id); - write_str( + write!( w, - format_args!( - "
\ + "
\ {}", - render_rightside(cx, item, render_mode) - ), - ); + render_rightside(cx, item, render_mode), + )?; if trait_.is_some() { // Anchors are only used on trait impls. - write_str(w, format_args!("§")); + write!(w, "§")?; } - write_str( + write!( w, - format_args!( - "

{}

", - assoc_type( - item, - generics, - bounds, - None, - link.anchor(if trait_.is_some() { &source_id } else { &id }), - 0, - cx, - ) + "

{}

", + assoc_type( + item, + generics, + bounds, + None, + link.anchor(if trait_.is_some() { &source_id } else { &id }), + 0, + cx, ), - ); + )?; } clean::AssocTypeItem(tydef, _bounds) => { let source_id = format!("{item_type}.{name}"); let id = cx.derive_id(&source_id); - write_str( + write!( w, - format_args!( - "
\ + "
\ {}", - render_rightside(cx, item, render_mode) - ), - ); + render_rightside(cx, item, render_mode), + )?; if trait_.is_some() { // Anchors are only used on trait impls. - write_str(w, format_args!("§")); + write!(w, "§")?; } - write_str( + write!( w, - format_args!( - "

{}

", - assoc_type( - item, - &tydef.generics, - &[], // intentionally leaving out bounds - Some(tydef.item_type.as_ref().unwrap_or(&tydef.type_)), - link.anchor(if trait_.is_some() { &source_id } else { &id }), - 0, - cx, - ) + "

{}

", + assoc_type( + item, + &tydef.generics, + &[], // intentionally leaving out bounds + Some(tydef.item_type.as_ref().unwrap_or(&tydef.type_)), + link.anchor(if trait_.is_some() { &source_id } else { &id }), + 0, + cx, ), - ); + )?; } - clean::StrippedItem(..) => return, + clean::StrippedItem(..) => return Ok(()), _ => panic!("can't make docs for trait item with name {:?}", item.name), } - w.push_str(&info_buffer); + w.write_str(&info_buffer)?; if toggled { - w.push_str("
"); - w.push_str(&doc_buffer); - w.push_str("
"); + write!(w, "
{doc_buffer}
")?; } + Ok(()) } let mut impl_items = String::new(); @@ -1958,7 +1958,7 @@ fn render_impl( false, trait_, rendering_params, - ); + )?; } _ => {} } @@ -1976,7 +1976,7 @@ fn render_impl( false, trait_, rendering_params, - ); + )?; } for method in methods { doc_impl_item( @@ -1990,20 +1990,20 @@ fn render_impl( false, trait_, rendering_params, - ); + )?; } } fn render_default_items( - boring: &mut String, - interesting: &mut String, + mut boring: impl fmt::Write, + mut interesting: impl fmt::Write, cx: &Context<'_>, t: &clean::Trait, i: &clean::Impl, parent: &clean::Item, render_mode: RenderMode, rendering_params: ImplRenderingParameters, - ) { + ) -> fmt::Result { for trait_item in &t.items { // Skip over any default trait items that are impossible to reference // (e.g. if it has a `Self: Sized` bound on an unsized type). @@ -2023,8 +2023,8 @@ fn render_impl( let assoc_link = AssocItemLink::GotoSource(did.into(), &provided_methods); doc_impl_item( - boring, - interesting, + &mut boring, + &mut interesting, cx, trait_item, parent, @@ -2033,8 +2033,9 @@ fn render_impl( true, Some(t), rendering_params, - ); + )?; } + Ok(()) } // If we've implemented a trait, then also emit documentation for all @@ -2054,7 +2055,7 @@ fn render_impl( &i.impl_item, render_mode, rendering_params, - ); + )?; } } if render_mode == RenderMode::Normal { @@ -2171,7 +2172,7 @@ fn render_rightside( }) } -pub(crate) fn render_impl_summary( +fn render_impl_summary( cx: &Context<'_>, i: &Impl, parent: &clean::Item, diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 3c5c2ce19767..39a631b637bd 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -2,7 +2,7 @@ use std::cmp::Ordering; use std::fmt::{self, Display, Write as _}; use std::iter; -use rinja::Template; +use askama::Template; use rustc_abi::VariantIdx; use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; use rustc_hir as hir; @@ -11,7 +11,7 @@ use rustc_hir::def_id::DefId; use rustc_index::IndexVec; use rustc_middle::ty::{self, TyCtxt}; use rustc_span::hygiene::MacroKind; -use rustc_span::symbol::{Symbol, kw, sym}; +use rustc_span::symbol::{Symbol, sym}; use tracing::{debug, info}; use super::type_layout::document_type_layout; @@ -37,7 +37,7 @@ use crate::html::markdown::{HeadingOffset, MarkdownSummaryLine}; use crate::html::render::{document_full, document_item_info}; use crate::html::url_parts_builder::UrlPartsBuilder; -/// Generates a Rinja template struct for rendering items with common methods. +/// Generates an Askama template struct for rendering items with common methods. /// /// Usage: /// ```ignore (illustrative) @@ -301,7 +301,7 @@ fn toggle_close(mut w: impl fmt::Write) { w.write_str("
").unwrap(); } -trait ItemTemplate<'a, 'cx: 'a>: rinja::Template + Display { +trait ItemTemplate<'a, 'cx: 'a>: askama::Template + Display { fn item_and_cx(&self) -> (&'a clean::Item, &'a Context<'cx>); } @@ -347,9 +347,12 @@ fn item_module(cx: &Context<'_>, item: &clean::Item, items: &[clean::Item]) -> i // but we actually want stable items to come first return is_stable2.cmp(&is_stable1); } - let lhs = i1.name.unwrap_or(kw::Empty); - let rhs = i2.name.unwrap_or(kw::Empty); - compare_names(lhs.as_str(), rhs.as_str()) + match (i1.name, i2.name) { + (Some(name1), Some(name2)) => compare_names(name1.as_str(), name2.as_str()), + (Some(_), None) => Ordering::Greater, + (None, Some(_)) => Ordering::Less, + (None, None) => Ordering::Equal, + } } let tcx = cx.tcx(); @@ -1229,12 +1232,13 @@ fn item_trait_alias( wrap_item(w, |w| { write!( w, - "{attrs}trait {name}{generics}{where_b} = {bounds};", + "{attrs}trait {name}{generics} = {bounds}{where_clause};", attrs = render_attributes_in_pre(it, "", cx), name = it.name.unwrap(), generics = t.generics.print(cx), - where_b = print_where_clause(&t.generics, cx, 0, Ending::Newline).maybe_display(), bounds = bounds(&t.bounds, true, cx), + where_clause = + print_where_clause(&t.generics, cx, 0, Ending::NoNewline).maybe_display(), ) })?; @@ -1867,7 +1871,7 @@ fn item_proc_macro(cx: &Context<'_>, it: &clean::Item, m: &clean::ProcMacro) -> } } } - Ok(()) + fmt::Result::Ok(()) })?; write!(w, "{}", document(cx, it, None, HeadingOffset::H2)) }) @@ -1944,7 +1948,7 @@ fn item_constant( } } } - Ok(()) + Ok::<(), fmt::Error>(()) })?; write!(w, "{}", document(cx, it, None, HeadingOffset::H2)) diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs index b39701fae1d6..aff8684ee3a0 100644 --- a/src/librustdoc/html/render/search_index.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -709,8 +709,11 @@ pub(crate) fn build_index( let mut result = Vec::new(); for (index, item) in self.items.iter().enumerate() { if let Some(ty) = &item.search_type - && let my = - ty.param_names.iter().map(|sym| sym.as_str()).collect::>() + && let my = ty + .param_names + .iter() + .filter_map(|sym| sym.map(|sym| sym.to_string())) + .collect::>() && my != prev { result.push((index, my.join(","))); @@ -1109,7 +1112,7 @@ fn simplify_fn_type<'a, 'tcx>( } Type::BareFunction(ref bf) => { let mut ty_generics = Vec::new(); - for ty in bf.decl.inputs.values.iter().map(|arg| &arg.type_) { + for ty in bf.decl.inputs.iter().map(|arg| &arg.type_) { simplify_fn_type( self_, generics, @@ -1372,7 +1375,7 @@ fn simplify_fn_constraint<'a>( /// Used to allow type-based search on constants and statics. fn make_nullary_fn( clean_type: &clean::Type, -) -> (Vec, Vec, Vec, Vec>) { +) -> (Vec, Vec, Vec>, Vec>) { let mut rgen: FxIndexMap)> = Default::default(); let output = get_index_type(clean_type, vec![], &mut rgen); (vec![], vec![output], vec![], vec![]) @@ -1387,7 +1390,7 @@ fn get_fn_inputs_and_outputs( tcx: TyCtxt<'_>, impl_or_trait_generics: Option<&(clean::Type, clean::Generics)>, cache: &Cache, -) -> (Vec, Vec, Vec, Vec>) { +) -> (Vec, Vec, Vec>, Vec>) { let decl = &func.decl; let mut rgen: FxIndexMap)> = Default::default(); @@ -1415,15 +1418,15 @@ fn get_fn_inputs_and_outputs( (None, &func.generics) }; - let mut arg_types = Vec::new(); - for arg in decl.inputs.values.iter() { + let mut param_types = Vec::new(); + for param in decl.inputs.iter() { simplify_fn_type( self_, generics, - &arg.type_, + ¶m.type_, tcx, 0, - &mut arg_types, + &mut param_types, &mut rgen, false, cache, @@ -1436,15 +1439,15 @@ fn get_fn_inputs_and_outputs( let mut simplified_params = rgen.into_iter().collect::>(); simplified_params.sort_by_key(|(_, (idx, _))| -idx); ( - arg_types, + param_types, ret_types, simplified_params .iter() .map(|(name, (_idx, _traits))| match name { - SimplifiedParam::Symbol(name) => *name, - SimplifiedParam::Anonymous(_) => kw::Empty, + SimplifiedParam::Symbol(name) => Some(*name), + SimplifiedParam::Anonymous(_) => None, SimplifiedParam::AssociatedType(def_id, name) => { - Symbol::intern(&format!("{}::{}", tcx.item_name(*def_id), name)) + Some(Symbol::intern(&format!("{}::{}", tcx.item_name(*def_id), name))) } }) .collect(), diff --git a/src/librustdoc/html/render/sidebar.rs b/src/librustdoc/html/render/sidebar.rs index 89ff61ecb03e..cd0c9775f5c9 100644 --- a/src/librustdoc/html/render/sidebar.rs +++ b/src/librustdoc/html/render/sidebar.rs @@ -1,7 +1,7 @@ use std::borrow::Cow; use std::cmp::Ordering; -use rinja::Template; +use askama::Template; use rustc_data_structures::fx::FxHashSet; use rustc_hir::def::CtorKind; use rustc_hir::def_id::{DefIdMap, DefIdSet}; @@ -123,10 +123,10 @@ impl<'a> Link<'a> { pub(crate) mod filters { use std::fmt::{self, Display}; - use rinja::filters::Safe; + use askama::filters::Safe; use crate::html::escape::EscapeBodyTextWithWbr; - pub(crate) fn wrapped(v: T) -> rinja::Result> + pub(crate) fn wrapped(v: T) -> askama::Result> where T: Display, { diff --git a/src/librustdoc/html/render/tests.rs b/src/librustdoc/html/render/tests.rs index 657cd3c82aae..327a30887b1d 100644 --- a/src/librustdoc/html/render/tests.rs +++ b/src/librustdoc/html/render/tests.rs @@ -47,8 +47,7 @@ fn test_all_types_prints_header_once() { // Regression test for #82477 let all_types = AllTypes::new(); - let mut buffer = String::new(); - all_types.print(&mut buffer); + let buffer = all_types.print().to_string(); assert_eq!(1, buffer.matches("List of all items").count()); } diff --git a/src/librustdoc/html/render/type_layout.rs b/src/librustdoc/html/render/type_layout.rs index a1ee5c8c548b..fb1f0271c2ad 100644 --- a/src/librustdoc/html/render/type_layout.rs +++ b/src/librustdoc/html/render/type_layout.rs @@ -1,6 +1,6 @@ use std::fmt; -use rinja::Template; +use askama::Template; use rustc_abi::{Primitive, TagEncoding, Variants}; use rustc_hir::def_id::DefId; use rustc_middle::span_bug; diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs index cbbd4b01d83e..095795c711d9 100644 --- a/src/librustdoc/html/sources.rs +++ b/src/librustdoc/html/sources.rs @@ -3,7 +3,7 @@ use std::ffi::OsStr; use std::path::{Component, Path, PathBuf}; use std::{fmt, fs}; -use rinja::Template; +use askama::Template; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_hir::def_id::LOCAL_CRATE; use rustc_middle::ty::TyCtxt; diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index aa8df35258df..74d23b3143f4 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -1447,7 +1447,7 @@ so that we can apply CSS-filters to change the arrow color in themes */ cursor: pointer; } .setting-check input { - flex-shrink: 0, + flex-shrink: 0; } .setting-radio input:checked { diff --git a/src/librustdoc/html/templates/STYLE.md b/src/librustdoc/html/templates/STYLE.md index 32bacb11475c..12c2553cffdb 100644 --- a/src/librustdoc/html/templates/STYLE.md +++ b/src/librustdoc/html/templates/STYLE.md @@ -1,13 +1,13 @@ # Style for Templates -This directory has templates in the [Rinja templating language][rinjadoc], which is very +This directory has templates in the [Askama templating language][askamadoc], which is very similar to [Jinja2][jinjadoc]. [jinjadoc]: https://jinja.palletsprojects.com/en/3.1.x/templates/ -[rinjadoc]: https://docs.rs/rinja/latest/rinja/ +[askamadoc]: https://docs.rs/askama/latest/askama/ We want our rendered output to have as little unnecessary whitespace as -possible, so that pages load quickly. To achieve that we use Rinja's +possible, so that pages load quickly. To achieve that we use Askama's [whitespace control] features. By default, whitespace characters are removed around jinja tags (`{% %}` for example). At the end of most lines, we put an empty comment tag: `{# #}`. This causes all whitespace between the end of the @@ -18,7 +18,7 @@ remove following whitespace but not preceding. We also use the whitespace control characters in most instances of tags with control flow, for example `{% if foo %}`. -[whitespace control]: https://rinja.readthedocs.io/en/stable/configuration.html#whitespace-control +[whitespace control]: https://askama.readthedocs.io/en/stable/configuration.html#whitespace-control We want our templates to be readable, so we use indentation and newlines liberally. We indent by four spaces after opening an HTML tag _or_ a Jinja @@ -26,11 +26,11 @@ tag. In most cases an HTML tag should be followed by a newline, but if the tag has simple contents and fits with its close tag on a single line, the contents don't necessarily need a new line. -Rinja templates support quite sophisticated control flow. To keep our templates +Askama templates support quite sophisticated control flow. To keep our templates simple and understandable, we use only a subset: `if` and `for`. In particular -we avoid [assignments in the template logic][assignments] and [Rinja +we avoid [assignments in the template logic][assignments] and [Askama macros][macros]. This also may make things easier if we switch to a different Jinja-style template system in the future. -[assignments]: https://rinja.readthedocs.io/en/stable/template_syntax.html#assignments -[macros]: https://rinja.readthedocs.io/en/stable/template_syntax.html#macros +[assignments]: https://askama.readthedocs.io/en/stable/template_syntax.html#assignments +[macros]: https://askama.readthedocs.io/en/stable/template_syntax.html#macros diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 9d8eb70fbe07..dab23f8e42a3 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -11,7 +11,7 @@ use rustc_hir::def::CtorKind; use rustc_hir::def_id::DefId; use rustc_metadata::rendered_const; use rustc_middle::{bug, ty}; -use rustc_span::{Pos, Symbol}; +use rustc_span::{Pos, Symbol, kw}; use rustdoc_json_types::*; use crate::clean::{self, ItemId}; @@ -609,9 +609,13 @@ impl FromClean for FunctionSignature { let clean::FnDecl { inputs, output, c_variadic } = decl; FunctionSignature { inputs: inputs - .values .into_iter() - .map(|arg| (arg.name.to_string(), arg.type_.into_json(renderer))) + .map(|param| { + // `_` is the most sensible name for missing param names. + let name = param.name.unwrap_or(kw::Underscore).to_string(); + let type_ = param.type_.into_json(renderer); + (name, type_) + }) .collect(), output: if output.is_unit() { None } else { Some(output.into_json(renderer)) }, is_c_variadic: c_variadic, diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs index ba27eed7c113..131a12ce228f 100644 --- a/src/librustdoc/json/mod.rs +++ b/src/librustdoc/json/mod.rs @@ -14,6 +14,7 @@ use std::io::{BufWriter, Write, stdout}; use std::path::PathBuf; use std::rc::Rc; +use rustc_data_structures::fx::FxHashSet; use rustc_hir::def_id::{DefId, DefIdSet}; use rustc_middle::ty::TyCtxt; use rustc_session::Session; @@ -123,6 +124,58 @@ impl<'tcx> JsonRenderer<'tcx> { } } +fn target(sess: &rustc_session::Session) -> types::Target { + // Build a set of which features are enabled on this target + let globally_enabled_features: FxHashSet<&str> = + sess.unstable_target_features.iter().map(|name| name.as_str()).collect(); + + // Build a map of target feature stability by feature name + use rustc_target::target_features::Stability; + let feature_stability: FxHashMap<&str, Stability> = sess + .target + .rust_target_features() + .into_iter() + .copied() + .map(|(name, stability, _)| (name, stability)) + .collect(); + + types::Target { + triple: sess.opts.target_triple.tuple().into(), + target_features: sess + .target + .rust_target_features() + .into_iter() + .copied() + .filter(|(_, stability, _)| { + // Describe only target features which the user can toggle + stability.toggle_allowed().is_ok() + }) + .map(|(name, stability, implied_features)| { + types::TargetFeature { + name: name.into(), + unstable_feature_gate: match stability { + Stability::Unstable(feature_gate) => Some(feature_gate.as_str().into()), + _ => None, + }, + implies_features: implied_features + .into_iter() + .copied() + .filter(|name| { + // Imply only target features which the user can toggle + feature_stability + .get(name) + .map(|stability| stability.toggle_allowed().is_ok()) + .unwrap_or(false) + }) + .map(String::from) + .collect(), + globally_enabled: globally_enabled_features.contains(name), + } + }) + .collect(), + } +} + impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> { fn descr() -> &'static str { "json" @@ -248,6 +301,12 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> { let e = ExternalCrate { crate_num: LOCAL_CRATE }; let index = (*self.index).clone().into_inner(); + // Note that tcx.rust_target_features is inappropriate here because rustdoc tries to run for + // multiple targets: https://github.com/rust-lang/rust/pull/137632 + // + // We want to describe a single target, so pass tcx.sess rather than tcx. + let target = target(self.tcx.sess); + debug!("Constructing Output"); let output_crate = types::Crate { root: self.id_from_item_default(e.def_id().into()), @@ -288,6 +347,7 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> { ) }) .collect(), + target, format_version: types::FORMAT_VERSION, }; if let Some(ref out_dir) = self.out_dir { diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index fdbb792d25da..297597b3deac 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -60,7 +60,7 @@ fn filter_assoc_items_by_name_and_namespace( ns: Namespace, ) -> impl Iterator { tcx.associated_items(assoc_items_of).filter_by_name_unhygienic(ident.name).filter(move |item| { - item.kind.namespace() == ns && tcx.hygienic_eq(ident, item.ident(tcx), assoc_items_of) + item.namespace() == ns && tcx.hygienic_eq(ident, item.ident(tcx), assoc_items_of) }) } @@ -743,7 +743,7 @@ impl<'tcx> LinkCollector<'_, 'tcx> { ns, ) .map(|item| { - let res = Res::Def(item.kind.as_def_kind(), item.def_id); + let res = Res::Def(item.as_def_kind(), item.def_id); (res, item.def_id) }) .collect::>(), diff --git a/src/librustdoc/passes/strip_hidden.rs b/src/librustdoc/passes/strip_hidden.rs index bcdca862862d..692ce21d6cfb 100644 --- a/src/librustdoc/passes/strip_hidden.rs +++ b/src/librustdoc/passes/strip_hidden.rs @@ -91,19 +91,21 @@ impl DocFolder for Stripper<'_, '_> { if let clean::ImportItem(clean::Import { source, .. }) = &i.kind && let Some(source_did) = source.did - && let Some(import_def_id) = i.def_id().and_then(|def_id| def_id.as_local()) { - let reexports = reexport_chain(self.tcx, import_def_id, source_did); - - // Check if any reexport in the chain has a hidden source - let has_hidden_source = reexports - .iter() - .filter_map(|reexport| reexport.id()) - .any(|reexport_did| self.tcx.is_doc_hidden(reexport_did)) - || self.tcx.is_doc_hidden(source_did); - - if has_hidden_source { + if self.tcx.is_doc_hidden(source_did) { return None; + } else if let Some(import_def_id) = i.def_id().and_then(|def_id| def_id.as_local()) { + let reexports = reexport_chain(self.tcx, import_def_id, source_did); + + // Check if any reexport in the chain has a hidden source + let has_hidden_source = reexports + .iter() + .filter_map(|reexport| reexport.id()) + .any(|reexport_did| self.tcx.is_doc_hidden(reexport_did)); + + if has_hidden_source { + return None; + } } } diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs index 137fe4c4c354..7247950545ad 100644 --- a/src/rustdoc-json-types/lib.rs +++ b/src/rustdoc-json-types/lib.rs @@ -30,7 +30,7 @@ pub type FxHashMap = HashMap; // re-export for use in src/librustdoc /// This integer is incremented with every breaking change to the API, /// and is returned along with the JSON blob as [`Crate::format_version`]. /// Consuming code should assert that this value matches the format version(s) that it supports. -pub const FORMAT_VERSION: u32 = 43; +pub const FORMAT_VERSION: u32 = 44; /// The root of the emitted JSON blob. /// @@ -52,11 +52,67 @@ pub struct Crate { pub paths: HashMap, /// Maps `crate_id` of items to a crate name and html_root_url if it exists. pub external_crates: HashMap, + /// Information about the target for which this documentation was generated + pub target: Target, /// A single version number to be used in the future when making backwards incompatible changes /// to the JSON output. pub format_version: u32, } +/// Information about a target +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +pub struct Target { + /// The target triple for which this documentation was generated + pub triple: String, + /// A list of features valid for use in `#[target_feature]` attributes + /// for the target where this rustdoc JSON was generated. + pub target_features: Vec, +} + +/// Information about a target feature. +/// +/// Rust target features are used to influence code generation, especially around selecting +/// instructions which are not universally supported by the target architecture. +/// +/// Target features are commonly enabled by the [`#[target_feature]` attribute][1] to influence code +/// generation for a particular function, and less commonly enabled by compiler options like +/// `-Ctarget-feature` or `-Ctarget-cpu`. Targets themselves automatically enable certain target +/// features by default, for example because the target's ABI specification requires saving specific +/// registers which only exist in an architectural extension. +/// +/// Target features can imply other target features: for example, x86-64 `avx2` implies `avx`, and +/// aarch64 `sve2` implies `sve`, since both of these architectural extensions depend on their +/// predecessors. +/// +/// Target features can be probed at compile time by [`#[cfg(target_feature)]`][2] or `cfg!(…)` +/// conditional compilation to determine whether a target feature is enabled in a particular +/// context. +/// +/// [1]: https://doc.rust-lang.org/stable/reference/attributes/codegen.html#the-target_feature-attribute +/// [2]: https://doc.rust-lang.org/reference/conditional-compilation.html#target_feature +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +pub struct TargetFeature { + /// The name of this target feature. + pub name: String, + /// Other target features which are implied by this target feature, if any. + pub implies_features: Vec, + /// If this target feature is unstable, the name of the associated language feature gate. + pub unstable_feature_gate: Option, + /// Whether this feature is globally enabled for this compilation session. + /// + /// Target features can be globally enabled implicitly as a result of the target's definition. + /// For example, x86-64 hardware floating point ABIs require saving x87 and SSE2 registers, + /// which in turn requires globally enabling the `x87` and `sse2` target features so that the + /// generated machine code conforms to the target's ABI. + /// + /// Target features can also be globally enabled explicitly as a result of compiler flags like + /// [`-Ctarget-feature`][1] or [`-Ctarget-cpu`][2]. + /// + /// [1]: https://doc.rust-lang.org/beta/rustc/codegen-options/index.html#target-feature + /// [2]: https://doc.rust-lang.org/beta/rustc/codegen-options/index.html#target-cpu + pub globally_enabled: bool, +} + /// Metadata of a crate, either the same crate on which `rustdoc` was invoked, or its dependency. #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct ExternalCrate { diff --git a/src/stage0 b/src/stage0 index 9d6a08d378d8..6e86501a72ab 100644 --- a/src/stage0 +++ b/src/stage0 @@ -14,468 +14,466 @@ nightly_branch=master # All changes below this comment will be overridden the next time the # tool is executed. -compiler_date=2025-02-18 +compiler_date=2025-04-02 compiler_version=beta -rustfmt_date=2025-02-18 +rustfmt_date=2025-04-02 rustfmt_version=nightly -dist/2025-02-18/rustc-beta-aarch64-apple-darwin.tar.gz=1b51ca064350d8b15c7ab6c8ec996a497e912dc237cafc2c205066fc6416e0ff -dist/2025-02-18/rustc-beta-aarch64-apple-darwin.tar.xz=e4b71f6456d9e62ada6909254606da7f6681f3da0f5bc7d2c3d5c387fea35743 -dist/2025-02-18/rustc-beta-aarch64-pc-windows-msvc.tar.gz=1ff70a5bd238d959d806c3b471a5b03c6cde784944a96a585e0ae0837d2a9c92 -dist/2025-02-18/rustc-beta-aarch64-pc-windows-msvc.tar.xz=5017b351bb90a08041757eae61386b224ec0161c5734293184a87d8903f30098 -dist/2025-02-18/rustc-beta-aarch64-unknown-linux-gnu.tar.gz=8a58b6cc4577615efc76bb9472229098d6f938c1f051ea540409e9dc812dbd8f -dist/2025-02-18/rustc-beta-aarch64-unknown-linux-gnu.tar.xz=330e217dbd1c507c8706aef5fbd0baf9584495445743f38668cdc962adfb125e -dist/2025-02-18/rustc-beta-aarch64-unknown-linux-musl.tar.gz=4060ec54281975880a9819b815120d6a450e4c31ddf1136ecce348e28875d50d -dist/2025-02-18/rustc-beta-aarch64-unknown-linux-musl.tar.xz=0f92b9267a55ac0c764cde63b8cbc8a0a317f7e0817185d380fc2aa35a933687 -dist/2025-02-18/rustc-beta-arm-unknown-linux-gnueabi.tar.gz=4e989e00725e7cfb08ea834c74ec6dd352eda74c13218f7da423ed598af9f9df -dist/2025-02-18/rustc-beta-arm-unknown-linux-gnueabi.tar.xz=b06181daf8842c2e544e5d54169f9bbfc70ee76115495de033ac4e341617a588 -dist/2025-02-18/rustc-beta-arm-unknown-linux-gnueabihf.tar.gz=93fe2efcde1032ad636ef509a73168f0ab7fadbca699a27e2882b3832539e8fa -dist/2025-02-18/rustc-beta-arm-unknown-linux-gnueabihf.tar.xz=b49d0256381c928785035578e5b7624c37ba732ea7aefca37dbb66b5162c8090 -dist/2025-02-18/rustc-beta-armv7-unknown-linux-gnueabihf.tar.gz=56fd36c20d78085f39f0df40f15f7694e8744714104539865b9c3d7b06d47e2f -dist/2025-02-18/rustc-beta-armv7-unknown-linux-gnueabihf.tar.xz=86587bea60c2b8a114ab33fe65a7152fcf8e1dcca14550712dca72af9fd65674 -dist/2025-02-18/rustc-beta-i686-pc-windows-gnu.tar.gz=32c95c78b223efea2ee8e02fbe3a58ac753ce9284e792bc87feaa051fcff5687 -dist/2025-02-18/rustc-beta-i686-pc-windows-gnu.tar.xz=d2e623f11aee7e81eceb6947e3f7150bfd727eb2f527e4abc6b10d3322959802 -dist/2025-02-18/rustc-beta-i686-pc-windows-msvc.tar.gz=f7ffd07eb2b5e83df513c6a313e28003e3ce923778583e78da9efbb5e62405dc -dist/2025-02-18/rustc-beta-i686-pc-windows-msvc.tar.xz=cd2e61b548a6849b17183fcacb2ac8f94955d893be439793580c39080feb28be -dist/2025-02-18/rustc-beta-i686-unknown-linux-gnu.tar.gz=fedeca202c1651fe4b15cfc411365ecf016376b3cc7c772d2e0d739e0ec02dc6 -dist/2025-02-18/rustc-beta-i686-unknown-linux-gnu.tar.xz=6389f10e2328bdfa81ef1f34406bb4ec8bcb6dcf64d39c95946d32c9fee7f0b7 -dist/2025-02-18/rustc-beta-loongarch64-unknown-linux-gnu.tar.gz=21b565bbaacc2be5d066c5d0c49b7c0f5b0bd24690ca35e9c88e6ec91846f744 -dist/2025-02-18/rustc-beta-loongarch64-unknown-linux-gnu.tar.xz=4a728e3ec41834775f0b288cdca5ae152314edcaf20d7ea46ea62fab1b9ef327 -dist/2025-02-18/rustc-beta-loongarch64-unknown-linux-musl.tar.gz=0a72f650aa70708f9a72886ea33b7a2e3ffe2a6e2cbcb1d2248f3d9eca74a9d4 -dist/2025-02-18/rustc-beta-loongarch64-unknown-linux-musl.tar.xz=877c3c447f4c25068f70bd7d6dd5078d75b0c194777b2f8a9311a66fc6eda701 -dist/2025-02-18/rustc-beta-powerpc-unknown-linux-gnu.tar.gz=67af5e05ab0a367d3f76c0656823b530a23fb26d9c86db2b433684b9191b8881 -dist/2025-02-18/rustc-beta-powerpc-unknown-linux-gnu.tar.xz=2da086d39eaa000ba629ee15bec740db57039ca3e5c7c55feb9cb9ca6d39c785 -dist/2025-02-18/rustc-beta-powerpc64-unknown-linux-gnu.tar.gz=b079df9a3e5be95a755d22f5ecf3ddeb43f94d96eaa3985770ae98ad0e7e15bb -dist/2025-02-18/rustc-beta-powerpc64-unknown-linux-gnu.tar.xz=916fe3b67094bb351320371de9587f01bb65f9b9aed2c7aff7930e499822b660 -dist/2025-02-18/rustc-beta-powerpc64le-unknown-linux-gnu.tar.gz=356e3173c960aadfb91dcb607a26647895fb1ae11a7cb596b019c71c6dd808e7 -dist/2025-02-18/rustc-beta-powerpc64le-unknown-linux-gnu.tar.xz=9115c4c85d8c4b5254df41a5d3f55733648ba282711e18a692ee100ed13fb550 -dist/2025-02-18/rustc-beta-powerpc64le-unknown-linux-musl.tar.gz=b8a267f9ca2d23385c529924782f633b6b9f66b50cda5986eff91c223d715307 -dist/2025-02-18/rustc-beta-powerpc64le-unknown-linux-musl.tar.xz=84e65fc1d4282d737b6d0b1aaa1c2abd395af215983eb5b3700e925ca6ba3bc3 -dist/2025-02-18/rustc-beta-riscv64gc-unknown-linux-gnu.tar.gz=19b1d8618edb5d3a6cf620c814f6b76a462bc965f4aac2cde7aca5849b92cac9 -dist/2025-02-18/rustc-beta-riscv64gc-unknown-linux-gnu.tar.xz=9914408b5590fe7c43b2aa10c261bb5162b024e396c625b06546564a5eaddb89 -dist/2025-02-18/rustc-beta-s390x-unknown-linux-gnu.tar.gz=37ac73ea85f43a4859d8c4526cb9480e69bcaa778e842128852c8b21c6db6b45 -dist/2025-02-18/rustc-beta-s390x-unknown-linux-gnu.tar.xz=af1cab661b26cab1ade53f12ec08d13d60a74c2f370d9d3617154e0f01cb3719 -dist/2025-02-18/rustc-beta-x86_64-apple-darwin.tar.gz=aa9999ad56f8968e3e0f5417661ff42fbd1bd482a649d1a8c01d6ba5a6e78a72 -dist/2025-02-18/rustc-beta-x86_64-apple-darwin.tar.xz=bfd09bf8db9bbd7557df3f206207631cc4b10d59d0cf6b072e610646b5c7fa4a -dist/2025-02-18/rustc-beta-x86_64-pc-windows-gnu.tar.gz=dabab346a003a5b13265da6bab96fc703c34f728c852092bec4cf08d13daeadc -dist/2025-02-18/rustc-beta-x86_64-pc-windows-gnu.tar.xz=c2252dea69c8dcf6ba0213da8b05b8d9173676fb7448cde684da7b56d2c52577 -dist/2025-02-18/rustc-beta-x86_64-pc-windows-msvc.tar.gz=9ae9c3cb963872b2ef02650bcec15906e0b5e89cc6d3bee0aadfffcec7a1e6df -dist/2025-02-18/rustc-beta-x86_64-pc-windows-msvc.tar.xz=bcbf75c92e9afe6b25bbde275bd38c3cdeda6324baf5b8c99173ca5738760a7f -dist/2025-02-18/rustc-beta-x86_64-unknown-freebsd.tar.gz=5313d0780f6a9587e809da0f1ffc973721afad88a0ef8fb83005c383d79229d8 -dist/2025-02-18/rustc-beta-x86_64-unknown-freebsd.tar.xz=52ab3212d64b56a8da207fe976cbc8d266e962a61c742e6069137b10ff25c3c1 -dist/2025-02-18/rustc-beta-x86_64-unknown-illumos.tar.gz=527f839ddedc7bdff48527a276d3d7f64d475dd815b81c6664f1ce25668e0ce4 -dist/2025-02-18/rustc-beta-x86_64-unknown-illumos.tar.xz=3861d9928983a415cd44e5dc50a99af948fac392adfb6c2147b14fb98dd08890 -dist/2025-02-18/rustc-beta-x86_64-unknown-linux-gnu.tar.gz=0054d14cf00b25cfbcb2a1560887c825f703223312ca9cdd0ad51076bf54a3cc -dist/2025-02-18/rustc-beta-x86_64-unknown-linux-gnu.tar.xz=75a9d69d13e50bb22ec721f9c64d08282d76f285482b285bb61bacabeecd710c -dist/2025-02-18/rustc-beta-x86_64-unknown-linux-musl.tar.gz=305765ca6a413ea86360b970bd062a19f6bc52756551af43d74920fc2a021d95 -dist/2025-02-18/rustc-beta-x86_64-unknown-linux-musl.tar.xz=c7230b578a97fb234ac106c7333615074b9a7a8abc1422f149ad613c2af28134 -dist/2025-02-18/rustc-beta-x86_64-unknown-netbsd.tar.gz=881bd9b260b2c7838ea1b4de2cd6baf2ff4d317e0c159faba1a683c4c32ba267 -dist/2025-02-18/rustc-beta-x86_64-unknown-netbsd.tar.xz=0c4f2cc0bafbf8b41b257e851870b64d3b5fc112f02227f561c645dc439c96db -dist/2025-02-18/rust-std-beta-aarch64-apple-darwin.tar.gz=958434edfc07bf6d10da3d41f01d1511b28d1178423a78bff2f60cd10046dbca -dist/2025-02-18/rust-std-beta-aarch64-apple-darwin.tar.xz=80043af05fb96c497bce55063f2733e37f243f85084f9aa60ab504d7c15c5cce -dist/2025-02-18/rust-std-beta-aarch64-apple-ios.tar.gz=509aa8803b29ccbb97a1a8c12e2ca6b27310d5af313650c7afff45ab1843106a -dist/2025-02-18/rust-std-beta-aarch64-apple-ios.tar.xz=f0f05dafc9a3277b075023bb449675946706307f769590c065cb53ae615708d9 -dist/2025-02-18/rust-std-beta-aarch64-apple-ios-macabi.tar.gz=c37c0aee56c5858f91fb5aa60df28cc92649d4884d5edde57eb6690f494ba5f5 -dist/2025-02-18/rust-std-beta-aarch64-apple-ios-macabi.tar.xz=e5120697e4a118824fdebf6d2a644f8f338bb83e209303fc684095b8f6b4ab1c -dist/2025-02-18/rust-std-beta-aarch64-apple-ios-sim.tar.gz=d5b851917a3f57703378596828e92068c28e00fe0b02331891737c2fc697b5ff -dist/2025-02-18/rust-std-beta-aarch64-apple-ios-sim.tar.xz=ef33164320931007db65f4915b533e5078a7279a7a134fc80045751a5198834a -dist/2025-02-18/rust-std-beta-aarch64-linux-android.tar.gz=4b94607d7c09b4f0f85236fb2237f1859150e12745ee2020cb134db904c1e05b -dist/2025-02-18/rust-std-beta-aarch64-linux-android.tar.xz=3aa7807ef9da83e1a4deebe4a7085e4df1b60edd4e9f237870f827073100d09c -dist/2025-02-18/rust-std-beta-aarch64-pc-windows-gnullvm.tar.gz=2d4c8a5a400c35443228087f8203f320253299a5018c1b92526f99023581c3e9 -dist/2025-02-18/rust-std-beta-aarch64-pc-windows-gnullvm.tar.xz=df8741055b3d4f7eeedec9e0101a1c184a37ffb75b2d4474bfbca577300355f2 -dist/2025-02-18/rust-std-beta-aarch64-pc-windows-msvc.tar.gz=8db9c07d4b68018cd3c67be1e7bc496078dfa8a6852a35c449db5ba19f6bf0df -dist/2025-02-18/rust-std-beta-aarch64-pc-windows-msvc.tar.xz=f112e3d51013ceff37e8c05d80c3605b76ddec8e55474d55815b4860f96febc8 -dist/2025-02-18/rust-std-beta-aarch64-unknown-fuchsia.tar.gz=2bb6d934225823c2dcdb86dca91dd8e488f69b238b283607f75abe9b5de46486 -dist/2025-02-18/rust-std-beta-aarch64-unknown-fuchsia.tar.xz=99036fde94fe0cb3ab2d2f48cd9f9bbb4d2fa784f1bd21afaa71b032cd95b069 -dist/2025-02-18/rust-std-beta-aarch64-unknown-linux-gnu.tar.gz=c49fee34a02f5d3fe4e03ed7da90e045f7967c3e2e8f7a30804f4da5d535225c -dist/2025-02-18/rust-std-beta-aarch64-unknown-linux-gnu.tar.xz=88170a13f9448b9671d252f0315aed94b6324716230db7307061d4890cfda70a -dist/2025-02-18/rust-std-beta-aarch64-unknown-linux-musl.tar.gz=a5e7442d722f6742fd0436d3c7d75738bc6cbd936f3399190086a88ef311e34e -dist/2025-02-18/rust-std-beta-aarch64-unknown-linux-musl.tar.xz=5d07a95e3203ebe98eed1b271a2e6ae44bead53e7bda019a8d256c8553c21bd1 -dist/2025-02-18/rust-std-beta-aarch64-unknown-linux-ohos.tar.gz=0af6b8fc7f46641d4de61ada9bc9ff01af7775d727121267177fa4c43cc9ed7b -dist/2025-02-18/rust-std-beta-aarch64-unknown-linux-ohos.tar.xz=fd68b34e7aba25d8a834c018febbde6c3de7d967e014a738681642f41ec61603 -dist/2025-02-18/rust-std-beta-aarch64-unknown-none.tar.gz=46025b0892498de8e311be7bd6df261065f80a70720cb9285062161a30af5d76 -dist/2025-02-18/rust-std-beta-aarch64-unknown-none.tar.xz=b4cbf42364270c158d801ac7d4b6cfd7bf1f5f9e74a3044e6d959f1971f5bc34 -dist/2025-02-18/rust-std-beta-aarch64-unknown-none-softfloat.tar.gz=ae2a5c63cce6ce237c81ae78cabc6e1e0634c956789c2e2f39e3a6c0d864636f -dist/2025-02-18/rust-std-beta-aarch64-unknown-none-softfloat.tar.xz=6bba5069c89d9a0d9a2013715814fb55ebcd77b342ed0dfc72115a18367c5e8c -dist/2025-02-18/rust-std-beta-aarch64-unknown-uefi.tar.gz=0bef07ceece7523d6f41f1d640569c52ebe8a6b97b35da84240d873fd68250da -dist/2025-02-18/rust-std-beta-aarch64-unknown-uefi.tar.xz=cff8b58e158786cee1a719552fb97cb2cd3a12b541641437809428a65eed42fa -dist/2025-02-18/rust-std-beta-arm-linux-androideabi.tar.gz=a34fbf0d01cea60876a6d0aa4ee96587a5e31b6d4f84aa7c1ba5b7fed261b639 -dist/2025-02-18/rust-std-beta-arm-linux-androideabi.tar.xz=7d72d638f5984726fb4a61e81671d9557d0a9a876bf5bbf39b2df3c9983d2962 -dist/2025-02-18/rust-std-beta-arm-unknown-linux-gnueabi.tar.gz=9ef3aa1bcbe1a18658bd16359cbf3e94ae1b07f65bd5c69ffbfa964ad845baf5 -dist/2025-02-18/rust-std-beta-arm-unknown-linux-gnueabi.tar.xz=93020195c2ce07204179e2d2f900953707e341a71d9371551c4a727afc58378e -dist/2025-02-18/rust-std-beta-arm-unknown-linux-gnueabihf.tar.gz=5b0a4c4831534de85a5ba5b0149bbd824ca83648bf66babe5dbf13291b06e03d -dist/2025-02-18/rust-std-beta-arm-unknown-linux-gnueabihf.tar.xz=60f1ff95cc88330b6c9741520c02ec845e7b14943f2927091a9110b7fb1c4305 -dist/2025-02-18/rust-std-beta-arm-unknown-linux-musleabi.tar.gz=0f254a943b6e56873d2ab84e8a93fa7a3ab723df5a7926faeadae4696ed06121 -dist/2025-02-18/rust-std-beta-arm-unknown-linux-musleabi.tar.xz=0c682e7cbba8463682a0a20785ff7fd331d2bc7a32c0cf86b8159897fc5c5ee7 -dist/2025-02-18/rust-std-beta-arm-unknown-linux-musleabihf.tar.gz=6c5be45f79035f57ac41fd209f6e7d4439cab5acaa766f7bf001b24196411b1e -dist/2025-02-18/rust-std-beta-arm-unknown-linux-musleabihf.tar.xz=bf25eb6650ad27377414d53af6857133a539530c841cf96e3cae4406bf4ad485 -dist/2025-02-18/rust-std-beta-arm64ec-pc-windows-msvc.tar.gz=39ec7fd0ecf47b36c6badc1fc71f1290e99d2edfa9d7cfa72446fbb32ba9c8b0 -dist/2025-02-18/rust-std-beta-arm64ec-pc-windows-msvc.tar.xz=f1d578e9251d95c94c20e3ee7888993ec7ea3d967a880f89963df7bea0bbe93b -dist/2025-02-18/rust-std-beta-armebv7r-none-eabi.tar.gz=3990bce70402da79a27fd0f4adb169e4e9faf617bdbca2676bc41d9f85845dd7 -dist/2025-02-18/rust-std-beta-armebv7r-none-eabi.tar.xz=ac944400a3da94e32d7010e10b30879bbb5da456d3d54dfd0efc792884b035de -dist/2025-02-18/rust-std-beta-armebv7r-none-eabihf.tar.gz=1196e2ae338b325ceb89edaab8b165478ec481270a7ce4c65f47f45d76e7b33b -dist/2025-02-18/rust-std-beta-armebv7r-none-eabihf.tar.xz=fead57620d21252c958020e340fc793102d177f76fd90b3936eaf3a22a3b87c9 -dist/2025-02-18/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.gz=e5e81e1501554c2b28745c4d905bbe50f909dce3b7806f6010a9d48cc528304e -dist/2025-02-18/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.xz=d3c9513cdb058685848de3d7864a7fa5a9b1e45f779a7ecf447ac7faae652772 -dist/2025-02-18/rust-std-beta-armv5te-unknown-linux-musleabi.tar.gz=6ca5598fbdbf77bcf971e62d5b3f486e25d01e95773670bdc600448f29b68a09 -dist/2025-02-18/rust-std-beta-armv5te-unknown-linux-musleabi.tar.xz=7e0a8798586538c4b322b58b9e1ac90e27dea4a0b5b750873f90b8ec9dcdbe2e -dist/2025-02-18/rust-std-beta-armv7-linux-androideabi.tar.gz=cbd81d4f949248c0c48a60545648a384aa321ee5f590f52d50e8d3639a649745 -dist/2025-02-18/rust-std-beta-armv7-linux-androideabi.tar.xz=75216a970ba5a023717dbbd45b5a1a90ff9533f25deca241c11ebce80dc6229e -dist/2025-02-18/rust-std-beta-armv7-unknown-linux-gnueabi.tar.gz=5acf37dc6035d3d83d003d70d3db3c196b20d461a70385e8e5d545be1f4392b4 -dist/2025-02-18/rust-std-beta-armv7-unknown-linux-gnueabi.tar.xz=8c75b0c815465126d6c7516883c478c78fc83cfb294bd5b9387d5bad65c9810f -dist/2025-02-18/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.gz=733fca96e3d6dd232c746a6034bd7cc864f06bfce3d5da3bfd72c5ca4cea221d -dist/2025-02-18/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.xz=e9ef142105d0073bf070a6de74e7173fbc09f3f22fd50eef0fea8ab6cf0ab4d7 -dist/2025-02-18/rust-std-beta-armv7-unknown-linux-musleabi.tar.gz=13f2b55f297628bea201f3caaae0178f0d898c67a696d4b60a37c3ba5af0582b -dist/2025-02-18/rust-std-beta-armv7-unknown-linux-musleabi.tar.xz=455605ff7e88d69052a4b3798ba27a673807ac1be197a8ac9e57497b5bac1661 -dist/2025-02-18/rust-std-beta-armv7-unknown-linux-musleabihf.tar.gz=5b4b8eae2d86baeb470ad2a143f5d91f0dedeb225607189d9d0f8c8115e5251f -dist/2025-02-18/rust-std-beta-armv7-unknown-linux-musleabihf.tar.xz=fd36a0f0a001436195eacdb52baee2462c43a1f9899b2e01ed60019f8285a95d -dist/2025-02-18/rust-std-beta-armv7-unknown-linux-ohos.tar.gz=093900dfc07c4c4f59bd84aa8e9b505890cd8736a994798da8cfd7fb6210ab5b -dist/2025-02-18/rust-std-beta-armv7-unknown-linux-ohos.tar.xz=e5cef28308348a378835ced449affa965f49d9b7382d28cbf32337ae94ebc9cd -dist/2025-02-18/rust-std-beta-armv7a-none-eabi.tar.gz=210229d27f6d574670e9406b98748869212e66713a8ad37f2e5b67ebf27e43ab -dist/2025-02-18/rust-std-beta-armv7a-none-eabi.tar.xz=323197f1dc3fe70e0a540df8a5f5d9475dcb390f1685bef54ba355ad3b48f316 -dist/2025-02-18/rust-std-beta-armv7r-none-eabi.tar.gz=f66d3a794ea7ea0df73b5df389738e6b3e1790b27c06187de2ed1888743ecb57 -dist/2025-02-18/rust-std-beta-armv7r-none-eabi.tar.xz=ae1465d82ea49e5ed33ac95dc0ece4c8fd0ce3df20b21a6a44ed93f33d131aca -dist/2025-02-18/rust-std-beta-armv7r-none-eabihf.tar.gz=fa0d84655bfb7488c9c378ecf833edbde08c652d25fbc9092ed2707b320f657a -dist/2025-02-18/rust-std-beta-armv7r-none-eabihf.tar.xz=251ba3b71c4a0bbdc327a84ee1b3c3deeeed3917fe55aadff9a52a44063f6270 -dist/2025-02-18/rust-std-beta-i586-pc-windows-msvc.tar.gz=9d9d89b206dc85323a7ee765447d1cafc2fab9189be88e1558709d94c51f2298 -dist/2025-02-18/rust-std-beta-i586-pc-windows-msvc.tar.xz=b124483bdffbb41b5c806f6bcc1003ba15d031cf5fe02eaead555abe15da20a6 -dist/2025-02-18/rust-std-beta-i586-unknown-linux-gnu.tar.gz=914925fb75c45cd9939c8692b02efd337b814040ca9bce369d812b97698a4c3e -dist/2025-02-18/rust-std-beta-i586-unknown-linux-gnu.tar.xz=eefceae8f0d42a5e3524ac134afa9a13e938f1680edf605cca2e2d9dfbd33682 -dist/2025-02-18/rust-std-beta-i586-unknown-linux-musl.tar.gz=4baafd6924c5ab59c0c4dfd30272c08328ea1f31b70e8a9a3dababb94c1dee03 -dist/2025-02-18/rust-std-beta-i586-unknown-linux-musl.tar.xz=c75b6e4b50cd731d7f955956ce0afc02f04e2adc4268a1bec8b076eb1733ad28 -dist/2025-02-18/rust-std-beta-i686-linux-android.tar.gz=e067c5483336195763c2f1e9625644075fd93cc86180e6d24bee63aa26b22e99 -dist/2025-02-18/rust-std-beta-i686-linux-android.tar.xz=d4892feae881cc914b94b8bfd66b5e75cc4d62cbb697b8faa3f29d1d70d15f5f -dist/2025-02-18/rust-std-beta-i686-pc-windows-gnu.tar.gz=ff6f43c40e2f8edc9ca21df771c3c28ab77bcb0e254adaa09d8c9433bd56fa97 -dist/2025-02-18/rust-std-beta-i686-pc-windows-gnu.tar.xz=8d6088d7ef7f13bbf576fe238e8a032091359a773845f35e3329b5d8273d1fcc -dist/2025-02-18/rust-std-beta-i686-pc-windows-gnullvm.tar.gz=cc62a0e5c529bb041455ed15f646e5c9c918f20a644ed7306ad8beb1abf07c1d -dist/2025-02-18/rust-std-beta-i686-pc-windows-gnullvm.tar.xz=9cdcd32f73d9839c5e6322f8b1e18e3abf825ddbbe9bb498616f0c058c5fb061 -dist/2025-02-18/rust-std-beta-i686-pc-windows-msvc.tar.gz=fecfb22d75b38e9c92c64790833c8ed8b4ea70c40d3d9c67a23277216c1246bb -dist/2025-02-18/rust-std-beta-i686-pc-windows-msvc.tar.xz=a592d638118b0b95e8ef0e174b94c1825d0e3a3aab87d03737eb7415d1b32076 -dist/2025-02-18/rust-std-beta-i686-unknown-freebsd.tar.gz=e8546b2f4fe5746706d2b0d56fe174ee5993bd61a9fe451fd233236d7af0feee -dist/2025-02-18/rust-std-beta-i686-unknown-freebsd.tar.xz=09efaf8f4f26ce6d466c1e20758901dc64348cdf390f4b878b4ee9542f50dbae -dist/2025-02-18/rust-std-beta-i686-unknown-linux-gnu.tar.gz=e173f1ac1662deba8c719965d5d4c77e711cc0eac732d933b6c8ac021a44de5c -dist/2025-02-18/rust-std-beta-i686-unknown-linux-gnu.tar.xz=600aa6b6ed1b49afdcc4978c897cd1e1f801193b804b0d1723319464c8378c88 -dist/2025-02-18/rust-std-beta-i686-unknown-linux-musl.tar.gz=38f7ee73e7067df2b98064b9f0ed00b8aa7c7eeae5955719fa0e2cf1f126ed19 -dist/2025-02-18/rust-std-beta-i686-unknown-linux-musl.tar.xz=6e639d9c45eda6b43ce0ce52e3213172df1875adfa0c13e52385b5aa9fa05da1 -dist/2025-02-18/rust-std-beta-i686-unknown-uefi.tar.gz=2ae2a44ad2610bbe3a97d176bbfd3e43efa22b5713c9591b9f3bcd7609f3a30b -dist/2025-02-18/rust-std-beta-i686-unknown-uefi.tar.xz=d8fcf03e16ce9ada0253a2f8899ee9193083e1638d9e0da6cc76886b6ee14c91 -dist/2025-02-18/rust-std-beta-loongarch64-unknown-linux-gnu.tar.gz=cb0f09f7d81b1e49a761a94396dcb4e999dbbea7d70e044785992da9a2aa38e2 -dist/2025-02-18/rust-std-beta-loongarch64-unknown-linux-gnu.tar.xz=1cecfc8d91f5f3cb7bc67f49795d5e2c74638df0f7d66a3051a851522dae2860 -dist/2025-02-18/rust-std-beta-loongarch64-unknown-linux-musl.tar.gz=0369af7a8b56dac39448a22f1ad27df42c72ccdcb43cb96e7eaecf0c0d8b94e2 -dist/2025-02-18/rust-std-beta-loongarch64-unknown-linux-musl.tar.xz=a395fd16ea741c72b39db5d398a46a90cae8531be620a3468d0dc13f8a9979f0 -dist/2025-02-18/rust-std-beta-loongarch64-unknown-none.tar.gz=e2ce2c57ad140b9088052009efae96ed04ce14c258cd954ee049dfc9146242a7 -dist/2025-02-18/rust-std-beta-loongarch64-unknown-none.tar.xz=a055dd6cc47dad744fe9343d100750ea013cbe3a5bf4fcdac54e80809352a6d3 -dist/2025-02-18/rust-std-beta-loongarch64-unknown-none-softfloat.tar.gz=26f8ba1c9594f7336ad530eef0076f2d30752d2edcf96d944cc962dde3d3caff -dist/2025-02-18/rust-std-beta-loongarch64-unknown-none-softfloat.tar.xz=32c80782a30c7bf300510e4fa29dad76d9a40bed2d5746c4d55b17fb261d788c -dist/2025-02-18/rust-std-beta-nvptx64-nvidia-cuda.tar.gz=2cd25291aa0c7610f10ab04cdf4ba4d214e0c684bed73d2ef31ae84af2da0eaf -dist/2025-02-18/rust-std-beta-nvptx64-nvidia-cuda.tar.xz=a7f02677a5c35388593142ef95cf56ffe1632df7fd42ff35bff89dafb34a0bdf -dist/2025-02-18/rust-std-beta-powerpc-unknown-linux-gnu.tar.gz=64ee7c6fb36ea45490911ae5557f6a051728a05a7c88b1476489be87456be4bb -dist/2025-02-18/rust-std-beta-powerpc-unknown-linux-gnu.tar.xz=250993b5a1915a8970d91f7a10f3f50c907cc9508d71d3b2c8e20914f90254a6 -dist/2025-02-18/rust-std-beta-powerpc64-unknown-linux-gnu.tar.gz=deb267998a725fb0288432a51aeac3004d6430fce8683c91d102b6708e5b99ea -dist/2025-02-18/rust-std-beta-powerpc64-unknown-linux-gnu.tar.xz=49ba80f0a2970948699b78fc60ac09f77dda94e56931399c57c2c81fce8df9e4 -dist/2025-02-18/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.gz=06ff5073e946ed2a5f80f9a5befd7b0c27e9a959cebf26b6cefc5762a0fcdb03 -dist/2025-02-18/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.xz=27f12f5835f564b03f55d85121c9474b9fc93d3084c5b5d0fc63d33c8c9dcc64 -dist/2025-02-18/rust-std-beta-powerpc64le-unknown-linux-musl.tar.gz=78aff087bbef054b5a6a8d2a1649dd59f69b7f98635eb0c130c4ba87b3018850 -dist/2025-02-18/rust-std-beta-powerpc64le-unknown-linux-musl.tar.xz=e82b6bdfed001c91f8f88f6c37e31ef35f2f25cdca6fe8adfd90d024cc068e15 -dist/2025-02-18/rust-std-beta-riscv32i-unknown-none-elf.tar.gz=8dd6fdb684882ce4087bb96ec2d982c0d808c93c053c774b49cfc705959b4309 -dist/2025-02-18/rust-std-beta-riscv32i-unknown-none-elf.tar.xz=4d6db36241c3d8735e7c2ee84a37ae0cfbc2fc79c6fd259ca4b74e7edb68b8f0 -dist/2025-02-18/rust-std-beta-riscv32im-unknown-none-elf.tar.gz=32e8a2eb316b2a82f80e7268a318df89f732d7cbaba779debe10664aec7d40de -dist/2025-02-18/rust-std-beta-riscv32im-unknown-none-elf.tar.xz=562030f1bdc1307bc0261a2e66c12a6f21fed0ed21fdb2140b1b1d55664aab00 -dist/2025-02-18/rust-std-beta-riscv32imac-unknown-none-elf.tar.gz=52e8c7ab87f5d2cbb712fb54ad8394b50a7f95961e1a7e5ffce981a962899a2c -dist/2025-02-18/rust-std-beta-riscv32imac-unknown-none-elf.tar.xz=74f13bf5f0ff428c323c3041771b653d3ccf5a999105869378bf09a6ce6ca040 -dist/2025-02-18/rust-std-beta-riscv32imafc-unknown-none-elf.tar.gz=e2b8a784b4c6826d00a69de8e1891a40619f4b17c6e54c5cbed349fedefbd8f1 -dist/2025-02-18/rust-std-beta-riscv32imafc-unknown-none-elf.tar.xz=a231848519003a9ea1306a7da2139675516c0d94e5cbd8af140bb1a37515d7fa -dist/2025-02-18/rust-std-beta-riscv32imc-unknown-none-elf.tar.gz=82d33d6527db7adaff8bec04c6edb4f3f7a1609fb5e5a91011a3b48dd47af93e -dist/2025-02-18/rust-std-beta-riscv32imc-unknown-none-elf.tar.xz=bfe440ce80c4547afef2c6b8379bccde9f7206a5406c5a7ed5c06ab460ad8ba1 -dist/2025-02-18/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.gz=728c559f432bf8487c345967a2ebc9e4eada676a6d56a68ec32d26ee9775857e -dist/2025-02-18/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.xz=51e7990ff209c27a15d40a684d634e5cad26d55913b897c2be6d92fcb849b7d8 -dist/2025-02-18/rust-std-beta-riscv64gc-unknown-linux-musl.tar.gz=ea66ba0e6af1fc7ce741c0838bc005abc04c6ad85c6831d2e05d04f30066281b -dist/2025-02-18/rust-std-beta-riscv64gc-unknown-linux-musl.tar.xz=7429a295ccda168e41e9717647ba4639eceb81a73d66ad7ba01c9e7f1ca19c03 -dist/2025-02-18/rust-std-beta-riscv64gc-unknown-none-elf.tar.gz=01824c3ca49cfb433de4508282f0395bae8053866691869fb804a3058a403b02 -dist/2025-02-18/rust-std-beta-riscv64gc-unknown-none-elf.tar.xz=67e324c82c6a5c9fd279b9bf5ebabaecf35374c741e5728c2db3fbbb6eab1fd9 -dist/2025-02-18/rust-std-beta-riscv64imac-unknown-none-elf.tar.gz=466d4e5c1912937481fbd22d739987d663f3c771ff0efd676b34fc34e9266f87 -dist/2025-02-18/rust-std-beta-riscv64imac-unknown-none-elf.tar.xz=409c2870098222c09abcb1c89c7394633222bef2cba9756638e8cad058e3c524 -dist/2025-02-18/rust-std-beta-s390x-unknown-linux-gnu.tar.gz=b31e3389756f78bf680982d6c6415c3712567e5050beddae10d2df52de560e61 -dist/2025-02-18/rust-std-beta-s390x-unknown-linux-gnu.tar.xz=729b7433746947b88b8d4f488e2831bff1a92911b8c25f16a1208542e38d5834 -dist/2025-02-18/rust-std-beta-sparc64-unknown-linux-gnu.tar.gz=56caed9608e88e9ed6dec56ec3265d6464633ed57b14a455c626983defc87411 -dist/2025-02-18/rust-std-beta-sparc64-unknown-linux-gnu.tar.xz=9c9d16cac691185cf055117d6888a25f14c72cd110e3bc699c6e78b5d0dc70d8 -dist/2025-02-18/rust-std-beta-sparcv9-sun-solaris.tar.gz=6963215ffa1d2cf9650db8bc36f1eb5c97fb4d824a010c2a65f842fa00b4b4c0 -dist/2025-02-18/rust-std-beta-sparcv9-sun-solaris.tar.xz=9077823bd323a251347336f3c656c6847d5fefb90efed0cacadd510f42afbb74 -dist/2025-02-18/rust-std-beta-thumbv6m-none-eabi.tar.gz=f6d1b17e822403428a6ddf254caf78c75c2d91c208e035590779b51d45b7e081 -dist/2025-02-18/rust-std-beta-thumbv6m-none-eabi.tar.xz=1eb4e8ca0d8a52ddf754aec64b70e7a1f91d2746eef7e3c6d4580a0794cbfae3 -dist/2025-02-18/rust-std-beta-thumbv7em-none-eabi.tar.gz=7793950c2a0016ae90ee8fb70e881047a1f85c82f087fb02532009d6419ba6a8 -dist/2025-02-18/rust-std-beta-thumbv7em-none-eabi.tar.xz=14464141719b2b2c5d4a4b29685f3a2e336c2542ea33af01cfaec2ed7511baba -dist/2025-02-18/rust-std-beta-thumbv7em-none-eabihf.tar.gz=62612b4da1872950af31bf3d9f0a595f019e6c4074874f4cdfa9166c5ff39434 -dist/2025-02-18/rust-std-beta-thumbv7em-none-eabihf.tar.xz=07ab29714f76693f69273a5567408307186b272061501a9ac83eebe944f66d31 -dist/2025-02-18/rust-std-beta-thumbv7m-none-eabi.tar.gz=b2da60ea5d746b607c505279b84aa2a8f3bac3e258ca867f6aeca958e50691c8 -dist/2025-02-18/rust-std-beta-thumbv7m-none-eabi.tar.xz=3eee9280fdd35f30ee9b4a2e5d8614ee916f36cd08629a574f6450721a1fe05b -dist/2025-02-18/rust-std-beta-thumbv7neon-linux-androideabi.tar.gz=c5be169574de4fcd550b67d19834e064b81084e673764390b9f177631f3fb0ed -dist/2025-02-18/rust-std-beta-thumbv7neon-linux-androideabi.tar.xz=bcd6ddf6493cbe17236a74c26da7e16a9a752fd39ab453866ae3301cff0c8375 -dist/2025-02-18/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.gz=e52c2e8272a9ff9442ae6bafb7526cac424d15d4d6d1d8d210fe981b42da9b73 -dist/2025-02-18/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.xz=81adef669c6f8f08b941b0befc6af30eb78b2717c3aacd52a1526d9545548c53 -dist/2025-02-18/rust-std-beta-thumbv8m.base-none-eabi.tar.gz=1036f47867b7d29ae468a040c50da016e20a6a3a291714df4193895234591c00 -dist/2025-02-18/rust-std-beta-thumbv8m.base-none-eabi.tar.xz=508b4f1e307d0b033eab345ab5106eb83ad8dad212f491f1ba92b9680f699bc6 -dist/2025-02-18/rust-std-beta-thumbv8m.main-none-eabi.tar.gz=41c806851db8e59dc9ad8a756c8efde7dc14e8ef5dc4feb81be9351d267b6157 -dist/2025-02-18/rust-std-beta-thumbv8m.main-none-eabi.tar.xz=f3bb9c783f4350e491fd683d057521f497314e85576b26808f4edc7d1d8612c6 -dist/2025-02-18/rust-std-beta-thumbv8m.main-none-eabihf.tar.gz=36a3e0675cc972fe6f4f860da47c9d4e0ac175191622c651fbb002207506b627 -dist/2025-02-18/rust-std-beta-thumbv8m.main-none-eabihf.tar.xz=c3287e3ebd4583a576f4bbdcfaa77fc21f6165b18573cbfdeb28593494ec14dc -dist/2025-02-18/rust-std-beta-wasm32-unknown-emscripten.tar.gz=4a7128b50478a05d4fdad69715a0a7c9dcc745aab33cbc2e137cb670c6265001 -dist/2025-02-18/rust-std-beta-wasm32-unknown-emscripten.tar.xz=6e3b5981cca095c2414ad4d23f3e69a942a12c1d51dc9e055ad8409c5edbdcf9 -dist/2025-02-18/rust-std-beta-wasm32-unknown-unknown.tar.gz=3b0cbbb35daf13711e8f211da8e2ed4ade96f728be5e5ad3ca02e4d3e32b7262 -dist/2025-02-18/rust-std-beta-wasm32-unknown-unknown.tar.xz=4e50db69d0917f205a16fa3c4ee5e4012c000194ff75641ddeb49bbec9a2ec49 -dist/2025-02-18/rust-std-beta-wasm32-wasip1.tar.gz=d382d7f9787018480329518035fc4ce3247775633423e0f2940c3670cbdd4705 -dist/2025-02-18/rust-std-beta-wasm32-wasip1.tar.xz=e1d9c800db62bf606d9be9a75dd00ac7190acf3fd3592cbdeba67170ddb092aa -dist/2025-02-18/rust-std-beta-wasm32-wasip1-threads.tar.gz=cc7cd664a483eace96710d341132de4f9cf2113f358722425ddcf84cfe821116 -dist/2025-02-18/rust-std-beta-wasm32-wasip1-threads.tar.xz=17156e3e57e304ab3ab10f8191a9952400182d2a46ebcd39d1cfde97b94c0756 -dist/2025-02-18/rust-std-beta-wasm32-wasip2.tar.gz=7ab89b39693bd1bc3f344dce6ad1c127ef38f64591c7be769d07603b2422800d -dist/2025-02-18/rust-std-beta-wasm32-wasip2.tar.xz=2f53c60d0c0388ff644c17e341368e8b15d4c41b2827b03507d4efee100a1841 -dist/2025-02-18/rust-std-beta-wasm32v1-none.tar.gz=3277ec65149e708925ca7fc062cde92953d01569d2700d2831e6ff68768e5b30 -dist/2025-02-18/rust-std-beta-wasm32v1-none.tar.xz=24df037c2c4bcb3d593033d93b6e26aa1dc38161452220d7a73a23a696dc93bc -dist/2025-02-18/rust-std-beta-x86_64-apple-darwin.tar.gz=3878e1506ee4642fdd1bd5e10025c9c289f8d03b7cea876d2348fabc2675b721 -dist/2025-02-18/rust-std-beta-x86_64-apple-darwin.tar.xz=46bdd522559b61848cfcbc8c55d95b190a134f2a0ac19e3c7ebfaea867f9780b -dist/2025-02-18/rust-std-beta-x86_64-apple-ios.tar.gz=e914a0a4a2824f12764b0b91b0dd97a25416686839f35dea2aabde41c011f850 -dist/2025-02-18/rust-std-beta-x86_64-apple-ios.tar.xz=b44ac0cc8cab86ba9d000d2164786b5bdc115ace7990ead57aaba2b0e02750aa -dist/2025-02-18/rust-std-beta-x86_64-apple-ios-macabi.tar.gz=497c75ec8b5f99a625d898b406d437b8902b8ad42ee1d629a0efd27cfee96e44 -dist/2025-02-18/rust-std-beta-x86_64-apple-ios-macabi.tar.xz=a53ed7bfd16d62a7f51509d32fb6cc6b1f3af331f4c4867cbc1eb57da5c3d521 -dist/2025-02-18/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.gz=3cec5b6714f156e43c85b4b15377475bc38f65325f61de020bddfc2708b25a7b -dist/2025-02-18/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.xz=ea2cc73a03644647dec905100154a3238dd819fd0421f770dbc433cd6dc49f33 -dist/2025-02-18/rust-std-beta-x86_64-linux-android.tar.gz=2eaebfe572503b69e34674ed414357c514bcfbf013e6a2a7bb3fb14f501872e8 -dist/2025-02-18/rust-std-beta-x86_64-linux-android.tar.xz=66c4f03b907515831f9a48c8f5036d4c3115e814507a27abe1e423ef4a7e7c0b -dist/2025-02-18/rust-std-beta-x86_64-pc-solaris.tar.gz=4c8f54f1709908a9edabd9e60d8492cda771db4b51fe766f2a2323a10f184e1e -dist/2025-02-18/rust-std-beta-x86_64-pc-solaris.tar.xz=60d74169e80b3e1297b010501fa5a46a29a7541c84ceeff304b4c2ace7631540 -dist/2025-02-18/rust-std-beta-x86_64-pc-windows-gnu.tar.gz=9d043fbcd7e180052b903180114d50c71a2ccbeb22fff7020514b4b0a11a8123 -dist/2025-02-18/rust-std-beta-x86_64-pc-windows-gnu.tar.xz=f08905c0b8192f23f214465d757d93e30aee0250dda279d648e948961e0745ca -dist/2025-02-18/rust-std-beta-x86_64-pc-windows-gnullvm.tar.gz=e35a42a9a6eccc4b738b389fdff24ba01ef23ff8d00fbd34100acafffb9c3763 -dist/2025-02-18/rust-std-beta-x86_64-pc-windows-gnullvm.tar.xz=a1fd2d1b1bb1fe9593df7835b5fb81e5c9453c0bbbc17b9ee5deb0512ad12550 -dist/2025-02-18/rust-std-beta-x86_64-pc-windows-msvc.tar.gz=feada263ce77cd0ec635ae78c8ce34099385a1f89d1eb680576a85a8adf0d75e -dist/2025-02-18/rust-std-beta-x86_64-pc-windows-msvc.tar.xz=ee8def01984eba376773f7a055a18a4096750d26f96ab9150326dc60ece9fbe5 -dist/2025-02-18/rust-std-beta-x86_64-unknown-freebsd.tar.gz=7791a0155a0a3464d07b176383a4b61dcfaef4bf0247c58d447402fac3123186 -dist/2025-02-18/rust-std-beta-x86_64-unknown-freebsd.tar.xz=11bae401884cce0306b415bb1202c2c63f81395677057fbbe12e9302951a9d3d -dist/2025-02-18/rust-std-beta-x86_64-unknown-fuchsia.tar.gz=4d05cd943f4e4250d50a5f732a64f32431a6cfef59b38bc087b1dbe1aa4b9561 -dist/2025-02-18/rust-std-beta-x86_64-unknown-fuchsia.tar.xz=7bdc7161d66b6c330f027f53b15f164c9ad4d55debe77b7c34971a877bf82caa -dist/2025-02-18/rust-std-beta-x86_64-unknown-illumos.tar.gz=01edf8fdab00df25cfea2ade367dc4f66a1d08d11bfd9a7e56b65a723e14b517 -dist/2025-02-18/rust-std-beta-x86_64-unknown-illumos.tar.xz=9efccf8ba6fc68997123924cddd7008b15f1a57170d03597a370346fdc6c83d6 -dist/2025-02-18/rust-std-beta-x86_64-unknown-linux-gnu.tar.gz=9dbfabe77853e672d576e70332e07727882cd6af14dee9a00d5186b43763ce82 -dist/2025-02-18/rust-std-beta-x86_64-unknown-linux-gnu.tar.xz=04e31482a3ff18d8fdff40c4e95b22bc667bc0dd1ba06fadbe2479bae5d97288 -dist/2025-02-18/rust-std-beta-x86_64-unknown-linux-gnux32.tar.gz=ebb6e0c56d905ef064fa15449a72746daa9e3998f5aba5c6a3c132bc676228cd -dist/2025-02-18/rust-std-beta-x86_64-unknown-linux-gnux32.tar.xz=818fc179c8380f0fb70c46e04086926a69b026591ab62cfbc1051abc5c80012a -dist/2025-02-18/rust-std-beta-x86_64-unknown-linux-musl.tar.gz=c0a1c692a334821d61a9b92cd1332f047175d4335336db3e2129687ba96ce5bc -dist/2025-02-18/rust-std-beta-x86_64-unknown-linux-musl.tar.xz=2c71b87db4cec49e3c620e6b4e0e07f1aaaffe69020b07c87546232ed1ad3b20 -dist/2025-02-18/rust-std-beta-x86_64-unknown-linux-ohos.tar.gz=c1bbf445dd0b187904af5871bf48a720151ef75fdd3dd13161dad01ef5e87bbc -dist/2025-02-18/rust-std-beta-x86_64-unknown-linux-ohos.tar.xz=19963165ec2c35c15024869c16a707bdc90e72032ebf6e203cc67411ec8ba7c7 -dist/2025-02-18/rust-std-beta-x86_64-unknown-netbsd.tar.gz=63fbbd51047125fe30f1954ea19a05d6f051d2a77929952bab326c8ded6db8d3 -dist/2025-02-18/rust-std-beta-x86_64-unknown-netbsd.tar.xz=1c255d1de9c2629210575b862600bf369499a0eb8873178ceff4a337ba9dccfe -dist/2025-02-18/rust-std-beta-x86_64-unknown-none.tar.gz=781f14a54c5e68acde1e68042905a48f687294e2bc61450f422a6e15bf6ab509 -dist/2025-02-18/rust-std-beta-x86_64-unknown-none.tar.xz=d45921b98740f3cce5833bc4fb1e36816f34b81e96c3ca2c76deff4744134c6c -dist/2025-02-18/rust-std-beta-x86_64-unknown-redox.tar.gz=0cd76d3c5b051b0b2015cb08079ea3b5ecbb9b0b68779eb35946721b24c07008 -dist/2025-02-18/rust-std-beta-x86_64-unknown-redox.tar.xz=6dec719cdb7f35f6eafd901414525b40f030566bdf3fb55e3b05de162dbf0741 -dist/2025-02-18/rust-std-beta-x86_64-unknown-uefi.tar.gz=aad1e2cfd4f428acb67d9dac1fab4450eccfe9212f52f99f06c09899285b6b1e -dist/2025-02-18/rust-std-beta-x86_64-unknown-uefi.tar.xz=4252b618ffc906949756ad28a5437d11b0353fe1d755ee1d23502a208bdee74c -dist/2025-02-18/cargo-beta-aarch64-apple-darwin.tar.gz=2f7f459d2595d3f60bcef4ccbd3c72095a3ec54fa3f2221a647ae892c308d5b2 -dist/2025-02-18/cargo-beta-aarch64-apple-darwin.tar.xz=501feb9138f3c11a13fd649d6573924ead10f5e6fb1e759d880684bff11c12be -dist/2025-02-18/cargo-beta-aarch64-pc-windows-msvc.tar.gz=b589177b0287a42ce17939dbbee92d883dfec88ebad33bf9a719a3cb2f446533 -dist/2025-02-18/cargo-beta-aarch64-pc-windows-msvc.tar.xz=d795082d304ecdde233a4b6bb3aa558392b2c5a1553fab213ee99648c49f7a51 -dist/2025-02-18/cargo-beta-aarch64-unknown-linux-gnu.tar.gz=8444d938514ad2d55769cf614774dfb4e5a27c34f8ba8b49329a2bcf0b000162 -dist/2025-02-18/cargo-beta-aarch64-unknown-linux-gnu.tar.xz=02e52fc13ae52066031ac40dad039ad752b83582e5f9e74ecef206aa9206ac16 -dist/2025-02-18/cargo-beta-aarch64-unknown-linux-musl.tar.gz=e89709bb552e7ee73de02b08c6d8820b07bccdc09777eff9716efabb2bdd50cd -dist/2025-02-18/cargo-beta-aarch64-unknown-linux-musl.tar.xz=50944f0e51190f9db065764afc7a41a3a1e39767bd1ef5ec659c98fe9243cc98 -dist/2025-02-18/cargo-beta-arm-unknown-linux-gnueabi.tar.gz=0343dfc2f015d476b3aca59b33dd75f907f595bc24715e6c518194ab1a5dfec1 -dist/2025-02-18/cargo-beta-arm-unknown-linux-gnueabi.tar.xz=3dd6c378c10172b1abfdd1db2fa764d1b48153ac1b5065cf124399941d036e56 -dist/2025-02-18/cargo-beta-arm-unknown-linux-gnueabihf.tar.gz=6eac5ffb9adaf2591d3b1872249f4a959c04afdf6694e62dc850936aa8d35972 -dist/2025-02-18/cargo-beta-arm-unknown-linux-gnueabihf.tar.xz=484510e6b9519c2b047864584253c8c1f725ce843e8dd3117349032314737462 -dist/2025-02-18/cargo-beta-armv7-unknown-linux-gnueabihf.tar.gz=fcf4d4b2d401ea689ee32f38b4a61c77b52ff4d3d114b23d0262bd02c3d1ab5d -dist/2025-02-18/cargo-beta-armv7-unknown-linux-gnueabihf.tar.xz=1a75296c42d6cf93a5e51ecb2b2bfbf0cdea350668d610e8b0c90937163b4f33 -dist/2025-02-18/cargo-beta-i686-pc-windows-gnu.tar.gz=d1b5147ec79466ab9441825b4761e89cebe57ad21a3199b0eca0779683c45ed6 -dist/2025-02-18/cargo-beta-i686-pc-windows-gnu.tar.xz=980850e06ccd90512baebbfe3baaa65b5c089edbae8146fd940c708fd7556abc -dist/2025-02-18/cargo-beta-i686-pc-windows-msvc.tar.gz=78c67ba481cc7b855b54a2edc0297bfb5eadcd83d5a028b05291415417bc6947 -dist/2025-02-18/cargo-beta-i686-pc-windows-msvc.tar.xz=6ea74c750e6e0a794965c6616e5b1a82dee295815b0c24a3898952b1a5a02c8a -dist/2025-02-18/cargo-beta-i686-unknown-linux-gnu.tar.gz=a0c8f67fe77b94674698b4816c081e2ef08500990c0f9eb069d0190df9c4f129 -dist/2025-02-18/cargo-beta-i686-unknown-linux-gnu.tar.xz=9b13f958ec4edff194858e90c54866a129e88769a76fe22582b07e17540708c3 -dist/2025-02-18/cargo-beta-loongarch64-unknown-linux-gnu.tar.gz=f4d2f1c8a7bec6d2b8378aa87a324c42f0f414962174b40b6f0d1dc21d0cacf4 -dist/2025-02-18/cargo-beta-loongarch64-unknown-linux-gnu.tar.xz=f25659ef3be1a28da8821eb178e02108f41cd5c0b87aa01a052a3a90e7a9da50 -dist/2025-02-18/cargo-beta-loongarch64-unknown-linux-musl.tar.gz=b687a7c3fac08680818804e034af6689f1bbcf8fc0e406c99b2a49ddae1e900d -dist/2025-02-18/cargo-beta-loongarch64-unknown-linux-musl.tar.xz=e33818d2f94e8ba148dbf8cd53d6396e370157acba6d0865a5ac71d292939a0a -dist/2025-02-18/cargo-beta-powerpc-unknown-linux-gnu.tar.gz=9cdc2115bd2022cb0b0ac4f1c71142c064957137decc028dde7585acabb8b780 -dist/2025-02-18/cargo-beta-powerpc-unknown-linux-gnu.tar.xz=f722447494f0a7af9c31b71364aa4a2fde79a9887440d8281e4561f7d71620d3 -dist/2025-02-18/cargo-beta-powerpc64-unknown-linux-gnu.tar.gz=d8a30f9e48e89cb1d18532fd7fbef8eeceef6bc602ffaf9e730c635e2fdbb156 -dist/2025-02-18/cargo-beta-powerpc64-unknown-linux-gnu.tar.xz=ec6b3b1595c5761b8092a04a412e79534c28910ed78ed792c9af7ddc4d92a389 -dist/2025-02-18/cargo-beta-powerpc64le-unknown-linux-gnu.tar.gz=4bf9c73173199fd3ca952d33702288deb483c7fd392179352135b64e7e8fadb4 -dist/2025-02-18/cargo-beta-powerpc64le-unknown-linux-gnu.tar.xz=12aa06644e07344a77d0c16dc1ed96bfba63de02df1f432d57b82f8a1e2282b6 -dist/2025-02-18/cargo-beta-powerpc64le-unknown-linux-musl.tar.gz=eab362146d449dcdd10740c8e6f9dec6e640ffcca162eb51febbc835e34acdfd -dist/2025-02-18/cargo-beta-powerpc64le-unknown-linux-musl.tar.xz=867b716eae9225c66c0ab4642e4e497055ad2effd24343bdf80354ce2845d6f9 -dist/2025-02-18/cargo-beta-riscv64gc-unknown-linux-gnu.tar.gz=0503ba2e4b1d668fa3a3174f96ec3fcc12ff767574a7af8ef5fc824ca86dc965 -dist/2025-02-18/cargo-beta-riscv64gc-unknown-linux-gnu.tar.xz=478b9f1d4f517f93f15530d27a7d55ea29cdd06eccf01176ffd08c0ee3204c1f -dist/2025-02-18/cargo-beta-s390x-unknown-linux-gnu.tar.gz=419a679aaf6e164649538916daf28081a063bd56c7b86ff0e2df58072f334fdc -dist/2025-02-18/cargo-beta-s390x-unknown-linux-gnu.tar.xz=31b39e242035036c1101412b7c86387e1183063ff5f6ce67d311d0764435a588 -dist/2025-02-18/cargo-beta-x86_64-apple-darwin.tar.gz=d6d5224228dd54b6d16be30271111620c02fd88e656b8bbd22452b66b0d5cb56 -dist/2025-02-18/cargo-beta-x86_64-apple-darwin.tar.xz=cbeff7c031b4ab4732207b90ee8849b27f03cb28d3e085bf4d70444347dbfc99 -dist/2025-02-18/cargo-beta-x86_64-pc-windows-gnu.tar.gz=ae5922955ec579732aacd8112bc53bf5333438eb81d0f81dc5f387888ac979a3 -dist/2025-02-18/cargo-beta-x86_64-pc-windows-gnu.tar.xz=553c55a2bc8eae2c8ba831823a97f2232808af1f753642ec4cdd09c33dd3f6ae -dist/2025-02-18/cargo-beta-x86_64-pc-windows-msvc.tar.gz=d9b2cf14565478429fba6266f0c86a58f3bbd1ce11a63268828b33ccb55759cf -dist/2025-02-18/cargo-beta-x86_64-pc-windows-msvc.tar.xz=2e8c0560355d11a038219072d2503860f5c5b3cd137b89ad931f54d9bba60499 -dist/2025-02-18/cargo-beta-x86_64-unknown-freebsd.tar.gz=4b528361607845e6f8ece403bbdb8d77c6159ec137396319562ea2772502792f -dist/2025-02-18/cargo-beta-x86_64-unknown-freebsd.tar.xz=c244ec4f97420c29c690e32bd6d8f14994bf1d990747f31a3dc0f2b37644493e -dist/2025-02-18/cargo-beta-x86_64-unknown-illumos.tar.gz=7d3b49df93e87322a9e99e36c6df020d3311c5538ad2298d8b5d8f2d9ad3e0d3 -dist/2025-02-18/cargo-beta-x86_64-unknown-illumos.tar.xz=136ce90487448ee770472d4bd2c0d9c96200f0ec762419feb42fefa26ba36b58 -dist/2025-02-18/cargo-beta-x86_64-unknown-linux-gnu.tar.gz=510538965ea142405925d3f4f03a87783516407989b8aa7be07fb84c0680e9fa -dist/2025-02-18/cargo-beta-x86_64-unknown-linux-gnu.tar.xz=a8c569398d71cab0b90c809b1d869a2e3c5037407b5af804df08c205775981c2 -dist/2025-02-18/cargo-beta-x86_64-unknown-linux-musl.tar.gz=1493f66e5cb12e8b955841804e7df745e26daea2278144aa57670192c4c62cef -dist/2025-02-18/cargo-beta-x86_64-unknown-linux-musl.tar.xz=472bbe49415557b75b572879d0c33750731c1fe9e56cc6ef3b0fd5532e56446c -dist/2025-02-18/cargo-beta-x86_64-unknown-netbsd.tar.gz=d3baa6019e13449c01fbeebebce42027ce4ba70841cf28733f6849e7c6ce5d89 -dist/2025-02-18/cargo-beta-x86_64-unknown-netbsd.tar.xz=0db9af42e9ad914a99db4924721c895cdf490bc5351bc8c2d8993e3569e952e4 -dist/2025-02-18/clippy-beta-aarch64-apple-darwin.tar.gz=6ce3b464744082131c99a213454225e5702564c83032e11dd0f3d95530a4e0af -dist/2025-02-18/clippy-beta-aarch64-apple-darwin.tar.xz=925baff0d91b959a99c989a4ada70973baf3da03e1d7e7e8be1fa334c3acbc50 -dist/2025-02-18/clippy-beta-aarch64-pc-windows-msvc.tar.gz=76d265c2fb6280eb8ed399501964f301a50e09e548cee708ebacc978d8db538c -dist/2025-02-18/clippy-beta-aarch64-pc-windows-msvc.tar.xz=e3d1d69cbc838ab639b2e41537b10266f1b6998a228882d4041f35cbb8984909 -dist/2025-02-18/clippy-beta-aarch64-unknown-linux-gnu.tar.gz=918191cad727d795b51f892abb6e4fc87ed735bfcb51433cfb4371cb8be8690c -dist/2025-02-18/clippy-beta-aarch64-unknown-linux-gnu.tar.xz=157d6eb9e7dd80dda7daae5584d095a5e68d13ba8b1d1229e90b5b51f6670e8d -dist/2025-02-18/clippy-beta-aarch64-unknown-linux-musl.tar.gz=fd4de290450e3d3c9188263d9506167e298f4c2d4c781fb3573806694b5ca1ba -dist/2025-02-18/clippy-beta-aarch64-unknown-linux-musl.tar.xz=335c5fd24d1c118e4d1d8abc43d3529dafc9b30af39f6b009924cd0fea676182 -dist/2025-02-18/clippy-beta-arm-unknown-linux-gnueabi.tar.gz=209cdd2042e293d1061b149d97333515821dda0ffeb9b30f24dd2dbb4c1ad548 -dist/2025-02-18/clippy-beta-arm-unknown-linux-gnueabi.tar.xz=57dbfdc34ff4e74aaa8776b80d35aaf0317fdc314ee4b0f3bf58fc672963cf38 -dist/2025-02-18/clippy-beta-arm-unknown-linux-gnueabihf.tar.gz=a89a2562fe9ac6492a5de220c395f433b0e53a8b29c72b3a8d4843f996649ca6 -dist/2025-02-18/clippy-beta-arm-unknown-linux-gnueabihf.tar.xz=0e6ff6453df1397e7b12e7e356e7c7300cfb1f85bc3a6705735067128d2a8135 -dist/2025-02-18/clippy-beta-armv7-unknown-linux-gnueabihf.tar.gz=7764c2dbaf217f4b1d8ca4ed2ceaacbb91e8010d26ae1bb10b808afd5dc6a798 -dist/2025-02-18/clippy-beta-armv7-unknown-linux-gnueabihf.tar.xz=b7a042eb6830653a623c6299ef57492ae6c9b51a9cd8480f0a6fc2fb6d378bbb -dist/2025-02-18/clippy-beta-i686-pc-windows-gnu.tar.gz=ff41e5b666b3531ccdc0ee836dceb270179d6a849e47024eedc6ea309d36791a -dist/2025-02-18/clippy-beta-i686-pc-windows-gnu.tar.xz=98c6386b63ed89dd96beea223f4c720320b6ca460f11b77c46427e128034cbbb -dist/2025-02-18/clippy-beta-i686-pc-windows-msvc.tar.gz=12bd371402e4d3251f60fa29b3b3aca88b4480229088b68791dffbb4ae1554ce -dist/2025-02-18/clippy-beta-i686-pc-windows-msvc.tar.xz=62a22d1e9b4fdba254e549f5edb276bef5252754ba67a76526d5aeca85515646 -dist/2025-02-18/clippy-beta-i686-unknown-linux-gnu.tar.gz=04179b3a20a68ae2fd8444832ea4edd8155dc9296c7a1edf101053e3ff934891 -dist/2025-02-18/clippy-beta-i686-unknown-linux-gnu.tar.xz=c955e464e99097025fc7d0e42bf90342f74f475c5148526df2f51ca46ce8db4d -dist/2025-02-18/clippy-beta-loongarch64-unknown-linux-gnu.tar.gz=6f58d326a1f2a35246384640b999f95a961a9fe1e5a3c4a3e67d7f96e1ef43fb -dist/2025-02-18/clippy-beta-loongarch64-unknown-linux-gnu.tar.xz=583b1d55a38fdd473a3f3f3cc0fbeac808fbeb593b8b45c7a6b8a09dec0d68cf -dist/2025-02-18/clippy-beta-loongarch64-unknown-linux-musl.tar.gz=80d73fe94ecbbcdb14b35e1616d52e0bb9b1f04dcdd4fc384e7103cc36325014 -dist/2025-02-18/clippy-beta-loongarch64-unknown-linux-musl.tar.xz=1bae908e4d3931eb4dc71ac1524f990bbccaadd9d30897bf516899baebd4c5d5 -dist/2025-02-18/clippy-beta-powerpc-unknown-linux-gnu.tar.gz=b882e7ea97e0d36b289a46ef84b14b2b44ccea93ebdc77b2ab3430361ad15b1f -dist/2025-02-18/clippy-beta-powerpc-unknown-linux-gnu.tar.xz=91e52dc398dccbafd040e401f155c204f2a14d5f62aecfc24912910d5e45008d -dist/2025-02-18/clippy-beta-powerpc64-unknown-linux-gnu.tar.gz=c81497f2b2d2670b9dea2e35804e10780c1631a8761d4bc3331767c1ccaad6b9 -dist/2025-02-18/clippy-beta-powerpc64-unknown-linux-gnu.tar.xz=6236e129f3e551a3126fa07662cc8ad512ad5fcf436a8da9e27a915ad4c234cf -dist/2025-02-18/clippy-beta-powerpc64le-unknown-linux-gnu.tar.gz=1b031f055ea4ab4a9da0c8bfb0037e92b493caf7879351f8b404a96c447ec92c -dist/2025-02-18/clippy-beta-powerpc64le-unknown-linux-gnu.tar.xz=2f07224e49f7cab10d673116d9dee9f964b4c44ac3db336e7ddbab9e0b1bc698 -dist/2025-02-18/clippy-beta-powerpc64le-unknown-linux-musl.tar.gz=84a8295a7066d258404c87d2269a01d89cc7efd0f143ab53689597f3fb351417 -dist/2025-02-18/clippy-beta-powerpc64le-unknown-linux-musl.tar.xz=019460a6b0e1c5c1331d5a54f3e45306ba0d1b1c2206e2e69f38c1c3501cf741 -dist/2025-02-18/clippy-beta-riscv64gc-unknown-linux-gnu.tar.gz=aba8f7bd0a89205961f9803418cdf9bb63a7d72bab4a1ff937f4a142921f4833 -dist/2025-02-18/clippy-beta-riscv64gc-unknown-linux-gnu.tar.xz=4607503ba131ca655dab86ad48c1737f216f8ec25ba6dfddbf1f0807e5a6dd2a -dist/2025-02-18/clippy-beta-s390x-unknown-linux-gnu.tar.gz=b0170f9b9e13d4f6e016124fd40c858e00155479fb4f96c1edc896130bb76dcd -dist/2025-02-18/clippy-beta-s390x-unknown-linux-gnu.tar.xz=397f0a8944beffb87c74717bd0f422836b3daccfa848d91c0a65875031bf12fa -dist/2025-02-18/clippy-beta-x86_64-apple-darwin.tar.gz=11be90b9b09f4e24e56df2a602ed8161023314514121d9f76e424fb628df468c -dist/2025-02-18/clippy-beta-x86_64-apple-darwin.tar.xz=16d313798f12d0e74f888b627e079606958de58eb2ca4c70d5f7de8cce72620c -dist/2025-02-18/clippy-beta-x86_64-pc-windows-gnu.tar.gz=41ed081e4a7b205cde3fe958db18ffe1c1ac5a9c336f965a03fe89499a3eddbd -dist/2025-02-18/clippy-beta-x86_64-pc-windows-gnu.tar.xz=daaa3267dcbb3daa0cae47861683f29da5b7419214ec5949e242aa93e3f87148 -dist/2025-02-18/clippy-beta-x86_64-pc-windows-msvc.tar.gz=6d9b8f549e34d8fb65987b39c01c27fbb0e18e8950a07ec6fd1888d01e253971 -dist/2025-02-18/clippy-beta-x86_64-pc-windows-msvc.tar.xz=1c26b51c484f5b10ee693212e258fb86c63a2b59e631542918799d480a3587d4 -dist/2025-02-18/clippy-beta-x86_64-unknown-freebsd.tar.gz=a42777c542773a4262ac9fcb07ed13f769957f58a795160441241ad4e4f5258a -dist/2025-02-18/clippy-beta-x86_64-unknown-freebsd.tar.xz=9e809fa141ac68557f203aec2a6cc02a4ddd22169595c40ed4a964801ccadb1d -dist/2025-02-18/clippy-beta-x86_64-unknown-illumos.tar.gz=4e65b5db249a18e73247029506f619393be7042f2c91a00301962effb76a18ea -dist/2025-02-18/clippy-beta-x86_64-unknown-illumos.tar.xz=6714018d069fbce271c177f1941a6b77f18b67af462596aff273f7db1970ef4a -dist/2025-02-18/clippy-beta-x86_64-unknown-linux-gnu.tar.gz=72a8ee3bad3d638af0cc3ba6c0c0ed1594abe609573de71d9c7a884a8ac7645c -dist/2025-02-18/clippy-beta-x86_64-unknown-linux-gnu.tar.xz=f622befd60c3695d3d62642b953deabc3e3f04b32cae8a7cc228cb534244adbc -dist/2025-02-18/clippy-beta-x86_64-unknown-linux-musl.tar.gz=8946e02ab98281b6949c4d725a5fe3fb1bfc86651a675e451f126fec8d053762 -dist/2025-02-18/clippy-beta-x86_64-unknown-linux-musl.tar.xz=425907bd4320c516647e5dd6df6154746d64854fe2e78f27283b7fcb27164de7 -dist/2025-02-18/clippy-beta-x86_64-unknown-netbsd.tar.gz=505208d2d73ed7278e5b29d8450c382a89e4c0992d6199243e07c8640c611b85 -dist/2025-02-18/clippy-beta-x86_64-unknown-netbsd.tar.xz=d4b0306e7d7db5cb7da977a7ca72fff2070f102ac385c3b35286da25033582af -dist/2025-02-18/rustfmt-nightly-aarch64-apple-darwin.tar.gz=13854358645915af29d9337bb87301aa1a5e76ecc86a934dd640d02af3255ea2 -dist/2025-02-18/rustfmt-nightly-aarch64-apple-darwin.tar.xz=0cd190bd5a064235f9cd6f6e7eae4725b3b53ae36493b3ea54b8f190372ba3ee -dist/2025-02-18/rustfmt-nightly-aarch64-pc-windows-msvc.tar.gz=20b3f8c4c7b02158181970804d419b16f85a1083943e1c384e0bcef441f32aff -dist/2025-02-18/rustfmt-nightly-aarch64-pc-windows-msvc.tar.xz=1ace0f10060d2fc35a1f05a1d61adebf95212e8b46a2234c2e78030481c1b3e9 -dist/2025-02-18/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.gz=e5ad64d67931df49f6b7d3448e9860699d6549c2b4a96abda1a03069b45f339b -dist/2025-02-18/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.xz=e8112ae80c8fd43452612b79dabf471be561b7e828c9a2141c698429d761a49b -dist/2025-02-18/rustfmt-nightly-aarch64-unknown-linux-musl.tar.gz=8ad36bbe888e61b6d7e540ba4a2478652f14c1b28dbbcaab732003293b7c985b -dist/2025-02-18/rustfmt-nightly-aarch64-unknown-linux-musl.tar.xz=1794af320a273f4a951942ff0cd73a359fd82a971c572af1ab7ff2961340791c -dist/2025-02-18/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.gz=67b9d1d3c46bcce0aa94d6cb4155cdf7376677caf2e19685553266f781eb7cc1 -dist/2025-02-18/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.xz=9d7b97a85b1368cfc78f1df42afb08aa04eb17fbb91ceb3c379d59fab4294890 -dist/2025-02-18/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.gz=42396c7bd206d0fa07f3b44fcb894ac074e2af07eb158c1ef630bb5467151c8f -dist/2025-02-18/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.xz=6881c9681342f1430fd9cc8c9786cee40522be3dcd0fc4dcf2b3957d9d53f03e -dist/2025-02-18/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.gz=6cb8973ac4215d67aad9bb56521024626d7883a6e00748623a728dd9107698db -dist/2025-02-18/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.xz=920d877e04260be6ccf9963bea12220e886df673cbc48b55925650f8f5b21d9f -dist/2025-02-18/rustfmt-nightly-i686-pc-windows-gnu.tar.gz=ec5c7105f2c2a2055f704435fff9edbbee0a234e63050676c034f983d4e341ee -dist/2025-02-18/rustfmt-nightly-i686-pc-windows-gnu.tar.xz=ab408b64db4bd47abf8e24c0f611f2c67a3c9ce7e2138a92772e0510c6dce5f9 -dist/2025-02-18/rustfmt-nightly-i686-pc-windows-msvc.tar.gz=d04250bc2e57fcb03f1d80722f2ac1117f797d768262d7630c9b53af808a8c9d -dist/2025-02-18/rustfmt-nightly-i686-pc-windows-msvc.tar.xz=6d7be9f04a46040f068544e32eb84c98afc1f81b750beb229def84a7513150fb -dist/2025-02-18/rustfmt-nightly-i686-unknown-linux-gnu.tar.gz=94f585a7c666dc9c95c3ae14744e614a3fbe37b3e31b476b48bc4ef3289bdd46 -dist/2025-02-18/rustfmt-nightly-i686-unknown-linux-gnu.tar.xz=83e82932245b3c1d3c275126184f942b9cb8bf20f0d40c7cb1efb6f918327b9d -dist/2025-02-18/rustfmt-nightly-loongarch64-unknown-linux-gnu.tar.gz=9c8cb5a14294c48f8ee972d5f460751a8bae5b541bff3d872c85812b621c39d8 -dist/2025-02-18/rustfmt-nightly-loongarch64-unknown-linux-gnu.tar.xz=4f616740bef30599e6950ae2d8ae694513003e14122f6002a9d60bdc64f77cfc -dist/2025-02-18/rustfmt-nightly-loongarch64-unknown-linux-musl.tar.gz=a668e7be7946f6a9099486a40256f17832288322c9237d931f172ed76caf678d -dist/2025-02-18/rustfmt-nightly-loongarch64-unknown-linux-musl.tar.xz=b02c57c217f358ff4344ee2afcbb8353cffc0a012f970d9520ad233d188d59e2 -dist/2025-02-18/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.gz=9baf04e268999020372b21484ecc4f5aa001b3bcee05619ae5b0a11571a3a45f -dist/2025-02-18/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.xz=b2c2c3a0eecca7b4c35eabf09e215158c48eb426899e365db1c91c1c560ad255 -dist/2025-02-18/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.gz=c42df8e575a24a5edbc58b5b46a89a226188d2aafc59da89d568acbb6e9cceb6 -dist/2025-02-18/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.xz=fee7c373bb8fee5c7d4e43d7a7046d3bb156d3e496ed21cddf20c21ffdef3e69 -dist/2025-02-18/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.gz=a0ae21a3b56e20e667c72d92ad4bacd4abb77d1fea32949d7dd62a56d6b531d3 -dist/2025-02-18/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.xz=fc7e21cbd61169b37e81c73d4d5353d7e54ca322fd01491d9f37ff3666557e7e -dist/2025-02-18/rustfmt-nightly-powerpc64le-unknown-linux-musl.tar.gz=e08ceaa9241c2e53041b107af09674ca4fbc4e12b1371254869e3d80d5c907ab -dist/2025-02-18/rustfmt-nightly-powerpc64le-unknown-linux-musl.tar.xz=9f208dc6e5938a128174263349345e9fe7f587689f6a53fe5d026ae3c6fbed2c -dist/2025-02-18/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.gz=44abe49dfc0492cb3ab28f0aae0d784c982063399a38f8f13016f3dde123948a -dist/2025-02-18/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.xz=72fa294f92ab244608c384d6ad6eea0e540e6fc58181fd65a4fce0c5029c39fd -dist/2025-02-18/rustfmt-nightly-s390x-unknown-linux-gnu.tar.gz=556dcf393856c6d9c9c6731b02e34146f9f956f588025b6a614b8802032d125a -dist/2025-02-18/rustfmt-nightly-s390x-unknown-linux-gnu.tar.xz=93906364910891f71e13e0ecb07f02b707e42e11a0f1b117c590804dfa16a9d1 -dist/2025-02-18/rustfmt-nightly-x86_64-apple-darwin.tar.gz=7022c760f457075fb353e59984dcb551600581a315fd17ea1320b892b1d99a55 -dist/2025-02-18/rustfmt-nightly-x86_64-apple-darwin.tar.xz=e085ee261acbaa41361a0263dd8f13644f8a4e3679eca6bb0851b03c647b80e8 -dist/2025-02-18/rustfmt-nightly-x86_64-pc-windows-gnu.tar.gz=2436e18fefae02554e620a1131455d923c1b67e00e878c75a941a6eedb4eae28 -dist/2025-02-18/rustfmt-nightly-x86_64-pc-windows-gnu.tar.xz=9f6e37b5973925d07115e517e6a3e490a221218f48fd101a20670da2c3d01add -dist/2025-02-18/rustfmt-nightly-x86_64-pc-windows-msvc.tar.gz=78f492a26981e7a6f9f3e8bbd1e880682e55cede081f3cfb13a2ec5f736edbb2 -dist/2025-02-18/rustfmt-nightly-x86_64-pc-windows-msvc.tar.xz=d4d788fa3e3b9a598aa7baec47af3b56362224533be85dd68a411f35f8800b2d -dist/2025-02-18/rustfmt-nightly-x86_64-unknown-freebsd.tar.gz=8922186dedf0b12e9aa2bb041b76be8fccd43b9322c3496c688355f34bbd7a59 -dist/2025-02-18/rustfmt-nightly-x86_64-unknown-freebsd.tar.xz=6325e43f2c28118a9525f5c5fc09de9fb9a09ffb4aaad31f28d394c233ee8398 -dist/2025-02-18/rustfmt-nightly-x86_64-unknown-illumos.tar.gz=7f317107f8319c650973cef52f745c2a8e57ea6a087910b6979404f2cb2f1cff -dist/2025-02-18/rustfmt-nightly-x86_64-unknown-illumos.tar.xz=b273be4897e83f786020bce1dc5dd1caf01e2ea43f085391c0031277718feba0 -dist/2025-02-18/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.gz=0373011266a9ab62f45fa137a4bfdb970ccad8bbbb74bf776466d203f28d226b -dist/2025-02-18/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.xz=62748525678370dbda7f1cbd12a384e95d4af76103de998785278f6d1f076177 -dist/2025-02-18/rustfmt-nightly-x86_64-unknown-linux-musl.tar.gz=30eeb980720d8c22bc45c012c4fd212e118195206b8b993630f074e526e6693a -dist/2025-02-18/rustfmt-nightly-x86_64-unknown-linux-musl.tar.xz=2f3843d9544fa56dc87f1d13ef79c68c1e68d84bec007f0345159a7448368dfe -dist/2025-02-18/rustfmt-nightly-x86_64-unknown-netbsd.tar.gz=a86eaeab8f5f45d16eaf355a46d8b19afcd8c46db732432091156e381aa79cb6 -dist/2025-02-18/rustfmt-nightly-x86_64-unknown-netbsd.tar.xz=144cd28da601c331f6501c634ad89286be213a69cf521435e35657c5f6fe2afd -dist/2025-02-18/rustc-nightly-aarch64-apple-darwin.tar.gz=21101db859a550ab39de1ecdec75f4f058934ed8e0ab7dfadbb2efab57bc5e0a -dist/2025-02-18/rustc-nightly-aarch64-apple-darwin.tar.xz=a40da26e908810701112b9d3f9ab83515c8e2f4b33219f8f773c5459366d37e1 -dist/2025-02-18/rustc-nightly-aarch64-pc-windows-msvc.tar.gz=5391bc993b7208c10a6f4256417c9f76a4a33d167b2fd547b57af614d3fc8458 -dist/2025-02-18/rustc-nightly-aarch64-pc-windows-msvc.tar.xz=d72a205f52173b1726d8341a9436e62439b1987fe0cd4d2bbff740e38f629b41 -dist/2025-02-18/rustc-nightly-aarch64-unknown-linux-gnu.tar.gz=185e052bf2ba1cda4b6ad1c49a9f65b906899ad1ca09cd864d6041941ad344dc -dist/2025-02-18/rustc-nightly-aarch64-unknown-linux-gnu.tar.xz=640f7af3fef5f0abacdaa292ce17255433ee16f12bfc2d2e81d70afcf9fcdd8f -dist/2025-02-18/rustc-nightly-aarch64-unknown-linux-musl.tar.gz=8cdee468a90606b21a8cc3305f2b6b3eb7e3d687263f4ca8319c709cda2a324f -dist/2025-02-18/rustc-nightly-aarch64-unknown-linux-musl.tar.xz=358bbfb24816c781e07d5480a5606dce27068f856c0a606873ceba05c9540c3c -dist/2025-02-18/rustc-nightly-arm-unknown-linux-gnueabi.tar.gz=b220757cc8ed39c429c49b55e293ded3e07239d2e2bab8a9054ce55581393c47 -dist/2025-02-18/rustc-nightly-arm-unknown-linux-gnueabi.tar.xz=18d3cbc49e44b7810b498517d21390e39bee7ca8351c8b321592e83301ad79e9 -dist/2025-02-18/rustc-nightly-arm-unknown-linux-gnueabihf.tar.gz=77ac127bae48859f57d9bd8337ac4a0bda95b1190e451abeaf7e77f1a240a647 -dist/2025-02-18/rustc-nightly-arm-unknown-linux-gnueabihf.tar.xz=79009bbf0325f9db0c905d74cb0f139c92478a0b2fb5edaf383366b0e654a172 -dist/2025-02-18/rustc-nightly-armv7-unknown-linux-gnueabihf.tar.gz=8264c7ed7bc47953ae76cf87236655562a55846abb195bc9281833a0da168db6 -dist/2025-02-18/rustc-nightly-armv7-unknown-linux-gnueabihf.tar.xz=c6a85e7f2a469fb05f0a84ceaea25dc0d95b57bd4d68dcee447918162cb36b2a -dist/2025-02-18/rustc-nightly-i686-pc-windows-gnu.tar.gz=0f31c9ed4ba7e942806fc2927d305f9d3ad676cf81e53e0f7c4123aef375fedc -dist/2025-02-18/rustc-nightly-i686-pc-windows-gnu.tar.xz=350f4b46dee2aa6ebfc31912cfae5c7c1db99b298c52834308e95c504cadbe7d -dist/2025-02-18/rustc-nightly-i686-pc-windows-msvc.tar.gz=e12a40b7178995ac223eb7fa317e1114a988256d99fe615f70d64cf3f2891fa7 -dist/2025-02-18/rustc-nightly-i686-pc-windows-msvc.tar.xz=09fb4a4744a55bf8fd6371e5496f6a9c00b119ddf20b19855653d66d9a618214 -dist/2025-02-18/rustc-nightly-i686-unknown-linux-gnu.tar.gz=52361a34730f8bf14eefad7e51f66fc3ba3be405a364d4520103208fe8fdc056 -dist/2025-02-18/rustc-nightly-i686-unknown-linux-gnu.tar.xz=ea81964fc8bcb8b43968acb6a4f7fdec2ddea9f75a8be5446fb01b4267d0d75f -dist/2025-02-18/rustc-nightly-loongarch64-unknown-linux-gnu.tar.gz=11e7a143112b6abf818652e425b6f092464cc9d8f5286e90180c7af8d5939643 -dist/2025-02-18/rustc-nightly-loongarch64-unknown-linux-gnu.tar.xz=86f5d40eecccb623ff744bbc1fb40458949db9b2f8501cadc6be9bca95f6c693 -dist/2025-02-18/rustc-nightly-loongarch64-unknown-linux-musl.tar.gz=1be7ecdf609958fb0ef945203b22a600f1e343ee7fc581f6451eecd39f1e0b7e -dist/2025-02-18/rustc-nightly-loongarch64-unknown-linux-musl.tar.xz=03d3b67092da64f7b7be7ba4e115cfad4071c0bea3abb5e60ac166127713b169 -dist/2025-02-18/rustc-nightly-powerpc-unknown-linux-gnu.tar.gz=4e33311490c2dcf79a16307e1141ce37574ec3829a1e93d0f5b06ff68ad5c861 -dist/2025-02-18/rustc-nightly-powerpc-unknown-linux-gnu.tar.xz=504c102fa1c8dc5042cb354a60b87c0f6d47f9adab341f496af723f3ea8bd548 -dist/2025-02-18/rustc-nightly-powerpc64-unknown-linux-gnu.tar.gz=c559971ae42a5e0e999e2fe119033bffbfe8c64b767e697e0b95f5dfc271d13e -dist/2025-02-18/rustc-nightly-powerpc64-unknown-linux-gnu.tar.xz=51159ab0ade5a62e128b6c794da5c9815324470c468e5808b50663c3a0df6d39 -dist/2025-02-18/rustc-nightly-powerpc64le-unknown-linux-gnu.tar.gz=a8134f8f7ea4531d54ab5c0a0894f140ce5182a384c57395edbe06ed551970ab -dist/2025-02-18/rustc-nightly-powerpc64le-unknown-linux-gnu.tar.xz=8f2f5d88ba9f4ee946db5f00d56c4852213dcb0b46ce2793966af6c96d934dc6 -dist/2025-02-18/rustc-nightly-powerpc64le-unknown-linux-musl.tar.gz=7bfc6666757b57fa6160d076a9eb52852dcb5bf788bd12c0f014bbd552b8a7ef -dist/2025-02-18/rustc-nightly-powerpc64le-unknown-linux-musl.tar.xz=e2c3293e2a90012ad48bbc2b6f285adf20f356ff1f4146b3f11543511bbb3c44 -dist/2025-02-18/rustc-nightly-riscv64gc-unknown-linux-gnu.tar.gz=f582a59b5a6cbe6d58400c69f1cad4f34d0f1541c1ffb9df3ce71846edd828fe -dist/2025-02-18/rustc-nightly-riscv64gc-unknown-linux-gnu.tar.xz=244384bd94f7c3606a086abc8be9d36a855faf09d9bb6b121f42e168c526e717 -dist/2025-02-18/rustc-nightly-s390x-unknown-linux-gnu.tar.gz=327e29662140cb76b1ff362fe51f9a12fb4ec304929317ed8de7295fdb9c5b9f -dist/2025-02-18/rustc-nightly-s390x-unknown-linux-gnu.tar.xz=a2c4e19b3a8dabd5c8fe72edd60d1925947cad5971c77c62f12fca764c6e4e7a -dist/2025-02-18/rustc-nightly-x86_64-apple-darwin.tar.gz=b6812f92e08cff1b706380637fdd553b04b9cea746ffb69e6488fbec70680136 -dist/2025-02-18/rustc-nightly-x86_64-apple-darwin.tar.xz=f2502b2a810938c41e2302a9112c97d04998ada16583373e6488bcca00595761 -dist/2025-02-18/rustc-nightly-x86_64-pc-windows-gnu.tar.gz=9159f7323718c6a8b98f7de5186ed507b3dca1bfcce9bdfa6437313bd630a989 -dist/2025-02-18/rustc-nightly-x86_64-pc-windows-gnu.tar.xz=10d54c9b80570b6729d0e68f017d862c5126f09b42f150d004aa8fd5382b165c -dist/2025-02-18/rustc-nightly-x86_64-pc-windows-msvc.tar.gz=1f29c1aef1dcc3ff9f2e3013b7ea0521829e6e474f9058cb70fea65180230b41 -dist/2025-02-18/rustc-nightly-x86_64-pc-windows-msvc.tar.xz=18cddaf7653f146dcc8a44ca0cc33c6dd3c24f28fff87aedca01fe3beaaa9915 -dist/2025-02-18/rustc-nightly-x86_64-unknown-freebsd.tar.gz=e57c1477cf9b75e727db48b8b75435d65aa0a6ef0eb566ac1890b576c330f64f -dist/2025-02-18/rustc-nightly-x86_64-unknown-freebsd.tar.xz=725f9e9d25b7ad6f60d5596684964b0c3a63d98a62a2aeda6a134b9f02fdb681 -dist/2025-02-18/rustc-nightly-x86_64-unknown-illumos.tar.gz=86a9034fa275c0fc73d639fe6437fc4d2621bf12897c9f83a81ab6056173a95f -dist/2025-02-18/rustc-nightly-x86_64-unknown-illumos.tar.xz=4aeef66ad8a908589ddf0d89581a6ca809b7c2a57f06bbda6fd3927b531fe07b -dist/2025-02-18/rustc-nightly-x86_64-unknown-linux-gnu.tar.gz=907aa282fb9f3d96c9fb03dadd62f4ea766e1242fe19106ae331a4f49a9b20f0 -dist/2025-02-18/rustc-nightly-x86_64-unknown-linux-gnu.tar.xz=e63d13a6acd596ebfd7bf65b292eedd2a5e260b536ca11517a3fe1d8e6a6241f -dist/2025-02-18/rustc-nightly-x86_64-unknown-linux-musl.tar.gz=b7bee098c32b321551f68e96e002f85e3a0323c864aa7f65641a58ae24f4238e -dist/2025-02-18/rustc-nightly-x86_64-unknown-linux-musl.tar.xz=e5c22c2fab89c7ba548b11104c54e8f82cafb1979ba73a318682bb10ed9e4fb9 -dist/2025-02-18/rustc-nightly-x86_64-unknown-netbsd.tar.gz=7bf40bffe95437244f6f8a5fde69499f42d2b716e166115530fbcdbdcd837887 -dist/2025-02-18/rustc-nightly-x86_64-unknown-netbsd.tar.xz=0adeaa382f289233ffc9229e116a340ac03a861f0fdbb5bd35aaf5d0d7370877 \ No newline at end of file +dist/2025-04-02/rustc-beta-aarch64-apple-darwin.tar.gz=42fbc48c6f9034c1d47029491e0adc7aaa1adecf429e22ea9eb6d36225ed13e7 +dist/2025-04-02/rustc-beta-aarch64-apple-darwin.tar.xz=08f88363fd42d66d537c0a296502f94c3a3fecf59a004613c9acff33eb0b0207 +dist/2025-04-02/rustc-beta-aarch64-pc-windows-msvc.tar.gz=ea47adaa63abd18bf0c11cdb381eefb2874994527005cbccc0dcace33191f9c6 +dist/2025-04-02/rustc-beta-aarch64-pc-windows-msvc.tar.xz=cefea68c789907a45f0bd4233da2e3406287ac55d1c33f8612ec1aa006b853f0 +dist/2025-04-02/rustc-beta-aarch64-unknown-linux-gnu.tar.gz=38fa4ce395641a988247ee58c334389eda62fc1d3c0fb45157f24578319925d8 +dist/2025-04-02/rustc-beta-aarch64-unknown-linux-gnu.tar.xz=d8d0b459acdff2a32f8c40707bf5a17b71ce86fb5ee9ad61690cba8f8227bbfc +dist/2025-04-02/rustc-beta-aarch64-unknown-linux-musl.tar.gz=41f01647a80a7f21b85fe660af9e7964ad34f0e909d1e58c9e28e102a796791f +dist/2025-04-02/rustc-beta-aarch64-unknown-linux-musl.tar.xz=8436eddf40ad5bf61153f24c887fb0f0e878bcc403095719b35f3147328d6406 +dist/2025-04-02/rustc-beta-arm-unknown-linux-gnueabi.tar.gz=07ee5588005a18477a7de89321e6527ee5f10af00e9c4eeb2a8c666f79d3d606 +dist/2025-04-02/rustc-beta-arm-unknown-linux-gnueabi.tar.xz=8a95664cef49c1e45b2ae61ec464a5be976e4cecd2b502a050f95b9eb25dd4c7 +dist/2025-04-02/rustc-beta-arm-unknown-linux-gnueabihf.tar.gz=b9b186ea9bee58a646ce8c4c384fc4cb528c73c1fee3ea3f5028fd4b3fddab3a +dist/2025-04-02/rustc-beta-arm-unknown-linux-gnueabihf.tar.xz=9f62c2ea5b67c14ab804267d449ded07c8b551536886099b02b942ce2d641790 +dist/2025-04-02/rustc-beta-armv7-unknown-linux-gnueabihf.tar.gz=f07363ad0dff8b965dc10543f27cfd923266dea6284ebbb1d1b59b77f5ae2b61 +dist/2025-04-02/rustc-beta-armv7-unknown-linux-gnueabihf.tar.xz=a31afc234645a7dc5dc47f05bb5321fea12931278433df834def303cdea9f52d +dist/2025-04-02/rustc-beta-i686-pc-windows-gnu.tar.gz=f396061e8faaf66edea34b0855e2d3760fc0fd5c75e99696b50b2d4f310e11e0 +dist/2025-04-02/rustc-beta-i686-pc-windows-gnu.tar.xz=0f95f9170c5b211db29c3baac9341ef61de83511fe0000b8aae65aaf90041ae6 +dist/2025-04-02/rustc-beta-i686-pc-windows-msvc.tar.gz=82b7d1136d1b6f3d229fc77eac19d2cbfb3a46de472345b0ec3ebc152872164f +dist/2025-04-02/rustc-beta-i686-pc-windows-msvc.tar.xz=565bde72132e77617059da66edf9262f728336a2cc2c3c7cf4d61e0a4b5e681a +dist/2025-04-02/rustc-beta-i686-unknown-linux-gnu.tar.gz=8a3abc2a8aee8fa30699f51a216b29b41b2242143646d0f560f89bf72a0e285c +dist/2025-04-02/rustc-beta-i686-unknown-linux-gnu.tar.xz=7d47cf99aa5fd3b5bc2caa918b4eaba793b6d38252a72fa7be631c8db27c8525 +dist/2025-04-02/rustc-beta-loongarch64-unknown-linux-gnu.tar.gz=0654cf14bd3302d001fa00fe73cb7c597206c6897978b3aeefd00e9325a8bdad +dist/2025-04-02/rustc-beta-loongarch64-unknown-linux-gnu.tar.xz=6cd5c3ccb643a912d738239c0ad7464ee755cd81f45a26a9d3aa5ceeff569ba3 +dist/2025-04-02/rustc-beta-loongarch64-unknown-linux-musl.tar.gz=e3c0c5c52b04dd060f3a70b0c936dfb5c70ac29256361a491df9c898259dd551 +dist/2025-04-02/rustc-beta-loongarch64-unknown-linux-musl.tar.xz=83a9bc8f9a61b2a7fedddbdfb253aa078bc9896f179ec9b1d1bd918e7de34663 +dist/2025-04-02/rustc-beta-powerpc-unknown-linux-gnu.tar.gz=21efa7a67647df8aa99e40317c798895321d09c48b8453e51eef1635c20e9c47 +dist/2025-04-02/rustc-beta-powerpc-unknown-linux-gnu.tar.xz=56203ed9d3bbbab33e2825db7c72cfbe4f857f68dc98072cc98280cc4f1110d6 +dist/2025-04-02/rustc-beta-powerpc64-unknown-linux-gnu.tar.gz=76c343aa3f5c74e1419e3f2f79dd3a2091fad8f6db644cf14f7aef036c8369d0 +dist/2025-04-02/rustc-beta-powerpc64-unknown-linux-gnu.tar.xz=e9c7b97a407127e51fa49ca94c5f22c59f2f325848d55e6160d6dcf7ff690f91 +dist/2025-04-02/rustc-beta-powerpc64le-unknown-linux-gnu.tar.gz=27935ff4136141519b4e7b37b55253960b7fa16f5cd751d731ed85019432247b +dist/2025-04-02/rustc-beta-powerpc64le-unknown-linux-gnu.tar.xz=fd37c12a55055bc4a2f0e002b3126e6396df8d49254b2a8a7a45354aac46bb2c +dist/2025-04-02/rustc-beta-powerpc64le-unknown-linux-musl.tar.gz=cbeba9993d03c6c0c2c508414bee04665abb9c084c736b39c5b8d38c8f63402d +dist/2025-04-02/rustc-beta-powerpc64le-unknown-linux-musl.tar.xz=e92f69d85929c81e3c91b2ab45eec418afc65edf6f8bf9383148a98b052353df +dist/2025-04-02/rustc-beta-riscv64gc-unknown-linux-gnu.tar.gz=31a8ae1e64fb86a499518d7711595d653db56527aaedea06bc2bbcb912568844 +dist/2025-04-02/rustc-beta-riscv64gc-unknown-linux-gnu.tar.xz=7d001ad6c4825d5323813ed19747cc3e3d2dcbbe76317329a52127b3de37ee88 +dist/2025-04-02/rustc-beta-s390x-unknown-linux-gnu.tar.gz=c69d15e75d51caa0cf77fbe149d43b62c327896bdeb0c6c73fa7240404289862 +dist/2025-04-02/rustc-beta-s390x-unknown-linux-gnu.tar.xz=cf80772ba9eed4885a28aab38323f0ed24ab220339a3b8a148b7c27860c48c19 +dist/2025-04-02/rustc-beta-x86_64-apple-darwin.tar.gz=be22d207f8fd4722d69f6fdc56c57618ec01c54c5b6f3a8506c62583259d433a +dist/2025-04-02/rustc-beta-x86_64-apple-darwin.tar.xz=04feea9824748ae01b4f4f85d15adc5baee23c996c22de86041888466ae69512 +dist/2025-04-02/rustc-beta-x86_64-pc-windows-gnu.tar.gz=8c75005f0309d30e7c272adce173adb253874ce881b347946b6ffe5a07067439 +dist/2025-04-02/rustc-beta-x86_64-pc-windows-gnu.tar.xz=7b87c4ab5291d9ad3670f4e9ee98fe9f6f877ab8d4952109d7e5e9d20181a700 +dist/2025-04-02/rustc-beta-x86_64-pc-windows-msvc.tar.gz=a96d89ba655db5317dd51ffa2ebb81b7bdb76b19cf12de36e9d0aba2c5877ae2 +dist/2025-04-02/rustc-beta-x86_64-pc-windows-msvc.tar.xz=84bcfd763eba610c78223697393ea97f1f70e567a44b8cfe22db79f1cade4201 +dist/2025-04-02/rustc-beta-x86_64-unknown-freebsd.tar.gz=95ff7349cf12e49028256c06c8517719cada2720d4db80bfe7531289bbcdbde9 +dist/2025-04-02/rustc-beta-x86_64-unknown-freebsd.tar.xz=c8d0147c625faa5ce0e75c2509827bc4b190ad286e41411bce92023e00eb7a1d +dist/2025-04-02/rustc-beta-x86_64-unknown-illumos.tar.gz=4be80235a110028d64404e532eb20af37e46db72a7ac3a0cf7c94ddf463c461f +dist/2025-04-02/rustc-beta-x86_64-unknown-illumos.tar.xz=b18ea9a5c262c2f7505305110473cc15bd2c4ed9d583f07c15635406c050be08 +dist/2025-04-02/rustc-beta-x86_64-unknown-linux-gnu.tar.gz=234027a0075224ea157efaf39173ece43f9ca7d69d86e4790a2a038f7e6d98a6 +dist/2025-04-02/rustc-beta-x86_64-unknown-linux-gnu.tar.xz=308a8ee2855a6471db3b3b64cb06e355e31d0d617ebc9f30757bb7db5f6fc7c0 +dist/2025-04-02/rustc-beta-x86_64-unknown-linux-musl.tar.gz=10f39cc94f39bcf17d0fa3b8efeb4db72408fba694e5eb0f175e7465f6d2de49 +dist/2025-04-02/rustc-beta-x86_64-unknown-linux-musl.tar.xz=6b0d16b46347fdbcddfafad8209df19515059eddce1e048ecf1585341fa1e586 +dist/2025-04-02/rustc-beta-x86_64-unknown-netbsd.tar.gz=09f482425c92396f7e4ae3baf625dbcad1d886d82ecfb605b50393abdc23ce15 +dist/2025-04-02/rustc-beta-x86_64-unknown-netbsd.tar.xz=bac2f1a493bc2c5fa6cab1f58ff536cbeba55f77141b34636bfded9e3ff167b5 +dist/2025-04-02/rust-std-beta-aarch64-apple-darwin.tar.gz=8875ade1dd8ba0bca0c12860a076df1f089195a52adc546679025c405bef4dd1 +dist/2025-04-02/rust-std-beta-aarch64-apple-darwin.tar.xz=0a0593ab4c95802b0ed810c0442e13ad9304712c2f7c30a30c734523a7448d8a +dist/2025-04-02/rust-std-beta-aarch64-apple-ios.tar.gz=839086e20098c305adcdf9103cdf3f29a14c4140b4c1b728723e7aedad966883 +dist/2025-04-02/rust-std-beta-aarch64-apple-ios.tar.xz=70f1832193e77a2018088943b531bdbacbe5404d5d7a34393e03f40329e742ce +dist/2025-04-02/rust-std-beta-aarch64-apple-ios-macabi.tar.gz=94adeb2e63a91c09001facbc554678227a3717748104424e4fea71db3d5a16be +dist/2025-04-02/rust-std-beta-aarch64-apple-ios-macabi.tar.xz=73c9bb75eb6fa4cf613c7a2b0e237472e144a1469cb043194ad7802052149fee +dist/2025-04-02/rust-std-beta-aarch64-apple-ios-sim.tar.gz=0e01ed2620887b893687758d62422f661429e3c4566ff52d967463eca89f54c5 +dist/2025-04-02/rust-std-beta-aarch64-apple-ios-sim.tar.xz=c26beb8ea9f11845ce79d4f0ec2616ce82dfbc4fefadfc7f94a1df17f4d5bec2 +dist/2025-04-02/rust-std-beta-aarch64-linux-android.tar.gz=64047673efa9d9bad660e2a44f82e6f929c881fe205523bff10a549505d12b72 +dist/2025-04-02/rust-std-beta-aarch64-linux-android.tar.xz=0e4c6b76e8d92023533aef6fe377c9bd45ef9c1da517eda7bfefec85b966780b +dist/2025-04-02/rust-std-beta-aarch64-pc-windows-gnullvm.tar.gz=a25c50a86e5d674600cec5bd9e7939bf36b0afa766445b0d71673431388d285c +dist/2025-04-02/rust-std-beta-aarch64-pc-windows-gnullvm.tar.xz=8060a4c5337fa6c34b3f08ddb8886beeb5bafd2b02544b08a7cfcb466a27a972 +dist/2025-04-02/rust-std-beta-aarch64-pc-windows-msvc.tar.gz=efd76703934ae0187308eec9b3439abea0dd4437ac353d5dc07d92f9440ab9ee +dist/2025-04-02/rust-std-beta-aarch64-pc-windows-msvc.tar.xz=007462f554b0c6d2b165d727bf72b1ad4347a53869d672fcbf48db2c1dcf128d +dist/2025-04-02/rust-std-beta-aarch64-unknown-fuchsia.tar.gz=e0dc54be7890edef123d2dc31f0dcddd1c807cc060a34f475093cab79100d9fd +dist/2025-04-02/rust-std-beta-aarch64-unknown-fuchsia.tar.xz=01c06c1d61c512a034a109f50f957e4496639549837b63464acb4fb24ff65e09 +dist/2025-04-02/rust-std-beta-aarch64-unknown-linux-gnu.tar.gz=2042d37b09618379dd91125d20803e2d97d5f3f3794e01ed27597a0f3b27c102 +dist/2025-04-02/rust-std-beta-aarch64-unknown-linux-gnu.tar.xz=568f0b8da190daf78cd8573b0408db2ecc2c07b1cb1fa463239581963738e9de +dist/2025-04-02/rust-std-beta-aarch64-unknown-linux-musl.tar.gz=386b1e4786dbfe342626cde4c3708abd04d9862d69717c7acd5dfe82427e38f9 +dist/2025-04-02/rust-std-beta-aarch64-unknown-linux-musl.tar.xz=781d0f9417e1b3d33d95e3c5b82ba7e481a610dc468345119e09a52b1d170045 +dist/2025-04-02/rust-std-beta-aarch64-unknown-linux-ohos.tar.gz=8673d059524ac141a8907decfda36c8afac81fd36dd75f78df750a6d52ada221 +dist/2025-04-02/rust-std-beta-aarch64-unknown-linux-ohos.tar.xz=8e8afe45e9bb84ebc3e02f0b4b71dbcec7c844128329d31067303b86113c3439 +dist/2025-04-02/rust-std-beta-aarch64-unknown-none.tar.gz=72e1dce3c1f821b6018ec155bff250b941afcfcf1697b440a69822b10e929b94 +dist/2025-04-02/rust-std-beta-aarch64-unknown-none.tar.xz=7030883ad3ca170a061972707c488fc25d4dc8ab0f60a1b9b54240e42ca713ba +dist/2025-04-02/rust-std-beta-aarch64-unknown-none-softfloat.tar.gz=28f87a505ca4e2c33015338d73cfdf5c2fdb1f5775f82ec432d033a36880351d +dist/2025-04-02/rust-std-beta-aarch64-unknown-none-softfloat.tar.xz=45669a09671c183d702a31b6ecf095e8f422797c4e242063c7864180c6f657a4 +dist/2025-04-02/rust-std-beta-aarch64-unknown-uefi.tar.gz=1ad54cabda8bfabfd93e16c564c0950c26e1502662d5f4ce3b33b4ee265b9a2d +dist/2025-04-02/rust-std-beta-aarch64-unknown-uefi.tar.xz=a79f9d7eb4297994b2e87d48106a959c82bc4387433e5e86dc8caddde29a8a4e +dist/2025-04-02/rust-std-beta-arm-linux-androideabi.tar.gz=75192092fa7a40051a70a843cf75513de2c50d66927f16b122f7417c1d4f25e7 +dist/2025-04-02/rust-std-beta-arm-linux-androideabi.tar.xz=843dde45dfa49b5cc97266c61d8e58dfb22dbf2288e6e8baaef769eaf59675cc +dist/2025-04-02/rust-std-beta-arm-unknown-linux-gnueabi.tar.gz=03ccaa5e246502fc61fea1e0b33f5c60b5895cd0b5b932bf640d62e97164b457 +dist/2025-04-02/rust-std-beta-arm-unknown-linux-gnueabi.tar.xz=a73525dcab3a0f3bc7064c8a6cdeb9b0e5b359501cb7e8fe20075a0e97b2a5ba +dist/2025-04-02/rust-std-beta-arm-unknown-linux-gnueabihf.tar.gz=8c851fc122d14beee962e15fdb95c2873769805180be30723f418d84cbc0a8b8 +dist/2025-04-02/rust-std-beta-arm-unknown-linux-gnueabihf.tar.xz=8524ad1b7723a4a5898837d5b526fb11ffcd039b2c4835a2e139071f6cfd4e9f +dist/2025-04-02/rust-std-beta-arm-unknown-linux-musleabi.tar.gz=b108ec4460d4f6ca79813e6d2d4cb7061fa522a990333fb9f4f927b0fc659624 +dist/2025-04-02/rust-std-beta-arm-unknown-linux-musleabi.tar.xz=0bdb617dfa833c62c03f5bfd2f06ed3ca1479908d860f888d661794188bd57d6 +dist/2025-04-02/rust-std-beta-arm-unknown-linux-musleabihf.tar.gz=19f9fff71344f7a42f958c3efec720e4b2e0d67ba36a5fd66946e74811259f2b +dist/2025-04-02/rust-std-beta-arm-unknown-linux-musleabihf.tar.xz=0cdfe9b4a8bc4b63637cfd9766c3e0e1d3dcd6d2e82fe35f57973a0081e630ec +dist/2025-04-02/rust-std-beta-arm64ec-pc-windows-msvc.tar.gz=a8490374598bbfa42931bbfba51ecc0186c476217eb79408ae6b80a4ba6de9f2 +dist/2025-04-02/rust-std-beta-arm64ec-pc-windows-msvc.tar.xz=2bc2838320667f060c140345d1c26aedf90bf5efb1f72e6722b74d32f876901c +dist/2025-04-02/rust-std-beta-armebv7r-none-eabi.tar.gz=9a237e1dbd2e3b555aa3932351d1c20a0f9f2f06e810abd254b5ca152aace687 +dist/2025-04-02/rust-std-beta-armebv7r-none-eabi.tar.xz=f4978bf9af719f0b6e8300ea862fe617e983e5443a46c769d60d5e8c4d556ba8 +dist/2025-04-02/rust-std-beta-armebv7r-none-eabihf.tar.gz=c1476718625d5d5d42b60faa9ade845272b0b71e91d77a9cdd271c4682c900d2 +dist/2025-04-02/rust-std-beta-armebv7r-none-eabihf.tar.xz=f8ab07e99983fc7395841cc9ed7ce7cfaedd87bfb91214bd83508ad96aef0c0b +dist/2025-04-02/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.gz=649071a7de4792ff75da59ca421ea1cb364c011db97e73c480982a5f9f06b8aa +dist/2025-04-02/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.xz=529aac0b0a385fa5ddb76a88eb6923bcc981679caab2d1c374d443383c99f52a +dist/2025-04-02/rust-std-beta-armv5te-unknown-linux-musleabi.tar.gz=8bdf3412b0b557485099db86afcdf58293bfd4c09c4b360c2d9733788b612122 +dist/2025-04-02/rust-std-beta-armv5te-unknown-linux-musleabi.tar.xz=5d5a4ebed984a0930b214ec0b11e20fd9a7b8d5dc2d00985b75a77c8febcf441 +dist/2025-04-02/rust-std-beta-armv7-linux-androideabi.tar.gz=2c03cbb393641876bebad9b76465ac7f96adb82c14dcc9b5bc01a82e5110b892 +dist/2025-04-02/rust-std-beta-armv7-linux-androideabi.tar.xz=67d86fa728178c30cd7a33e0c488c32f58ae0caeb9a982370e080ea38853830b +dist/2025-04-02/rust-std-beta-armv7-unknown-linux-gnueabi.tar.gz=3737dd5f80f35f3fecf5cd8324c9226f45bb0bfd040998d91509a2c6fd8967f1 +dist/2025-04-02/rust-std-beta-armv7-unknown-linux-gnueabi.tar.xz=8f9f710c92af058d5a07c93b4cfd45b7d30e63ab79bea7f79530537aae2dd836 +dist/2025-04-02/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.gz=6ecb3e238e125e88851dba9711b2b32f4de1da55de36a62373bfcc42d001fa0b +dist/2025-04-02/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.xz=7d6807d24afe4825b77c1cb74c1412b814cf2508f5b40debb55b3f264e02eb6a +dist/2025-04-02/rust-std-beta-armv7-unknown-linux-musleabi.tar.gz=a15fccced78065f748a5c4f66763b8940ae3e52b5048b5ee1fab6b0b7b40c701 +dist/2025-04-02/rust-std-beta-armv7-unknown-linux-musleabi.tar.xz=20bc43c1b5742a9c7a97ade055441ca1ca153dab9602db3ffaf1ac518713568e +dist/2025-04-02/rust-std-beta-armv7-unknown-linux-musleabihf.tar.gz=b01929a0f18b1a41b65307a04d1273d2197df83b3c124f80659ef8fa4f8c4577 +dist/2025-04-02/rust-std-beta-armv7-unknown-linux-musleabihf.tar.xz=2a13350da7c632d3878ca8da8a7d0bda60c850df8e5d824956082b524eb136fe +dist/2025-04-02/rust-std-beta-armv7-unknown-linux-ohos.tar.gz=11bc9fd437be07cb454182b0d7b287ec030f7d8904f096b73beda6480ba33285 +dist/2025-04-02/rust-std-beta-armv7-unknown-linux-ohos.tar.xz=31e06feb45173fec8e58cf92216e44d556587fe2ed866102206e23514c73d3f0 +dist/2025-04-02/rust-std-beta-armv7a-none-eabi.tar.gz=aebbae792c070adea3f10135c02b2cf5d623b84e765ec3a72c89275f53a85384 +dist/2025-04-02/rust-std-beta-armv7a-none-eabi.tar.xz=e80dcb152e7a8337fbbff6a5c8dfcd9c6da4b753da6b14e63fe7c15cc0836359 +dist/2025-04-02/rust-std-beta-armv7r-none-eabi.tar.gz=e79846c1203d5d375c7c1cff1c843cb6fcd4e33bbc71b2363e12fc900bbd72bd +dist/2025-04-02/rust-std-beta-armv7r-none-eabi.tar.xz=0e24e48461cc46edef0237e38480ac806d0521c73ea366668e731f29b638d7c9 +dist/2025-04-02/rust-std-beta-armv7r-none-eabihf.tar.gz=fd2a9b48ea203b44567cfdcfcfb21d5d803896fdfdc5f3aa191e3fa7472b98db +dist/2025-04-02/rust-std-beta-armv7r-none-eabihf.tar.xz=2b85d461bed34a97cf832a7c0e1d4179d7800ef47523a8e31d635b8de5dd44a7 +dist/2025-04-02/rust-std-beta-i586-unknown-linux-gnu.tar.gz=cab412c30b27060cdcb29adb947dc070875813726707dff121c4a1aa8615646d +dist/2025-04-02/rust-std-beta-i586-unknown-linux-gnu.tar.xz=1b8d469fbb8903a5f4f5eb6ccee7bdf28cc56137b6b212fdfa1aed647f4c347b +dist/2025-04-02/rust-std-beta-i586-unknown-linux-musl.tar.gz=93fa0383e32f18567c3c156f3cddde1fa4296003f98cdd22b0b5628d69d5208a +dist/2025-04-02/rust-std-beta-i586-unknown-linux-musl.tar.xz=71ae00b01ffbfdc6654d0fd14df204adb7d499ac71e59c93affff91d58833d88 +dist/2025-04-02/rust-std-beta-i686-linux-android.tar.gz=4c6f4764e284ff29958417295ddc5d3316072fc9eac87dfed8b694c237aa4f88 +dist/2025-04-02/rust-std-beta-i686-linux-android.tar.xz=f471a7abb2d447f668f01973be4712e20c6dd29b210a96517b277e62c6d7de07 +dist/2025-04-02/rust-std-beta-i686-pc-windows-gnu.tar.gz=0c5efb9792502fc08174b2556f5c91f3edbad6e02de5e230f39c5fa011fc935c +dist/2025-04-02/rust-std-beta-i686-pc-windows-gnu.tar.xz=b6a87360e7be832288e59239d41e809db01710ccae5ef37bcbe7b0eb1d311e66 +dist/2025-04-02/rust-std-beta-i686-pc-windows-gnullvm.tar.gz=0429745cd95a198a7a42a1ce0c7ab2d502f3ff3eee81104fe6d5d4d5dab9447e +dist/2025-04-02/rust-std-beta-i686-pc-windows-gnullvm.tar.xz=bcb43c9e2d4a49c18d39e041d28021f2302707ae9ac20ef37f4d467fd2cd3975 +dist/2025-04-02/rust-std-beta-i686-pc-windows-msvc.tar.gz=e1d8c40e61701c6bfd519125169cc1ab1d60e9a58238351bbeda0ccc5522cc49 +dist/2025-04-02/rust-std-beta-i686-pc-windows-msvc.tar.xz=1f87f343a90f6e88cb3173d52f4f88d8abdb0c1a613681c92675c1acc340aa54 +dist/2025-04-02/rust-std-beta-i686-unknown-freebsd.tar.gz=5862f33548bef1aa21b3d63caefa12ee34775cb378f89c4dc161e081a773d11e +dist/2025-04-02/rust-std-beta-i686-unknown-freebsd.tar.xz=ed3460948031d0c4e97f7b1b77062f388d133db2b2212518eabd3198e72c031c +dist/2025-04-02/rust-std-beta-i686-unknown-linux-gnu.tar.gz=3a6edd9f412a274e372c9555b6758d540d06ac08efd21ce95df1ed4d30418afd +dist/2025-04-02/rust-std-beta-i686-unknown-linux-gnu.tar.xz=8338baaa50b9cb08a28f7bb21a22deef849f8809282c661e48c486a168b6249e +dist/2025-04-02/rust-std-beta-i686-unknown-linux-musl.tar.gz=56ab80fc6cb75a0d66c477e76f87918645bc3b616cf704306820832681022768 +dist/2025-04-02/rust-std-beta-i686-unknown-linux-musl.tar.xz=94efb810dbee977ecb3ff5a42a5a620d720c237da58d974ba1f376c99947baf5 +dist/2025-04-02/rust-std-beta-i686-unknown-uefi.tar.gz=64cb107065bde9b30c78b9b342211c4e6cd2c3ed726155dacfcf5958ba869a82 +dist/2025-04-02/rust-std-beta-i686-unknown-uefi.tar.xz=ff1bc215b4aba25f59eeee8285967e24b78f6965473ea8bb30186ab55804f88a +dist/2025-04-02/rust-std-beta-loongarch64-unknown-linux-gnu.tar.gz=da1d33b266e1dd277f97f63228843765706f26c9f75c4b5171f49c2762fed870 +dist/2025-04-02/rust-std-beta-loongarch64-unknown-linux-gnu.tar.xz=8309c9c4a03df90eb53116b5c5c4870d103911227848919580a48e5e85954709 +dist/2025-04-02/rust-std-beta-loongarch64-unknown-linux-musl.tar.gz=26a3115d5354f878f80bef1c83a44af185e2780882e17143ca57aff078d123a0 +dist/2025-04-02/rust-std-beta-loongarch64-unknown-linux-musl.tar.xz=12431c3b50276f352a3ea71c74db279cd03c2edfb3edf743f81774d4274f7ef9 +dist/2025-04-02/rust-std-beta-loongarch64-unknown-none.tar.gz=ac67b23f84d09ab17d26f30deb38a128ccf812a561738327effe48ecd0caa319 +dist/2025-04-02/rust-std-beta-loongarch64-unknown-none.tar.xz=5508b02465d3dbb40512a142eabb27817807d2af153089f7d05a0af355fdb245 +dist/2025-04-02/rust-std-beta-loongarch64-unknown-none-softfloat.tar.gz=a79a59139e13166cb1121d703cee113bf92821f937d433cb9a2c00567280a4e2 +dist/2025-04-02/rust-std-beta-loongarch64-unknown-none-softfloat.tar.xz=8c3b5501050f57125cc89e6525b780ca0e18d2d5318f779894ab97efef761fb3 +dist/2025-04-02/rust-std-beta-nvptx64-nvidia-cuda.tar.gz=84a48148eb313f236f85a4907af615b7af4c3ce3d9065ffe0db54458852690ab +dist/2025-04-02/rust-std-beta-nvptx64-nvidia-cuda.tar.xz=26281622332b438bc43b8f46921153a45c6236a4c0939c76fdb4d9fb3d29cbbb +dist/2025-04-02/rust-std-beta-powerpc-unknown-linux-gnu.tar.gz=0eef233c871404b913c6458d8005d362e3c24fcb0670ac49a7e67b1a503b4b29 +dist/2025-04-02/rust-std-beta-powerpc-unknown-linux-gnu.tar.xz=b96422b0f33446abee203160a22e9bac8861e1c7988b2cef463276743001fc7c +dist/2025-04-02/rust-std-beta-powerpc64-unknown-linux-gnu.tar.gz=18db97406a6e644734c7890991cb3006fabe1e1a185f89d108d28a992ed7c17c +dist/2025-04-02/rust-std-beta-powerpc64-unknown-linux-gnu.tar.xz=eea42655b5335643905acaa3d8ff1774e2c1a39ffde363c2073a8636c153087a +dist/2025-04-02/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.gz=5feaf6f3859204979fb4dab03fc93428abd103d61822d6e4e9a2f5d6d155213a +dist/2025-04-02/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.xz=98f8e695253c9dad3d82638bd69c084a3e7a96d17eb1dba0f90a42df993de864 +dist/2025-04-02/rust-std-beta-powerpc64le-unknown-linux-musl.tar.gz=e028f2ec967ecee5d9e7b48058209428ed220c5da2c00f2753f8d4e98951e168 +dist/2025-04-02/rust-std-beta-powerpc64le-unknown-linux-musl.tar.xz=69f508ffcb55347dbb773cfa22a1f7a6362f3aff6a48296b50945422ea82c7b5 +dist/2025-04-02/rust-std-beta-riscv32i-unknown-none-elf.tar.gz=ea30bf48fcb3873db4019ae3d248e1db868e1f7fc49e4549737aae58b3b49b22 +dist/2025-04-02/rust-std-beta-riscv32i-unknown-none-elf.tar.xz=c3724aaa58f812dc8283622f27e215546d8522b6ecdf1d191010dde3a1ba3344 +dist/2025-04-02/rust-std-beta-riscv32im-unknown-none-elf.tar.gz=9d24eb785b66796309c2f03944719fb6b6980ae8fb7ca97084fcfdea0094bcce +dist/2025-04-02/rust-std-beta-riscv32im-unknown-none-elf.tar.xz=f6b2233474eb64d041e6bd8f1b6dee3eaf775b6b5a7ddec703689352cf88f6a2 +dist/2025-04-02/rust-std-beta-riscv32imac-unknown-none-elf.tar.gz=8a5c94055180b9a1226a23c5992a622062ac52cddf91651a91a5d236be46d0c8 +dist/2025-04-02/rust-std-beta-riscv32imac-unknown-none-elf.tar.xz=7ea826d6c58fe1ef1c9374aef0cbfec5495daddcda581b231d18397330d9e248 +dist/2025-04-02/rust-std-beta-riscv32imafc-unknown-none-elf.tar.gz=811881bd5b514c89c316453ea1214fbeccf5388f18468cc83676a879d58f53ab +dist/2025-04-02/rust-std-beta-riscv32imafc-unknown-none-elf.tar.xz=9448b7bad586237faa4f090ce8c3de83b62d19fbe37104ae32032d9df709d2e6 +dist/2025-04-02/rust-std-beta-riscv32imc-unknown-none-elf.tar.gz=dd9252a03b0a888ee7598a84c20aac721739c2caf9c5b585274d2a30d7fcbcb6 +dist/2025-04-02/rust-std-beta-riscv32imc-unknown-none-elf.tar.xz=d1f134647fe0c3efcce80351cf9e4786ca8e3e336c0316b7c28ff07b78907c73 +dist/2025-04-02/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.gz=4f688c40457ba71542438fbc100b62b5f081435567f965512481ccf3d002826d +dist/2025-04-02/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.xz=a474fddf29c6979e0870c397c19f64de00650893a781eb51d9e136802bfabbfd +dist/2025-04-02/rust-std-beta-riscv64gc-unknown-linux-musl.tar.gz=7071209fdf0d2605b623ef96c934ed039d1dd95a68c438a8c563530ed48fb4e2 +dist/2025-04-02/rust-std-beta-riscv64gc-unknown-linux-musl.tar.xz=1328504e895dc9bbc36ac697bd5031e0034b2468fc66a91e42b39a4d35d4ea8b +dist/2025-04-02/rust-std-beta-riscv64gc-unknown-none-elf.tar.gz=e7878c1137279790205e62f9c363a6f45e2a8cd9c30702a53478a8104dc87a6b +dist/2025-04-02/rust-std-beta-riscv64gc-unknown-none-elf.tar.xz=f373b1d79547c385a01c2b36951eb3750a4cf3bcaaa213587af9a6b4274dc924 +dist/2025-04-02/rust-std-beta-riscv64imac-unknown-none-elf.tar.gz=4832338ebc25d088e30952605b3f6491d96003790df5b10c5c56e29ec69ac646 +dist/2025-04-02/rust-std-beta-riscv64imac-unknown-none-elf.tar.xz=d782dac690b3da2b96206809512f1ae82fb4a73ee387d91128ae0d98bf51ef3a +dist/2025-04-02/rust-std-beta-s390x-unknown-linux-gnu.tar.gz=faccf22845e31101a420796d9065b350092cbee29d755c2369ee36cc7172866f +dist/2025-04-02/rust-std-beta-s390x-unknown-linux-gnu.tar.xz=f296c5726380b1f2b8603a079e8dfdfa7e4a97a499b1e86874753c312768ab15 +dist/2025-04-02/rust-std-beta-sparc64-unknown-linux-gnu.tar.gz=b8a8fd8fda8b99d96d6f890bcd0c9073393441e85a4cda169b6fc7dbb7296984 +dist/2025-04-02/rust-std-beta-sparc64-unknown-linux-gnu.tar.xz=923a0530224f0631162f7b86bef79be85f45071f62ca4f5de0588fb5ca6affa8 +dist/2025-04-02/rust-std-beta-sparcv9-sun-solaris.tar.gz=944a83365d3c46313e28b1d3a5b0e52e57ce88b3eaaf0f7f53234d4423ce9ca7 +dist/2025-04-02/rust-std-beta-sparcv9-sun-solaris.tar.xz=be0c983c443f05feb4614d97336755894b3ffc5083d852bd84ee7cd9e5edfa03 +dist/2025-04-02/rust-std-beta-thumbv6m-none-eabi.tar.gz=08905a766352dd259be919aeb366e965dbbd4066c398dc4d26efa333b0ac46b8 +dist/2025-04-02/rust-std-beta-thumbv6m-none-eabi.tar.xz=4fa005107c3d1addb242179c03a804a27d34ca68bd76c092a41a197da56abce1 +dist/2025-04-02/rust-std-beta-thumbv7em-none-eabi.tar.gz=e6ccc1004004ed759b1814daae0b50a3a0adca9786688ef9cc601a0a19edc72a +dist/2025-04-02/rust-std-beta-thumbv7em-none-eabi.tar.xz=fc23abf9c086a34264bfcfe7c4876ec65ce54f8ca73a98020bb8eab6d2c51d57 +dist/2025-04-02/rust-std-beta-thumbv7em-none-eabihf.tar.gz=e8121551c0529f73796bc157bf916e3608685454a02a81d170a258a7465b5b7c +dist/2025-04-02/rust-std-beta-thumbv7em-none-eabihf.tar.xz=2695f76447ff5d70aa3cc6b6690267b31b9aa4ddc7c45205e529f92d234483a0 +dist/2025-04-02/rust-std-beta-thumbv7m-none-eabi.tar.gz=36d7fb4edd572c7d73501aab7c89737ee0036d606700c728f430142e91649eb0 +dist/2025-04-02/rust-std-beta-thumbv7m-none-eabi.tar.xz=a6e59eaed0ab3e310852d9a75fc43600c7c2eee0c808224b87bcb8c18df4ada6 +dist/2025-04-02/rust-std-beta-thumbv7neon-linux-androideabi.tar.gz=6bc70be43929b77f3508b1872e5b09227aebce1c7c9c943995b5df92cf6d9181 +dist/2025-04-02/rust-std-beta-thumbv7neon-linux-androideabi.tar.xz=37b956924534aed1ae7ef9908d38bf724c6903591269136d23e293e17a0d333f +dist/2025-04-02/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.gz=041562edada0caeea67fe7f3ffb5b9f8c1b506c0d5ee7b657c5ee2afbefba7fa +dist/2025-04-02/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.xz=8980372a7e9a072b1e0b954569e59df260583a3371daf005c5a83576688562d1 +dist/2025-04-02/rust-std-beta-thumbv8m.base-none-eabi.tar.gz=83f461ac0ebcc05d5cbf67a6585b49dc7b245c8788dc3a75e08a93be41e2615f +dist/2025-04-02/rust-std-beta-thumbv8m.base-none-eabi.tar.xz=6ac8847ce601c8dfeffff07915de06a605b3c685f81b90f87b092897c2afb973 +dist/2025-04-02/rust-std-beta-thumbv8m.main-none-eabi.tar.gz=bfcd9ff7dc9bb5e95bd563d750240efcbc3bfa1a21a9f9a2786ef37f665b7e43 +dist/2025-04-02/rust-std-beta-thumbv8m.main-none-eabi.tar.xz=4507383395a26d41abd71041b162dfc5e9471a4c624d9fd6ad310e184ef15d01 +dist/2025-04-02/rust-std-beta-thumbv8m.main-none-eabihf.tar.gz=b4d1940ea5e24cd6a0ba3906c98d2b03e4a18927619152b43e91832733316258 +dist/2025-04-02/rust-std-beta-thumbv8m.main-none-eabihf.tar.xz=45eec7770344beb84cf418cf7818216d123136465785f4742127f6f5a8c5ce27 +dist/2025-04-02/rust-std-beta-wasm32-unknown-emscripten.tar.gz=19bf2f4bf64f874ccfd84b820b7200e83e896c96a396edd7bd10301d2bc89d98 +dist/2025-04-02/rust-std-beta-wasm32-unknown-emscripten.tar.xz=4c616b7bd972c09461f0bccf5009bc574dcfa8bdce2dd97d17fcffd64542e496 +dist/2025-04-02/rust-std-beta-wasm32-unknown-unknown.tar.gz=69bcb61fd0f8bd7d2da225a4525a877cce003afd7fc3d789c385f164959cd41a +dist/2025-04-02/rust-std-beta-wasm32-unknown-unknown.tar.xz=0372a64eda0c7249ce5fbcbbbf29e145e969b383a73b7c470f0b583720fcdbe2 +dist/2025-04-02/rust-std-beta-wasm32-wasip1.tar.gz=f76a2a3f4702eb781a680ebd4346afb4c26ca2235e62bad144b057860c09b8a8 +dist/2025-04-02/rust-std-beta-wasm32-wasip1.tar.xz=173bc3317b59a01036a9c8e0bccc570fd6f5174d15f94634f53d81dec3d2cd68 +dist/2025-04-02/rust-std-beta-wasm32-wasip1-threads.tar.gz=18e05380478ed0b3f76d9062fade2be2e66c039dcc470ffb01be3c8dffc79995 +dist/2025-04-02/rust-std-beta-wasm32-wasip1-threads.tar.xz=3d477eb85308f73d1081d6dd3e54577be4bd84f291a50af0e3be15fa8aa36db6 +dist/2025-04-02/rust-std-beta-wasm32-wasip2.tar.gz=3444883960a9f8b831d1f26ee17ef082a2029cdc2e9b45ce5af4d6565d3a526e +dist/2025-04-02/rust-std-beta-wasm32-wasip2.tar.xz=867361c7ba912b404c426807a60625a1f830707a172f7da139c1a892aa85bf35 +dist/2025-04-02/rust-std-beta-wasm32v1-none.tar.gz=d15017a323c662a1e8c65f51e66151138c2255cd8842a67e990000606dac839f +dist/2025-04-02/rust-std-beta-wasm32v1-none.tar.xz=f3b32484ef287317187ca0bd5245b1793ae40d50290a2882419da8503b8243f3 +dist/2025-04-02/rust-std-beta-x86_64-apple-darwin.tar.gz=179be6a29fcf16b4c18775208569a051f2f5a38558e751d2dda0a42027868843 +dist/2025-04-02/rust-std-beta-x86_64-apple-darwin.tar.xz=912f7f8d7117a5cac85dffee5ffd9f2c1cf237477bb0f9e1127afff1f0cd4757 +dist/2025-04-02/rust-std-beta-x86_64-apple-ios.tar.gz=9d2f3230bd82ba9d45e572b45ec63c63cfb592dba6311b6a16de075f18c86999 +dist/2025-04-02/rust-std-beta-x86_64-apple-ios.tar.xz=c8ff77db2d081444ab5167764465beb33046cc81cf2e8dbbd8e9a7328306762c +dist/2025-04-02/rust-std-beta-x86_64-apple-ios-macabi.tar.gz=76c9b2ae710fed611a2294a5e4bb6597b07d78f0bbd3a5a0d15c3320f38a0017 +dist/2025-04-02/rust-std-beta-x86_64-apple-ios-macabi.tar.xz=b9c485a3824c971a42c10af26cf06c539c34fa429e92601a1978280867029e62 +dist/2025-04-02/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.gz=a223c08b88c768d97bf9f071c74d9548acf00bbb097b8c8427c2ec87ca205597 +dist/2025-04-02/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.xz=34ddb3db8a71edabb4d0fd8d52a164dbca5a5cd96d6ba131e7d439c333726f78 +dist/2025-04-02/rust-std-beta-x86_64-linux-android.tar.gz=9ba28bf95c75ca0d69461d1c044902443053b64678b540967a97c7cd2eb7cc4c +dist/2025-04-02/rust-std-beta-x86_64-linux-android.tar.xz=09e35188a801371a55abeb9e2ee455ebd26d41b8eb561b8016ecacfc7ba20c90 +dist/2025-04-02/rust-std-beta-x86_64-pc-solaris.tar.gz=c1f2fb4b90cf258dfa1a52167ba925b583dc889ec1c3c48958560ff3b7b79b13 +dist/2025-04-02/rust-std-beta-x86_64-pc-solaris.tar.xz=d71f2bade21f751d9592e865ce3722b5d3b9abc49e55ca9d04c02d658360b6ad +dist/2025-04-02/rust-std-beta-x86_64-pc-windows-gnu.tar.gz=691c23504582e6db1cf883f52b5378aad3c42da7e2d2237e54601be9c8d16cac +dist/2025-04-02/rust-std-beta-x86_64-pc-windows-gnu.tar.xz=22e7327c5ba22863cb62cc5331862b8c2b4b10a732637729b5e1504034aa2cf1 +dist/2025-04-02/rust-std-beta-x86_64-pc-windows-gnullvm.tar.gz=81b7dda817a7dbc8b33542c356e0c5e5605b7c60a2fee13f4a266c8d970a3f54 +dist/2025-04-02/rust-std-beta-x86_64-pc-windows-gnullvm.tar.xz=09e4c9804f7489b337ccf66426e18e7522dcba24234b289a39eb63c8242353d0 +dist/2025-04-02/rust-std-beta-x86_64-pc-windows-msvc.tar.gz=a8188567321462309fb63af38f652c6a7448ebaae1425b9ec20d2fe2a12e8896 +dist/2025-04-02/rust-std-beta-x86_64-pc-windows-msvc.tar.xz=5284f85dce61b2b021888b6b82995aa7b4a14a979b42b83499a810c261fc183e +dist/2025-04-02/rust-std-beta-x86_64-unknown-freebsd.tar.gz=eb57c8ca7f515386d60a88e56443e377aae70e185ac52a62869e115c636a2bcc +dist/2025-04-02/rust-std-beta-x86_64-unknown-freebsd.tar.xz=8bef59b74196fa9f7839bb491f6b32d0761a45c8d7178980ee3afd80231b836e +dist/2025-04-02/rust-std-beta-x86_64-unknown-fuchsia.tar.gz=f43f402881f4558e3df4a7ace68ba80caa9354cfa5a8b1efac89f95e38386253 +dist/2025-04-02/rust-std-beta-x86_64-unknown-fuchsia.tar.xz=ea7d09c015c057591ff51b808cca9c8c1d973de3a9033fe42c1bf34d748d03a6 +dist/2025-04-02/rust-std-beta-x86_64-unknown-illumos.tar.gz=a4835455348bc5b154b1bba63aa03d2294713589214b50d3babae3e0f9918a3c +dist/2025-04-02/rust-std-beta-x86_64-unknown-illumos.tar.xz=711920e7491332251fb672abdc7685fa940f863d8e182e2ae9d9347d7fa6a725 +dist/2025-04-02/rust-std-beta-x86_64-unknown-linux-gnu.tar.gz=1b8324839c0e10e410f29bd471f6c49eb4710adbe172d6bef3e619ae95d47d02 +dist/2025-04-02/rust-std-beta-x86_64-unknown-linux-gnu.tar.xz=223b41f16a80b9c404f5af9a194b7414ef354681f911839353f24b44eed91494 +dist/2025-04-02/rust-std-beta-x86_64-unknown-linux-gnux32.tar.gz=6d8d8d9fd6336de0ebcb58fa85aa0d11e62a60d6c6ca01d71da0bdf668d216c1 +dist/2025-04-02/rust-std-beta-x86_64-unknown-linux-gnux32.tar.xz=033df93011b4461cde64c4230c495bad1523b9b38f5b0de56dd928c1da85b577 +dist/2025-04-02/rust-std-beta-x86_64-unknown-linux-musl.tar.gz=70a441c0cf8ca25abc1f722c1db5dde8b5fd3b90c767895b7518fc58c2678390 +dist/2025-04-02/rust-std-beta-x86_64-unknown-linux-musl.tar.xz=b5584d6d0031f8230a40f5ed76570ab1396c8997c3e957ca159d72a5dc201a2d +dist/2025-04-02/rust-std-beta-x86_64-unknown-linux-ohos.tar.gz=2596cdc3708d82aa93a8a1f595238fe9fd7b5b05a4886e7e390ca3b86d352e7e +dist/2025-04-02/rust-std-beta-x86_64-unknown-linux-ohos.tar.xz=c03901c0c8434b5db244c22145870e7d933b9060af3b23f24a765c755098a3a1 +dist/2025-04-02/rust-std-beta-x86_64-unknown-netbsd.tar.gz=82bc22594dc602b27edf8233bd9c4fbf0323999ce99ff2a7ddd0ce9268647eb1 +dist/2025-04-02/rust-std-beta-x86_64-unknown-netbsd.tar.xz=86f674f5e19a1b1780f06a6d5add06fd4240430233b7c3f5203a4daa5f444673 +dist/2025-04-02/rust-std-beta-x86_64-unknown-none.tar.gz=ca7882354f4274dc405034aa6edbda685b9d76bc6e5905074d2aaf8c35b35a95 +dist/2025-04-02/rust-std-beta-x86_64-unknown-none.tar.xz=ed6c828fdafcf87a68f522379f11c44eff1a4be1bf027d9888d1f17f22e9ca61 +dist/2025-04-02/rust-std-beta-x86_64-unknown-redox.tar.gz=6f8ab182274e2f5b0fa82fdc5c6e3776ba969e6ee6f6098ce6d170f6685f55c2 +dist/2025-04-02/rust-std-beta-x86_64-unknown-redox.tar.xz=ee061d725f657a2e52114f282be0cab1a6e542a0270b11782c36e8737ed84f32 +dist/2025-04-02/rust-std-beta-x86_64-unknown-uefi.tar.gz=0324f537f463738bbdbf40b92423df6c6068f76c583872d6070d6a41c5169dac +dist/2025-04-02/rust-std-beta-x86_64-unknown-uefi.tar.xz=2cd2727f71b14c06eb0a14fa532e5b3bc66f8b983c021f3201c327606b04511e +dist/2025-04-02/cargo-beta-aarch64-apple-darwin.tar.gz=76010b5a9f8dff0102a18de75e818c51b915a3bcff428fc48973728577c2ecd3 +dist/2025-04-02/cargo-beta-aarch64-apple-darwin.tar.xz=f0f03ece675cfaa9dd0f00204d7ddd4086a45357f09cac9d800d37bef8d0db33 +dist/2025-04-02/cargo-beta-aarch64-pc-windows-msvc.tar.gz=bf4ab12afcea7911ab973177de83b7bbdfd0000e3090331f31a595d57819ed6d +dist/2025-04-02/cargo-beta-aarch64-pc-windows-msvc.tar.xz=156fc94166e5f2af91fd9a36c67b545c0eff63dad51fcd81571cce01447c1c1b +dist/2025-04-02/cargo-beta-aarch64-unknown-linux-gnu.tar.gz=c86bbf8091188ab9f7d41e566ef628a657d66683884333c3851e99edaea6e279 +dist/2025-04-02/cargo-beta-aarch64-unknown-linux-gnu.tar.xz=610383a4efb93ab53cc747ba038888742346499407c982b7bc8c0c41689cf453 +dist/2025-04-02/cargo-beta-aarch64-unknown-linux-musl.tar.gz=7d427779360c9cba5903c2a0183be1c1759cb2c2f2b77bd2f64b409821fabb64 +dist/2025-04-02/cargo-beta-aarch64-unknown-linux-musl.tar.xz=29bda8bd7dcee65315b8c14a527f4e4b4dd678b35dd430591f7c71712ecbd2f9 +dist/2025-04-02/cargo-beta-arm-unknown-linux-gnueabi.tar.gz=ef6d6a810eecb3a38940634b653257070dcfcff52c2d8321fa3a933d41c7ed73 +dist/2025-04-02/cargo-beta-arm-unknown-linux-gnueabi.tar.xz=79796d83949811776aaedc7e6db6d32374c07b8f8d256d9b871de335bf5e7074 +dist/2025-04-02/cargo-beta-arm-unknown-linux-gnueabihf.tar.gz=fa93a1285a97453e2aaaf9cf392abb4ff9a419451e925959470166522e54b1dc +dist/2025-04-02/cargo-beta-arm-unknown-linux-gnueabihf.tar.xz=acb69df00475904faccf18729030a70e8ce21543189d48c7102330a98a12edf1 +dist/2025-04-02/cargo-beta-armv7-unknown-linux-gnueabihf.tar.gz=7141bf32c173d26f34571b2dfb890187d866f113e28b63908841377e48dbc6ab +dist/2025-04-02/cargo-beta-armv7-unknown-linux-gnueabihf.tar.xz=249f3c535805fb2510d13338401e9ae96f16e6996e58551025b35676a1147ab5 +dist/2025-04-02/cargo-beta-i686-pc-windows-gnu.tar.gz=fe4f5f35ecac25bc3726ffecbe3e650d51adb9ea13dc5153a0699ea8d8776d13 +dist/2025-04-02/cargo-beta-i686-pc-windows-gnu.tar.xz=b7b8432464eb793e9a651c4c38ee8abe76421a9be7f75e96237a4ef938f927f9 +dist/2025-04-02/cargo-beta-i686-pc-windows-msvc.tar.gz=a283da65d3a75435ff3d05441fd0337472fd16325531086e90b01cc5d5bd221a +dist/2025-04-02/cargo-beta-i686-pc-windows-msvc.tar.xz=ae19f98c901228ae5c7573cebde4816517bdb8d03dbdc7b92d95518d27d93531 +dist/2025-04-02/cargo-beta-i686-unknown-linux-gnu.tar.gz=e3c5b2560f64c8056ef82ed0cd659d35fda5181f19fa670b962228142398efbc +dist/2025-04-02/cargo-beta-i686-unknown-linux-gnu.tar.xz=3fc435b8a186f6ec1b7ebc38c92c2e23e1bd786415fc33e7743ef95c37c69b45 +dist/2025-04-02/cargo-beta-loongarch64-unknown-linux-gnu.tar.gz=bcab46663be61e979b7a89792d164e182d5482ad9b444a969dbb304c5dad8c8c +dist/2025-04-02/cargo-beta-loongarch64-unknown-linux-gnu.tar.xz=9e2ecb90d85a4aca95211892a6a41fde09ce1e4f44a60caab9aeb61833191d36 +dist/2025-04-02/cargo-beta-loongarch64-unknown-linux-musl.tar.gz=3c5c40f61e85663d03fe51f63d505d8dca73f94bfb3eed29f6e1396b31e0a554 +dist/2025-04-02/cargo-beta-loongarch64-unknown-linux-musl.tar.xz=775c56ce638e0923758ab5f82a87c15b7a1500d10e0be2433af40364a0455d58 +dist/2025-04-02/cargo-beta-powerpc-unknown-linux-gnu.tar.gz=c1a144dc83b673e0375e8f718cde6672ca276dbab9161d7f3e002c6273352c1b +dist/2025-04-02/cargo-beta-powerpc-unknown-linux-gnu.tar.xz=1b41b3396340c97c122661c95fe54265036e721f1750bad3a8fe4920f6f52b34 +dist/2025-04-02/cargo-beta-powerpc64-unknown-linux-gnu.tar.gz=2a43a7682ea3da8b911b09a7bb4a3a75fc3facb64fc952e51ff35c63e6630b75 +dist/2025-04-02/cargo-beta-powerpc64-unknown-linux-gnu.tar.xz=73a3383196527e63716de1b1cab233226519873556a755a7e47279f799936116 +dist/2025-04-02/cargo-beta-powerpc64le-unknown-linux-gnu.tar.gz=d5f521839bd4b258454097cf97b056508e6f9103f7312c93b632ae44ac9f7dc0 +dist/2025-04-02/cargo-beta-powerpc64le-unknown-linux-gnu.tar.xz=c4fc5ff91bc1054e8497efa53ee6a9a9eb7f06927cd314a681e16b6d46b08440 +dist/2025-04-02/cargo-beta-powerpc64le-unknown-linux-musl.tar.gz=5b0d569fe4ec84d6e7526af9d9794b440e8f1b5fc1b09e951678b09fd3ff97fb +dist/2025-04-02/cargo-beta-powerpc64le-unknown-linux-musl.tar.xz=e9c68eee5763c624cbe312bc1b50b6c3172eb7997e209371692e7f897d13b03b +dist/2025-04-02/cargo-beta-riscv64gc-unknown-linux-gnu.tar.gz=96962461e7f6744a46f18a557a4701d35d6fa3b6d960d854f4c3effe6f2636f8 +dist/2025-04-02/cargo-beta-riscv64gc-unknown-linux-gnu.tar.xz=4d6029204f930543afeeaf44d9e635692c86c9daaaac6301cccbe076c7facbe5 +dist/2025-04-02/cargo-beta-s390x-unknown-linux-gnu.tar.gz=f40421ea02804c3089420e5ca13838f94fb89c114de9a9e596e9a1207d2166d7 +dist/2025-04-02/cargo-beta-s390x-unknown-linux-gnu.tar.xz=77521eb215cded6886267644661b3357590f20368383f314da8f310197e9679e +dist/2025-04-02/cargo-beta-x86_64-apple-darwin.tar.gz=0357ed5c9c8ccbe71f89695bffe1604dbd2f451472fc6ea8d8d2dfc93a703b30 +dist/2025-04-02/cargo-beta-x86_64-apple-darwin.tar.xz=6ce4f66b60609f58046138831ae3828ad1d58f8d0b2f515f153c96b690a0134f +dist/2025-04-02/cargo-beta-x86_64-pc-windows-gnu.tar.gz=8fbf8506fc0c47bb30043c026107c51d6b548fa91320b5bbd2c608e191bdc007 +dist/2025-04-02/cargo-beta-x86_64-pc-windows-gnu.tar.xz=bb57df35e6d73b0b0bba58801d66febfed03f0b3f74085eb50ef8b5ea3fdbb40 +dist/2025-04-02/cargo-beta-x86_64-pc-windows-msvc.tar.gz=0bec5e9059c4b3035f636017c1586653d372f03969bcd4d80c0eaee52f01a2ac +dist/2025-04-02/cargo-beta-x86_64-pc-windows-msvc.tar.xz=3f836d3027d7ed25655f43262b126311bf014629dadc4a860f00302bc468e752 +dist/2025-04-02/cargo-beta-x86_64-unknown-freebsd.tar.gz=0f60566416471c38350c12f066bb512eca65a66319f5ee7fdbb60464d70661fa +dist/2025-04-02/cargo-beta-x86_64-unknown-freebsd.tar.xz=eae168df54ddfe95db669c205ae97baa902056722856fa174758ebd058168a95 +dist/2025-04-02/cargo-beta-x86_64-unknown-illumos.tar.gz=816eb91ac3858043f58075fc48fc2e90d0427c58b6283be589d337a7f0ddc9df +dist/2025-04-02/cargo-beta-x86_64-unknown-illumos.tar.xz=faba548d376309b71bcdae49f7089705be951f72a84ef68362aa6d865d40ebf9 +dist/2025-04-02/cargo-beta-x86_64-unknown-linux-gnu.tar.gz=1fe7e9d2c5a733acdaed418011c1fc31c3036e5299e8f9288ddeac43780fa35e +dist/2025-04-02/cargo-beta-x86_64-unknown-linux-gnu.tar.xz=7a39bd08e46d3e19da81c02ea3bb46bd1750a3ac1d1db8fb5db852cde14cdd72 +dist/2025-04-02/cargo-beta-x86_64-unknown-linux-musl.tar.gz=00df62b75e1811fd4fcc827b531e7ad94a73fcc37318d0aed28796d902b33568 +dist/2025-04-02/cargo-beta-x86_64-unknown-linux-musl.tar.xz=874084ab37814ddf50ef423e22f0721e5c24acd953ed02cf83432d2372606a5f +dist/2025-04-02/cargo-beta-x86_64-unknown-netbsd.tar.gz=7b4467e398bd34f94912c56863ae83b45415bbf612b3be15624a6a410c27ff2a +dist/2025-04-02/cargo-beta-x86_64-unknown-netbsd.tar.xz=75e7ac498a8e617bb907c26f2a3bba9a1e9a22af1c0946f88c7bd53c28790ffb +dist/2025-04-02/clippy-beta-aarch64-apple-darwin.tar.gz=0f5a8a6a96b8785beae1fc9476374d060632dcc4c17a4335031425ee8e2dec48 +dist/2025-04-02/clippy-beta-aarch64-apple-darwin.tar.xz=aed266be1799ae3e95099d491c3b20b731b2094bc8388c6ac3e782667b58ca6f +dist/2025-04-02/clippy-beta-aarch64-pc-windows-msvc.tar.gz=0ca97501432918d43aa9bed9b58cd4f1d0d738970e09d6c037ce967519b2b13f +dist/2025-04-02/clippy-beta-aarch64-pc-windows-msvc.tar.xz=c64edd87358c1ecb9e01b204977edaf0307cc939a3dd3ae62f151c153ac2019b +dist/2025-04-02/clippy-beta-aarch64-unknown-linux-gnu.tar.gz=7bfdd371ed44a32e50ecd6baf107796d5a77ca3cce0bd58bc5882afd98ca0edf +dist/2025-04-02/clippy-beta-aarch64-unknown-linux-gnu.tar.xz=cf49acab8153fb65867a9c44eabb7f156f85e9818b6f49453067ce0764036919 +dist/2025-04-02/clippy-beta-aarch64-unknown-linux-musl.tar.gz=bfb20f832ba30a4840f0d4898d27cf69b5717a78bd71b20270f8ddd66c48bc69 +dist/2025-04-02/clippy-beta-aarch64-unknown-linux-musl.tar.xz=54081690d35c39267a49d991e5e0c16043261b6969c49f23c2be44e46c3bfcdf +dist/2025-04-02/clippy-beta-arm-unknown-linux-gnueabi.tar.gz=3d88b69d6c67c58b09be9d679cfbe8ee449b9de419e950edcffd4637ded46cac +dist/2025-04-02/clippy-beta-arm-unknown-linux-gnueabi.tar.xz=67843ea0aeaab167029818669074e8bdc46a7e1c269a15580cdfe44a7d2ba96b +dist/2025-04-02/clippy-beta-arm-unknown-linux-gnueabihf.tar.gz=46e9efe50418a035ddabf9a6467b6b0ef20453816c4b6dfd46fa1342bdc42167 +dist/2025-04-02/clippy-beta-arm-unknown-linux-gnueabihf.tar.xz=3b27dc434e88280bbc89f5c5ba6eb68ec5332b549b73f7f8d79feda9cbb49628 +dist/2025-04-02/clippy-beta-armv7-unknown-linux-gnueabihf.tar.gz=670a6ce01ee6e5225b152a1357eba9a41cb47f04d08cdc8a0828eded4132aba1 +dist/2025-04-02/clippy-beta-armv7-unknown-linux-gnueabihf.tar.xz=cf92bed8c784e9579c09305fd227df3992950c227bc844a9b09995828d62e2cc +dist/2025-04-02/clippy-beta-i686-pc-windows-gnu.tar.gz=58238b6f4f8ad957a39c0eb63b45007d1c3f8c79e98307c7e5a531b7309a30f4 +dist/2025-04-02/clippy-beta-i686-pc-windows-gnu.tar.xz=e77c5215b3e96c59fa150330cb5144db66dac377fdad3be9c28f9fa07d9fb7cc +dist/2025-04-02/clippy-beta-i686-pc-windows-msvc.tar.gz=7c65df8af1f6f4102ffbd7fdaec50c24f89f2631edd06642732f1b5c74558ab4 +dist/2025-04-02/clippy-beta-i686-pc-windows-msvc.tar.xz=eeb119d26e1e2ddd3ef72741158d75d0db254f6420fd729d34abe5d172c7d765 +dist/2025-04-02/clippy-beta-i686-unknown-linux-gnu.tar.gz=c43518b27adce17f06f89c70ab52ae4c94f1f7129a182c16f9bb28fbc8a5f40b +dist/2025-04-02/clippy-beta-i686-unknown-linux-gnu.tar.xz=1d972c55d89cc01b7e408b4e24e8975bca29ff28578f224024a00f00d17c28b8 +dist/2025-04-02/clippy-beta-loongarch64-unknown-linux-gnu.tar.gz=0d779bd9fcc5ed8e1db81a3a385bc0158c3903e5b0f0e4c99d172eee106a4f3e +dist/2025-04-02/clippy-beta-loongarch64-unknown-linux-gnu.tar.xz=5515e0678c081ddae45f3f0c3c7ae58cc2f7b1141e1557a39826bf1aa58a2480 +dist/2025-04-02/clippy-beta-loongarch64-unknown-linux-musl.tar.gz=e99599c1fd0cab2eb0e89dd8e37e90ee2106d602a3edb3473fd65768bb8f7b27 +dist/2025-04-02/clippy-beta-loongarch64-unknown-linux-musl.tar.xz=f346a801dee3734461eab4303469d31faaf3e8f0d733b854470722ed48c66276 +dist/2025-04-02/clippy-beta-powerpc-unknown-linux-gnu.tar.gz=cd7b58e507d6695ada446ef9fa113a9588501832f4627b3e7cc0000a77c9265f +dist/2025-04-02/clippy-beta-powerpc-unknown-linux-gnu.tar.xz=0a7073874663b4ce8eb47a0257ac0cf8049acb34703241466f1208489c4dbee0 +dist/2025-04-02/clippy-beta-powerpc64-unknown-linux-gnu.tar.gz=78d0b9581a7d79549bbb6a7e8984bf923a7b80bf6bb3979a90e90ceed8e66d33 +dist/2025-04-02/clippy-beta-powerpc64-unknown-linux-gnu.tar.xz=79069a26ed617a2a07eef7cf098d028cb0c172fc4a6dc99115a51862b1b8bea8 +dist/2025-04-02/clippy-beta-powerpc64le-unknown-linux-gnu.tar.gz=23c58421839105c88937ad90a92603b7fcd6d9e21f291ab8c419fce1663a20a5 +dist/2025-04-02/clippy-beta-powerpc64le-unknown-linux-gnu.tar.xz=b546706d28c46f5bd3799d6b42201962ec2e9d6baf8df2b66cfcf1bc42789036 +dist/2025-04-02/clippy-beta-powerpc64le-unknown-linux-musl.tar.gz=31cf0d973eb3f0ca341a8d64c26b8b3b045b44b3c00d2497893dac6e44ebdeb4 +dist/2025-04-02/clippy-beta-powerpc64le-unknown-linux-musl.tar.xz=8afd89866c41631d4f4ac4d8a06d943473af7a96b043f6112216a04863817820 +dist/2025-04-02/clippy-beta-riscv64gc-unknown-linux-gnu.tar.gz=f08bf4ed1519e7c47f354a0d0b750933342314bacd4be761746666cf455cf74b +dist/2025-04-02/clippy-beta-riscv64gc-unknown-linux-gnu.tar.xz=e502f83f811c35e43df0a5e158d9eb61f60c9e1aacc75b588b2ba85022ca4b3e +dist/2025-04-02/clippy-beta-s390x-unknown-linux-gnu.tar.gz=21bede57083544028238ef6c9d24cbf9194a35c88500f2d0c5d50e6f0ae79616 +dist/2025-04-02/clippy-beta-s390x-unknown-linux-gnu.tar.xz=670c0a293e1b01f331c2645b648c1df087da4c1b5d689f608279b1ba524cbaef +dist/2025-04-02/clippy-beta-x86_64-apple-darwin.tar.gz=a6552e032c047203d5a9f5b767945c7a556be35468c42631c0c84cd049e24a8a +dist/2025-04-02/clippy-beta-x86_64-apple-darwin.tar.xz=17a9e9ea8e0d6140080b7fa4e3c77ad1a7fde3c3179f26b0aabe34c3af73b58a +dist/2025-04-02/clippy-beta-x86_64-pc-windows-gnu.tar.gz=2ffa8663502f4c6bba049318c70e79c174fd717d45ab4427103fc11563be678f +dist/2025-04-02/clippy-beta-x86_64-pc-windows-gnu.tar.xz=8c0a71f226b229f30a9acfbc1ab7c6bbedf692ef7b26737721a0518d3f1972ab +dist/2025-04-02/clippy-beta-x86_64-pc-windows-msvc.tar.gz=463c7a5d2a11beaeb1e63bc769db89fb9996a0558da15b4e091befe982893711 +dist/2025-04-02/clippy-beta-x86_64-pc-windows-msvc.tar.xz=40241fa6e463df734096e0e910b414c83d8a4dc8706b7c712cc170844e59e3c6 +dist/2025-04-02/clippy-beta-x86_64-unknown-freebsd.tar.gz=6464044b05b326d8ea594a963e38a52a1e27e0f028704427c41ec5e93e3772d9 +dist/2025-04-02/clippy-beta-x86_64-unknown-freebsd.tar.xz=77cdeb1e838c3da1d01252481f7c06149b0b8e7df48c2a2ee5961f4550d7b662 +dist/2025-04-02/clippy-beta-x86_64-unknown-illumos.tar.gz=d51238e1ad2329b9309e94b40f3374788e2fda9bf47466841a841392835e8a5e +dist/2025-04-02/clippy-beta-x86_64-unknown-illumos.tar.xz=6ad33945045790946fae843f63a805e60c09157e106ff342d3b99a201cd221e1 +dist/2025-04-02/clippy-beta-x86_64-unknown-linux-gnu.tar.gz=64b4f85d9eb75172928b46540090128ce9eec00e275d9027f74d0d5d4106bd76 +dist/2025-04-02/clippy-beta-x86_64-unknown-linux-gnu.tar.xz=b090383b4ebeae96fb340f0a363ee0276eb1f17a4f2a0f2ed81aff039f21bf78 +dist/2025-04-02/clippy-beta-x86_64-unknown-linux-musl.tar.gz=8d8025922c563bb1c872111722a4de298a8f85cd5be3e4cf753d44d6b8304de6 +dist/2025-04-02/clippy-beta-x86_64-unknown-linux-musl.tar.xz=ecf15ae9eb7dafe97afd69133f13364dac09d5e6edc35ddab91fb4ac32e17d42 +dist/2025-04-02/clippy-beta-x86_64-unknown-netbsd.tar.gz=c802af6a6f454b771046bd4a5207bdbe538cb6827becc9174dc229de5f874426 +dist/2025-04-02/clippy-beta-x86_64-unknown-netbsd.tar.xz=03d1e16eaf6f83f80e4cef8c7beebee97498135dd3138b97f97186b545edfb86 +dist/2025-04-02/rustfmt-nightly-aarch64-apple-darwin.tar.gz=c02047132bc7b48bbe930dfddb3afd31349eb042cb101a19d6e4360ea6e586ad +dist/2025-04-02/rustfmt-nightly-aarch64-apple-darwin.tar.xz=cf825dfaeb4d97eb2819ff8e46360192f480960f6b516e328ef8a9493d413a9f +dist/2025-04-02/rustfmt-nightly-aarch64-pc-windows-msvc.tar.gz=588551cbfb62eb4ed4e5755fe6eb3e1499a79e24a8a75f448b10d9a2237c63db +dist/2025-04-02/rustfmt-nightly-aarch64-pc-windows-msvc.tar.xz=df666f179fcfccb316aeb1a5eb4c17710b23198176edb34ba8b98c88cb369098 +dist/2025-04-02/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.gz=b06f4aefa01300ef1827a29c9fcd2e4da0c13f3aad92b4c929f6e8811d53ab71 +dist/2025-04-02/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.xz=059a888b8db76f5a3054a9a78a131d79c49060deaf70b2e2f03a4fcab44ab536 +dist/2025-04-02/rustfmt-nightly-aarch64-unknown-linux-musl.tar.gz=f0117a7be9eefe70fbd2f0d3fc05c51f3a97d069dc99500520a5d0973178fc6a +dist/2025-04-02/rustfmt-nightly-aarch64-unknown-linux-musl.tar.xz=f2fa87f1e814d0fb163146cf6a47d9375fec2c3778f76c33988acaa1665dacf7 +dist/2025-04-02/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.gz=fa53d4a6fb2ee3e1607d825afcc05063c0fa0dda1a3ede9a57e1ccc72cece8c4 +dist/2025-04-02/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.xz=3d785d982878f9bda4778cca0f9365947665849d5f7d2ee4794d8c28df3ab8c8 +dist/2025-04-02/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.gz=affb343357cd4c677cdeaf3b24698f20cfa15062cb63257aaa9bca3bd7baeeae +dist/2025-04-02/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.xz=6eb95c2021571a0c1ad3e3edf58fa4daa7711a9085e2ab61bc75799252183358 +dist/2025-04-02/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.gz=1dffc39afb9210c77e6d45b68cb801247f00afdf33107963c82a83bd94d2225e +dist/2025-04-02/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.xz=2da28dd8ec76744a7629619f527196689eb35e9bc60f3a5965ed69486e44235d +dist/2025-04-02/rustfmt-nightly-i686-pc-windows-gnu.tar.gz=5b1b39125106cdcbf12be9d5786900852f54eaa1429cabf28eeb68f96a008f90 +dist/2025-04-02/rustfmt-nightly-i686-pc-windows-gnu.tar.xz=3f2ecb3787c82a8dae89929aca4f2f3af790f1ab3c698adf21dde21c919a4052 +dist/2025-04-02/rustfmt-nightly-i686-pc-windows-msvc.tar.gz=eeb8b3f10f1cd75fac4e9e13dd1aee5941f38f1ff7fcfcaa69fcc3a42ea7c49a +dist/2025-04-02/rustfmt-nightly-i686-pc-windows-msvc.tar.xz=afd81cfd8d5fb37427c7eb2a1429c3b06d8daa1f42002c7230718fc56e132c47 +dist/2025-04-02/rustfmt-nightly-i686-unknown-linux-gnu.tar.gz=5eb0f065a5403645ebb6c01d7f27a763f9446b8a48db5b6ff962b6f7c0f3ea3b +dist/2025-04-02/rustfmt-nightly-i686-unknown-linux-gnu.tar.xz=3576e2e8ecc563cfbc4b3f464d80f8e27f412b5eb267656dc5f0316a11a2d299 +dist/2025-04-02/rustfmt-nightly-loongarch64-unknown-linux-gnu.tar.gz=5e69db53a1161ad7616f9e50d1a7fef785840bdf0ba81757d0b6811078692921 +dist/2025-04-02/rustfmt-nightly-loongarch64-unknown-linux-gnu.tar.xz=ba9d18dd2d63bad1e2863c9e14bbc4bd282d03cb806d03011d2d61ce701d934f +dist/2025-04-02/rustfmt-nightly-loongarch64-unknown-linux-musl.tar.gz=b112f8c2e6ec011382c02a40ca07f30e1885a1396a7f2c30f099e56d756f2f54 +dist/2025-04-02/rustfmt-nightly-loongarch64-unknown-linux-musl.tar.xz=42af68aa0b77306187d13ef881ee4327856f505a8a518f46244ffb17037f7e4e +dist/2025-04-02/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.gz=ed4277c9c8a27fdb97911bb9fbb46385b5fd807ac9338d31eecc3240bb0bc5c2 +dist/2025-04-02/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.xz=4cf3a7a64edd09b5d8ad72af545c15013842072e70789d1741f845f27c60566d +dist/2025-04-02/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.gz=65d49556ac1abd1da9cb7c41e518f85213ee2b1f05559c917614937d4c0cada9 +dist/2025-04-02/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.xz=535ea938d888ea12c139740e5d25ac4b82135b3274b8d86c3c59e36928922ec6 +dist/2025-04-02/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.gz=9776e0c641ae8a229453fe1fbdaaae05ea0caf37bb4893a00fe86e5d63d1241a +dist/2025-04-02/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.xz=bf73cfd35802b2706d0db96c854e8a4c45398297a59aef92226ac28d8bb69417 +dist/2025-04-02/rustfmt-nightly-powerpc64le-unknown-linux-musl.tar.gz=307012d0741898b3a2840ba3535832943ab6127f27323e587e1918b2023b37a2 +dist/2025-04-02/rustfmt-nightly-powerpc64le-unknown-linux-musl.tar.xz=79912529a393cb77c604f5a16d5b22611e938971656efd57fc5ef1980ffad35a +dist/2025-04-02/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.gz=854280cb3eeac146196ba30c8f3a010d568bf5bf9613d1870bd052a2aa3a03c0 +dist/2025-04-02/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.xz=36e6cfc2b333cf077e3e1bf651acab4e6845330fa151848926d7b33fafa016f3 +dist/2025-04-02/rustfmt-nightly-s390x-unknown-linux-gnu.tar.gz=19409bf4daa2e4d76c99659d7348f9a7dd4eb640c8bc81d93dc9170a1e51b7ba +dist/2025-04-02/rustfmt-nightly-s390x-unknown-linux-gnu.tar.xz=999346ff469e15507ec43c0b265a94b98ee99a0096d68ea0307a2280d138838f +dist/2025-04-02/rustfmt-nightly-x86_64-apple-darwin.tar.gz=6a52a943d59edb9e6ed97643b01a2ca2f51abb6fba1b4c9b73f59646372aac01 +dist/2025-04-02/rustfmt-nightly-x86_64-apple-darwin.tar.xz=3701a72b39a31e31c9fe65afa660a507088dfe6039867a2019bfb69970872bad +dist/2025-04-02/rustfmt-nightly-x86_64-pc-windows-gnu.tar.gz=c0dbe39a6dc72d96446312584055cfd75a4304c4859016ec7590d52813f0736c +dist/2025-04-02/rustfmt-nightly-x86_64-pc-windows-gnu.tar.xz=f9e8814cf2e0241bbe40bfafc62bb961d87060dd94c84fba8ea00b2992eafe2a +dist/2025-04-02/rustfmt-nightly-x86_64-pc-windows-msvc.tar.gz=b9a2c923b6794b3462882a9f5b1579e2463024a72ff34cdf4bdfd8b0f51ee528 +dist/2025-04-02/rustfmt-nightly-x86_64-pc-windows-msvc.tar.xz=c5e8272c451a3d685842e07a996e8bdc305ccb02a02d39f7f4cc764be4b2adce +dist/2025-04-02/rustfmt-nightly-x86_64-unknown-freebsd.tar.gz=d47cb1e290f09795a04652f33afba39f80f3b6dcc4b570c14c75b1d945c78f0a +dist/2025-04-02/rustfmt-nightly-x86_64-unknown-freebsd.tar.xz=389ea9f755623dd3d887bbff71189f86d7397c82e2f8fe660c27784cf7c68a94 +dist/2025-04-02/rustfmt-nightly-x86_64-unknown-illumos.tar.gz=b49f6c211c51a50309ddd2bcb4c886ebeef47e5413e6399778157bc90a37ed0e +dist/2025-04-02/rustfmt-nightly-x86_64-unknown-illumos.tar.xz=d53f55b6dba14bb2e2f90510c3e432781a8aad1f871d8f38795edf866ed4a4f3 +dist/2025-04-02/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.gz=2b8d77937298b23522ab9bd2f64a829f6faf1dccb87033f6006aa8c324474b47 +dist/2025-04-02/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.xz=0579d2a7c17cd585c49a42efe062466db777c1e7890f21b319234ee81c86ea39 +dist/2025-04-02/rustfmt-nightly-x86_64-unknown-linux-musl.tar.gz=65bc50db8fbe283e876b9ae7d6c15ff0461c1db8b3327f2992a99d21bcc3266c +dist/2025-04-02/rustfmt-nightly-x86_64-unknown-linux-musl.tar.xz=120505da1a8cddfb3f549438a52b2c73c76a9f1c2f25709db13d61efd214d732 +dist/2025-04-02/rustfmt-nightly-x86_64-unknown-netbsd.tar.gz=d19004b3f6b9fa446e23f540b21a8f314d3bbcca11f753c9a6fdaf4c7ae7a2de +dist/2025-04-02/rustfmt-nightly-x86_64-unknown-netbsd.tar.xz=e7facb66daed07789015c2d5b092afde5dbb1349d06cd0f80ae8319437587723 +dist/2025-04-02/rustc-nightly-aarch64-apple-darwin.tar.gz=3783e0aa4450a6bb913fc9a9799950892e65c7af9a2c895419090072999a2305 +dist/2025-04-02/rustc-nightly-aarch64-apple-darwin.tar.xz=4d3a72db4cfcd7663803f1a0b193326e37c7faecc0c97c3903a17fbc0f7c8848 +dist/2025-04-02/rustc-nightly-aarch64-pc-windows-msvc.tar.gz=c253308683fd394b1287a4eb9ca00cb8557bd7f7f91af8b087adccf9153a94eb +dist/2025-04-02/rustc-nightly-aarch64-pc-windows-msvc.tar.xz=63c30a1e523266dd6f8d6bb1525484f51fc6462bd7946900e0590b219f2a8b47 +dist/2025-04-02/rustc-nightly-aarch64-unknown-linux-gnu.tar.gz=74d2313a732fc8401d62b9a8610bd9a25502f0372921c0e99d9d20f0cf8e3b19 +dist/2025-04-02/rustc-nightly-aarch64-unknown-linux-gnu.tar.xz=a96db92f8c7cebe6e0d140a1853ecaa038e04975d62f17950e141d8ac2452536 +dist/2025-04-02/rustc-nightly-aarch64-unknown-linux-musl.tar.gz=250e2c21af9d4b284c7455668ebcc3d1e408c20cda1abf0ee69acac4c873e5ed +dist/2025-04-02/rustc-nightly-aarch64-unknown-linux-musl.tar.xz=931714cf51d93fee5cc9465e9a0e9d34c771fe2aaae46994f3b00da4c95a8f54 +dist/2025-04-02/rustc-nightly-arm-unknown-linux-gnueabi.tar.gz=28f993889175ba3feb78b458be5282b2564a7c9b96117fed071835ff7b47f43f +dist/2025-04-02/rustc-nightly-arm-unknown-linux-gnueabi.tar.xz=8645d1a7510cc13e2cd9abeffa71cbfb5f3a99990d27da2b05c336801a51c7f0 +dist/2025-04-02/rustc-nightly-arm-unknown-linux-gnueabihf.tar.gz=a86525223d8c5d67b0a92382b6ebce65761cdb83629e11bf29d625d688908d38 +dist/2025-04-02/rustc-nightly-arm-unknown-linux-gnueabihf.tar.xz=06a57a2c6298bb6e477d1e04922c626142bf96b2072684aecbbbf876bb4296f1 +dist/2025-04-02/rustc-nightly-armv7-unknown-linux-gnueabihf.tar.gz=a7fb3babdc244ea1f025f3033d13088c50696db8d6db29efcc6a78474a06769e +dist/2025-04-02/rustc-nightly-armv7-unknown-linux-gnueabihf.tar.xz=b130a7efa1c2bdfa5ef51237d5233ab6bd8feade7dc596d120b6501b4766a569 +dist/2025-04-02/rustc-nightly-i686-pc-windows-gnu.tar.gz=ebb4dda0d1ced3ec5aa14b1ef38227628db92a87f45b817d4ce41ff026a687ec +dist/2025-04-02/rustc-nightly-i686-pc-windows-gnu.tar.xz=43a69c9382b20249495824c149ffb5b5dae2ff7407c0c431859bc3e1f1ca4a7c +dist/2025-04-02/rustc-nightly-i686-pc-windows-msvc.tar.gz=bf3eb550e148e89e7ff17be5e72ad0462d57f3c452bfdc46b80a1812ec2fe457 +dist/2025-04-02/rustc-nightly-i686-pc-windows-msvc.tar.xz=b2dde774c1ef573c6a889c2d78bbb98f535f22be4b20896797be2f10781f0eb4 +dist/2025-04-02/rustc-nightly-i686-unknown-linux-gnu.tar.gz=96d130960b0dc1d8fa54f53d22a8fa8cf5aa35d0b213071404122e4e714feab0 +dist/2025-04-02/rustc-nightly-i686-unknown-linux-gnu.tar.xz=d743c6126151dd18624382a4228bf90af1239fc7fd97e763009b31666fb860fb +dist/2025-04-02/rustc-nightly-loongarch64-unknown-linux-gnu.tar.gz=090ec673f24758b8a4d0ce7b8c58fc6015585bd8392e37760283ffbe6045298c +dist/2025-04-02/rustc-nightly-loongarch64-unknown-linux-gnu.tar.xz=c71ad975a15c440890a7358b5459b7ca6b9d5e1842dd353071467c2a3f841605 +dist/2025-04-02/rustc-nightly-loongarch64-unknown-linux-musl.tar.gz=8806875cee039409632e8baf5433227af04bd07d015329d9512cc4f4879f687c +dist/2025-04-02/rustc-nightly-loongarch64-unknown-linux-musl.tar.xz=cebc3a4f1eb71e86e4e63f78e1c2f86fc98f7d23db1a3cb7e4c4d385e5591d51 +dist/2025-04-02/rustc-nightly-powerpc-unknown-linux-gnu.tar.gz=643dc0fe347a78a82321b5f47b41b09025856b6383ef67274ba3324879aae75e +dist/2025-04-02/rustc-nightly-powerpc-unknown-linux-gnu.tar.xz=955018b90daf3797497dfc423aec731e8d0320b96dcf42db1705b761e1e0dd58 +dist/2025-04-02/rustc-nightly-powerpc64-unknown-linux-gnu.tar.gz=aed278e57ffe0eb54328a9536607bc179806e0c2de9fccb9779a4517752899e5 +dist/2025-04-02/rustc-nightly-powerpc64-unknown-linux-gnu.tar.xz=0b6e0305b13d867c677243b16613f62b07352038f5e7ad7e1865cc2d00168283 +dist/2025-04-02/rustc-nightly-powerpc64le-unknown-linux-gnu.tar.gz=e10d8eee30be690aa2e6ff58ca554d47173086d5df8f0ea8581b3fd10d4cee0a +dist/2025-04-02/rustc-nightly-powerpc64le-unknown-linux-gnu.tar.xz=3ca3c258404dd8718321ed8a50aa6512fea9d810120db225a3fcfe56d7b83064 +dist/2025-04-02/rustc-nightly-powerpc64le-unknown-linux-musl.tar.gz=ddfc329b8932ad796c0eb7618632f9ae0c5ffb7a6093ea7d5cc4185fc0537f22 +dist/2025-04-02/rustc-nightly-powerpc64le-unknown-linux-musl.tar.xz=b4e82b64f2e934e17fc9b270295554a8bf0bd3d38ffffc66b367aad5bee3ad6f +dist/2025-04-02/rustc-nightly-riscv64gc-unknown-linux-gnu.tar.gz=116d290065bd9e8ff2ca57440e94f773f68adf79aedba767159dfb92fe1a42b0 +dist/2025-04-02/rustc-nightly-riscv64gc-unknown-linux-gnu.tar.xz=6e1deb0c47bba4b56bbf1d04344e45f0490938455aee421629f2fcfd309eff64 +dist/2025-04-02/rustc-nightly-s390x-unknown-linux-gnu.tar.gz=445f8a0ca579153b449fa0d36460227af68399c4227be76e4cbb3d65cef9055c +dist/2025-04-02/rustc-nightly-s390x-unknown-linux-gnu.tar.xz=d87bcac173e9800dc1c1b28e668a1b4c3616029d0ca53adfa4ac382733610193 +dist/2025-04-02/rustc-nightly-x86_64-apple-darwin.tar.gz=4342b89aed19f409df56bfac3d6ac071a02cb6839a52d19fdff9d10cc1d9f540 +dist/2025-04-02/rustc-nightly-x86_64-apple-darwin.tar.xz=cb787327895f275e6f9025bb38c6337492c839310931b8c7ba39743813621701 +dist/2025-04-02/rustc-nightly-x86_64-pc-windows-gnu.tar.gz=6cddd0d3cf18780b36776fd0324643a36b3294923531a741cc763516c8238caf +dist/2025-04-02/rustc-nightly-x86_64-pc-windows-gnu.tar.xz=cefc15752bd84b290f50b958b96feb0134d420a10c6f36791424c762cda08abc +dist/2025-04-02/rustc-nightly-x86_64-pc-windows-msvc.tar.gz=731e968787044081453a559a95579435654b47f91a9b7f94579ac007ed3e4cf9 +dist/2025-04-02/rustc-nightly-x86_64-pc-windows-msvc.tar.xz=3d9b173043aed73aa3ab1fa0b14d0ce2149a4943f4bb10aa1e31af619afe0eed +dist/2025-04-02/rustc-nightly-x86_64-unknown-freebsd.tar.gz=c0df2f0a354d2d657d8ec8091bc094060321b343c8e7bb8e4315cfe042dacfc3 +dist/2025-04-02/rustc-nightly-x86_64-unknown-freebsd.tar.xz=8933bc0361484ac7c6b226defaea73eda5c4e10462e7ea54052c7e1d370e48c0 +dist/2025-04-02/rustc-nightly-x86_64-unknown-illumos.tar.gz=5887f913ac80dfe9826619227c66eb234a2b4848e6bc4f41c6fdd8102bf981e9 +dist/2025-04-02/rustc-nightly-x86_64-unknown-illumos.tar.xz=4a54b8b09eba43df0d99fb6e03177cf8ba2214a5810be52ac33ee3d9d33e98bc +dist/2025-04-02/rustc-nightly-x86_64-unknown-linux-gnu.tar.gz=1c0bb76acd7944804d52c3139f4dcf154d3221cdeb300bb6b9bca726cd6ad30f +dist/2025-04-02/rustc-nightly-x86_64-unknown-linux-gnu.tar.xz=e67a33440c3e021ff2dd41add0fb05db6c0e8ae68bd30d33e8b3185b0bb7191b +dist/2025-04-02/rustc-nightly-x86_64-unknown-linux-musl.tar.gz=0ea7e17d7bb67d6a6c4b2f864aaffcd96512f15f17f0acc63751eb1df6c486a7 +dist/2025-04-02/rustc-nightly-x86_64-unknown-linux-musl.tar.xz=b73d37b704ab58921172cc561f5598db6a504dcd4d7980966f7c26caaf6d3594 +dist/2025-04-02/rustc-nightly-x86_64-unknown-netbsd.tar.gz=986f6c594d37bcbd3833e053640ba8775f68d26a65c5618386654ef55d7b3542 +dist/2025-04-02/rustc-nightly-x86_64-unknown-netbsd.tar.xz=c0d9a88c30d2ab38ec3a11fabb5515ed9bc3ac1a8e35a438d68bf7ff82f6b843 diff --git a/src/tools/bump-stage0/src/main.rs b/src/tools/bump-stage0/src/main.rs index f51072718a34..d679084ae44b 100644 --- a/src/tools/bump-stage0/src/main.rs +++ b/src/tools/bump-stage0/src/main.rs @@ -65,32 +65,33 @@ impl Tool { nightly_branch, } = &self.config; - file_content.push_str(&format!("dist_server={}", dist_server)); - file_content.push_str(&format!("\nartifacts_server={}", artifacts_server)); + file_content.push_str(&format!("dist_server={}\n", dist_server)); + file_content.push_str(&format!("artifacts_server={}\n", artifacts_server)); file_content.push_str(&format!( - "\nartifacts_with_llvm_assertions_server={}", + "artifacts_with_llvm_assertions_server={}\n", artifacts_with_llvm_assertions_server )); - file_content.push_str(&format!("\ngit_merge_commit_email={}", git_merge_commit_email)); - file_content.push_str(&format!("\ngit_repository={}", git_repository)); - file_content.push_str(&format!("\nnightly_branch={}", nightly_branch)); + file_content.push_str(&format!("git_merge_commit_email={}\n", git_merge_commit_email)); + file_content.push_str(&format!("git_repository={}\n", git_repository)); + file_content.push_str(&format!("nightly_branch={}\n", nightly_branch)); - file_content.push_str("\n\n"); + file_content.push_str("\n"); file_content.push_str(COMMENTS); + file_content.push_str("\n"); let compiler = self.detect_compiler()?; - file_content.push_str(&format!("\ncompiler_date={}", compiler.date)); - file_content.push_str(&format!("\ncompiler_version={}", compiler.version)); + file_content.push_str(&format!("compiler_date={}\n", compiler.date)); + file_content.push_str(&format!("compiler_version={}\n", compiler.version)); if let Some(rustfmt) = self.detect_rustfmt()? { - file_content.push_str(&format!("\nrustfmt_date={}", rustfmt.date)); - file_content.push_str(&format!("\nrustfmt_version={}", rustfmt.version)); + file_content.push_str(&format!("rustfmt_date={}\n", rustfmt.date)); + file_content.push_str(&format!("rustfmt_version={}\n", rustfmt.version)); } file_content.push_str("\n"); for (key, value) in self.checksums { - file_content.push_str(&format!("\n{}={}", key, value)); + file_content.push_str(&format!("{}={}\n", key, value)); } std::fs::write(PATH, file_content)?; diff --git a/src/tools/cargo b/src/tools/cargo index 0e93c5bf6a1d..d811228b14ae 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 0e93c5bf6a1d5ee7bc2af63d1afb16cd28793601 +Subproject commit d811228b14ae2707323f37346aee3f4147e247e6 diff --git a/src/tools/clippy/Cargo.toml b/src/tools/clippy/Cargo.toml index 94c170d73af3..f5a8e3dc387d 100644 --- a/src/tools/clippy/Cargo.toml +++ b/src/tools/clippy/Cargo.toml @@ -25,6 +25,7 @@ path = "src/driver.rs" [dependencies] clippy_config = { path = "clippy_config" } clippy_lints = { path = "clippy_lints" } +clippy_utils = { path = "clippy_utils" } rustc_tools_util = { path = "rustc_tools_util", version = "0.4.2" } tempfile = { version = "3.3", optional = true } termize = "0.1" diff --git a/src/tools/clippy/clippy_lints/src/assigning_clones.rs b/src/tools/clippy/clippy_lints/src/assigning_clones.rs index ab34af7c3174..e5439a6d401b 100644 --- a/src/tools/clippy/clippy_lints/src/assigning_clones.rs +++ b/src/tools/clippy/clippy_lints/src/assigning_clones.rs @@ -111,8 +111,8 @@ impl<'tcx> LateLintPass<'tcx> for AssigningClones { // Only suggest if `clone_from`/`clone_into` is explicitly implemented && resolved_assoc_items.in_definition_order().any(|assoc| match which_trait { - CloneTrait::Clone => assoc.name == sym::clone_from, - CloneTrait::ToOwned => assoc.name.as_str() == "clone_into", + CloneTrait::Clone => assoc.name() == sym::clone_from, + CloneTrait::ToOwned => assoc.name().as_str() == "clone_into", } ) && !clone_source_borrows_from_dest(cx, lhs, rhs.span) diff --git a/src/tools/clippy/clippy_lints/src/attrs/deprecated_cfg_attr.rs b/src/tools/clippy/clippy_lints/src/attrs/deprecated_cfg_attr.rs index cd38aed26a3e..7fab97d3ea14 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/deprecated_cfg_attr.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/deprecated_cfg_attr.rs @@ -1,10 +1,10 @@ use super::{Attribute, DEPRECATED_CFG_ATTR, DEPRECATED_CLIPPY_CFG_ATTR, unnecessary_clippy_cfg}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::msrvs::{self, MsrvStack}; +use clippy_utils::sym; use rustc_ast::AttrStyle; use rustc_errors::Applicability; use rustc_lint::EarlyContext; -use rustc_span::sym; pub(super) fn check(cx: &EarlyContext<'_>, attr: &Attribute, msrv: &MsrvStack) { // check cfg_attr @@ -18,7 +18,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, attr: &Attribute, msrv: &MsrvStack) { && msrv.meets(msrvs::TOOL_ATTRIBUTES) // check for `rustfmt_skip` and `rustfmt::skip` && let Some(skip_item) = &items[1].meta_item() - && (skip_item.has_name(sym!(rustfmt_skip)) + && (skip_item.has_name(sym::rustfmt_skip) || skip_item .path .segments diff --git a/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs b/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs index e3e081ce08e9..1cb43ab02a30 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs @@ -2,10 +2,10 @@ use super::USELESS_ATTRIBUTE; use super::utils::{is_lint_level, is_word, namespace_and_lint}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::{SpanRangeExt, first_line_of_span}; +use clippy_utils::sym; use rustc_ast::{Attribute, Item, ItemKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, LintContext}; -use rustc_span::sym; pub(super) fn check(cx: &EarlyContext<'_>, item: &Item, attrs: &[Attribute]) { let skip_unused_imports = attrs.iter().any(|attr| attr.has_name(sym::macro_use)); @@ -61,7 +61,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, item: &Item, attrs: &[Attribute]) { if is_word(lint, sym::unused_imports) && skip_unused_imports { return; } - if is_word(lint, sym!(unused_extern_crates)) { + if is_word(lint, sym::unused_extern_crates) { return; } }, diff --git a/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs b/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs index adac2f27ea8c..4a876b854165 100644 --- a/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs +++ b/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs @@ -53,10 +53,10 @@ fn is_impl_not_trait_with_bool_out<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) - .not_trait() .filter(|trait_id| implements_trait(cx, ty, *trait_id, &[])) .and_then(|trait_id| { - cx.tcx.associated_items(trait_id).find_by_name_and_kind( + cx.tcx.associated_items(trait_id).find_by_ident_and_kind( cx.tcx, Ident::from_str("Output"), - ty::AssocKind::Type, + ty::AssocTag::Type, trait_id, ) }) diff --git a/src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs b/src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs index f6c10da1596b..bf549dcdb506 100644 --- a/src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs +++ b/src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs @@ -38,7 +38,7 @@ pub fn check( // of all `#[test]` attributes in not ignored code examples fn check_code_sample(code: String, edition: Edition, ignore: bool) -> (bool, Vec>) { rustc_driver::catch_fatal_errors(|| { - rustc_span::create_session_globals_then(edition, None, || { + rustc_span::create_session_globals_then(edition, &[], None, || { let mut test_attr_spans = vec![]; let filename = FileName::anon_source_code(&code); diff --git a/src/tools/clippy/clippy_lints/src/equatable_if_let.rs b/src/tools/clippy/clippy_lints/src/equatable_if_let.rs index cd9ab2764ac4..3afb687040f4 100644 --- a/src/tools/clippy/clippy_lints/src/equatable_if_let.rs +++ b/src/tools/clippy/clippy_lints/src/equatable_if_let.rs @@ -45,6 +45,7 @@ fn unary_pattern(pat: &Pat<'_>) -> bool { pats.iter().all(unary_pattern) } match &pat.kind { + PatKind::Missing => unreachable!(), PatKind::Slice(_, _, _) | PatKind::Range(_, _, _) | PatKind::Binding(..) diff --git a/src/tools/clippy/clippy_lints/src/format_args.rs b/src/tools/clippy/clippy_lints/src/format_args.rs index 3862ff7921db..06224f57c5c5 100644 --- a/src/tools/clippy/clippy_lints/src/format_args.rs +++ b/src/tools/clippy/clippy_lints/src/format_args.rs @@ -550,7 +550,7 @@ impl<'tcx> FormatArgsExpr<'_, 'tcx> { // a `Target` that is in `self.ty_msrv_map`. if let Some(deref_trait_id) = self.cx.tcx.lang_items().deref_trait() && implements_trait(self.cx, ty, deref_trait_id, &[]) - && let Some(target_ty) = self.cx.get_associated_type(ty, deref_trait_id, "Target") + && let Some(target_ty) = self.cx.get_associated_type(ty, deref_trait_id, sym::Target) && let Some(msrv) = self.ty_msrv_map.get(&target_ty) && msrv.is_none_or(|msrv| self.msrv.meets(self.cx, msrv)) { diff --git a/src/tools/clippy/clippy_lints/src/functions/renamed_function_params.rs b/src/tools/clippy/clippy_lints/src/functions/renamed_function_params.rs index 041f6228fba2..4495aeb5953e 100644 --- a/src/tools/clippy/clippy_lints/src/functions/renamed_function_params.rs +++ b/src/tools/clippy/clippy_lints/src/functions/renamed_function_params.rs @@ -22,8 +22,8 @@ pub(super) fn check_impl_item(cx: &LateContext<'_>, item: &ImplItem<'_>, ignored && let Some(did) = trait_item_def_id_of_impl(items, item.owner_id) && !is_from_ignored_trait(trait_ref, ignored_traits) { - let mut param_idents_iter = cx.tcx.hir_body_param_names(body_id); - let mut default_param_idents_iter = cx.tcx.fn_arg_names(did).iter().copied(); + let mut param_idents_iter = cx.tcx.hir_body_param_idents(body_id); + let mut default_param_idents_iter = cx.tcx.fn_arg_idents(did).iter().copied(); let renames = RenamedFnArgs::new(&mut default_param_idents_iter, &mut param_idents_iter); if !renames.0.is_empty() { diff --git a/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs b/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs index d02d9b2102bd..430f24111832 100644 --- a/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs +++ b/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs @@ -315,7 +315,7 @@ fn check<'tcx>(cx: &LateContext<'tcx>, bounds: GenericBounds<'tcx>) { assocs .filter_by_name_unhygienic(constraint.ident.name) .next() - .is_some_and(|assoc| assoc.kind == ty::AssocKind::Type) + .is_some_and(|assoc| assoc.is_type()) }) { emit_lint(cx, poly_trait, bounds, index, implied_constraints, bound); diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs index 72e22ae59d8f..77085d52a32e 100644 --- a/src/tools/clippy/clippy_lints/src/len_zero.rs +++ b/src/tools/clippy/clippy_lints/src/len_zero.rs @@ -13,7 +13,7 @@ use rustc_hir::{ QPath, TraitItemRef, TyKind, }; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::{self, AssocKind, FnSig, Ty}; +use rustc_middle::ty::{self, FnSig, Ty}; use rustc_session::declare_lint_pass; use rustc_span::source_map::Spanned; use rustc_span::symbol::sym; @@ -288,8 +288,7 @@ fn check_trait_items(cx: &LateContext<'_>, visited_trait: &Item<'_>, ident: Iden .items() .flat_map(|&i| cx.tcx.associated_items(i).filter_by_name_unhygienic(is_empty)) .any(|i| { - i.kind == AssocKind::Fn - && i.fn_has_self_parameter + i.is_method() && cx.tcx.fn_sig(i.def_id).skip_binder().inputs().skip_binder().len() == 1 }); @@ -466,7 +465,7 @@ fn check_for_is_empty( .inherent_impls(impl_ty) .iter() .flat_map(|&id| cx.tcx.associated_items(id).filter_by_name_unhygienic(is_empty)) - .find(|item| item.kind == AssocKind::Fn); + .find(|item| item.is_fn()); let (msg, is_empty_span, self_kind) = match is_empty { None => ( @@ -486,7 +485,7 @@ fn check_for_is_empty( None, ), Some(is_empty) - if !(is_empty.fn_has_self_parameter + if !(is_empty.is_method() && check_is_empty_sig( cx, cx.tcx.fn_sig(is_empty.def_id).instantiate_identity().skip_binder(), @@ -608,7 +607,7 @@ fn is_empty_array(expr: &Expr<'_>) -> bool { fn has_is_empty(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { /// Gets an `AssocItem` and return true if it matches `is_empty(self)`. fn is_is_empty(cx: &LateContext<'_>, item: &ty::AssocItem) -> bool { - if item.kind == AssocKind::Fn { + if item.is_fn() { let sig = cx.tcx.fn_sig(item.def_id).skip_binder(); let ty = sig.skip_binder(); ty.inputs().len() == 1 @@ -644,7 +643,7 @@ fn has_is_empty(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { && cx.tcx.get_diagnostic_item(sym::Deref).is_some_and(|deref_id| { implements_trait(cx, ty, deref_id, &[]) && cx - .get_associated_type(ty, deref_id, "Target") + .get_associated_type(ty, deref_id, sym::Target) .is_some_and(|deref_ty| ty_has_is_empty(cx, deref_ty, depth + 1)) })) }, diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs index 8d47c756fc53..dabef18b98a9 100644 --- a/src/tools/clippy/clippy_lints/src/lifetimes.rs +++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs @@ -14,7 +14,7 @@ use rustc_hir::intravisit::{ }; use rustc_hir::{ AmbigArg, BareFnTy, BodyId, FnDecl, FnSig, GenericArg, GenericArgs, GenericBound, GenericParam, GenericParamKind, - Generics, HirId, Impl, ImplItem, ImplItemKind, Item, ItemKind, Lifetime, LifetimeName, LifetimeParamKind, Node, + Generics, HirId, Impl, ImplItem, ImplItemKind, Item, ItemKind, Lifetime, LifetimeKind, LifetimeParamKind, Node, PolyTraitRef, PredicateOrigin, TraitFn, TraitItem, TraitItemKind, Ty, TyKind, WhereBoundPredicate, WherePredicate, WherePredicateKind, lang_items, }; @@ -218,7 +218,7 @@ fn check_fn_inner<'tcx>( for bound in pred.bounds { let mut visitor = RefVisitor::new(cx); walk_param_bound(&mut visitor, bound); - if visitor.lts.iter().any(|lt| matches!(lt.res, LifetimeName::Param(_))) { + if visitor.lts.iter().any(|lt| matches!(lt.kind, LifetimeKind::Param(_))) { return; } if let GenericBound::Trait(ref trait_ref) = *bound { @@ -235,7 +235,7 @@ fn check_fn_inner<'tcx>( _ => None, }); for bound in lifetimes { - if bound.res != LifetimeName::Static && !bound.is_elided() { + if bound.kind != LifetimeKind::Static && !bound.is_elided() { return; } } @@ -421,8 +421,8 @@ fn named_lifetime_occurrences(lts: &[Lifetime]) -> Vec<(LocalDefId, usize)> { } fn named_lifetime(lt: &Lifetime) -> Option { - match lt.res { - LifetimeName::Param(id) if !lt.is_anonymous() => Some(id), + match lt.kind { + LifetimeKind::Param(id) if !lt.is_anonymous() => Some(id), _ => None, } } @@ -614,7 +614,7 @@ where // for lifetimes as parameters of generics fn visit_lifetime(&mut self, lifetime: &'tcx Lifetime) { - if let LifetimeName::Param(def_id) = lifetime.res + if let LifetimeKind::Param(def_id) = lifetime.kind && let Some(usages) = self.map.get_mut(&def_id) { usages.push(Usage { @@ -826,7 +826,7 @@ fn report_elidable_lifetimes( .iter() .map(|<| cx.tcx.def_span(lt)) .chain(usages.iter().filter_map(|usage| { - if let LifetimeName::Param(def_id) = usage.res + if let LifetimeKind::Param(def_id) = usage.kind && elidable_lts.contains(&def_id) { return Some(usage.ident.span); 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 250f17fa9025..a21597ffb93d 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 @@ -253,6 +253,7 @@ fn iter_matching_struct_fields<'a>( impl<'a> NormalizedPat<'a> { fn from_pat(cx: &LateContext<'_>, arena: &'a DroplessArena, pat: &'a Pat<'_>) -> Self { match pat.kind { + PatKind::Missing => unreachable!(), PatKind::Wild | PatKind::Binding(.., None) => Self::Wild, PatKind::Binding(.., Some(pat)) | PatKind::Box(pat) 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 56fbd626eefc..836c46240ce7 100644 --- a/src/tools/clippy/clippy_lints/src/matches/single_match.rs +++ b/src/tools/clippy/clippy_lints/src/matches/single_match.rs @@ -406,6 +406,7 @@ impl<'a> PatState<'a> { pats.iter().map(|p| p.pat), ), + PatKind::Missing => unreachable!(), PatKind::Wild | PatKind::Binding(_, _, _, None) | PatKind::Expr(_) diff --git a/src/tools/clippy/clippy_lints/src/methods/double_ended_iterator_last.rs b/src/tools/clippy/clippy_lints/src/methods/double_ended_iterator_last.rs index e82211bbf3ef..b5adc69e9a79 100644 --- a/src/tools/clippy/clippy_lints/src/methods/double_ended_iterator_last.rs +++ b/src/tools/clippy/clippy_lints/src/methods/double_ended_iterator_last.rs @@ -24,7 +24,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &'_ Expr<'_>, self_expr: &'_ Exp && let Ok(Some(fn_def)) = Instance::try_resolve(cx.tcx, cx.typing_env(), id, args) // find the provided definition of Iterator::last && let Some(item) = cx.tcx.get_diagnostic_item(sym::Iterator) - && let Some(last_def) = cx.tcx.provided_trait_methods(item).find(|m| m.name.as_str() == "last") + && let Some(last_def) = cx.tcx.provided_trait_methods(item).find(|m| m.name().as_str() == "last") // if the resolved method is the same as the provided definition && fn_def.def_id() == last_def.def_id { diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs b/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs index f51bdc78f8a5..7bb625222ec0 100644 --- a/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs +++ b/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs @@ -48,7 +48,7 @@ pub(super) fn check<'tcx>( && let Some(method_id) = typeck.type_dependent_def_id(cloned_call.hir_id) && cx.tcx.trait_of_item(method_id) == Some(iter_id) && let cloned_recv_ty = typeck.expr_ty_adjusted(cloned_recv) - && let Some(iter_assoc_ty) = cx.get_associated_type(cloned_recv_ty, iter_id, "Item") + && let Some(iter_assoc_ty) = cx.get_associated_type(cloned_recv_ty, iter_id, sym::Item) && matches!(*iter_assoc_ty.kind(), ty::Ref(_, ty, _) if !is_copy(cx, ty)) { if needs_into_iter diff --git a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs index 56ff7e2c61b2..e4a29b6560e5 100644 --- a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs +++ b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs @@ -17,7 +17,7 @@ use rustc_hir::{ }; use rustc_lint::LateContext; use rustc_middle::hir::nested_filter; -use rustc_middle::ty::{self, AssocKind, ClauseKind, EarlyBinder, GenericArg, GenericArgKind, Ty}; +use rustc_middle::ty::{self, AssocTag, ClauseKind, EarlyBinder, GenericArg, GenericArgKind, Ty}; use rustc_span::symbol::Ident; use rustc_span::{Span, sym}; @@ -238,10 +238,10 @@ fn is_contains_sig(cx: &LateContext<'_>, call_id: HirId, iter_expr: &Expr<'_>) - .instantiate_bound_regions_with_erased(sig.rebind(search_ty)) .kind() && let Some(iter_trait) = cx.tcx.get_diagnostic_item(sym::Iterator) - && let Some(iter_item) = cx.tcx.associated_items(iter_trait).find_by_name_and_kind( + && let Some(iter_item) = cx.tcx.associated_items(iter_trait).find_by_ident_and_kind( cx.tcx, Ident::with_dummy_span(sym::Item), - AssocKind::Type, + AssocTag::Type, iter_trait, ) && let args = cx.tcx.mk_args(&[GenericArg::from(typeck.expr_ty_adjusted(iter_expr))]) 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 c03420a5143e..6eeeea5d77c7 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 @@ -78,7 +78,7 @@ pub(super) fn check<'tcx>( .iter() .flat_map(|impl_id| cx.tcx.associated_items(impl_id).filter_by_name_unhygienic(sugg)) .find_map(|assoc| { - if assoc.fn_has_self_parameter + if assoc.is_method() && cx.tcx.fn_sig(assoc.def_id).skip_binder().inputs().skip_binder().len() == 1 { Some(assoc.def_id) diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs index c0e015685881..20cf35363d13 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs @@ -99,7 +99,7 @@ pub fn check_for_loop_iter( && let Some(into_iterator_trait_id) = cx.tcx.get_diagnostic_item(sym::IntoIterator) && let collection_ty = cx.typeck_results().expr_ty(collection) && implements_trait(cx, collection_ty, into_iterator_trait_id, &[]) - && let Some(into_iter_item_ty) = cx.get_associated_type(collection_ty, into_iterator_trait_id, "Item") + && let Some(into_iter_item_ty) = cx.get_associated_type(collection_ty, into_iterator_trait_id, sym::Item) && iter_item_ty == into_iter_item_ty && let Some(collection_snippet) = collection.span.get_source_text(cx) { 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 62ba3012643c..206b0a8ae3cd 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 @@ -153,7 +153,7 @@ fn check_addr_of_expr( } if let Some(deref_trait_id) = cx.tcx.get_diagnostic_item(sym::Deref) && implements_trait(cx, receiver_ty, deref_trait_id, &[]) - && cx.get_associated_type(receiver_ty, deref_trait_id, "Target") == Some(target_ty) + && cx.get_associated_type(receiver_ty, deref_trait_id, sym::Target) == Some(target_ty) // Make sure that it's actually calling the right `.to_string()`, (#10033) // *or* this is a `Cow::into_owned()` call (which would be the wrong into_owned receiver (str != Cow) // but that's ok for Cow::into_owned specifically) @@ -322,7 +322,7 @@ fn check_split_call_arg(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symb // add `.as_ref()` to the suggestion. let as_ref = if is_type_lang_item(cx, cx.typeck_results().expr_ty(expr), LangItem::String) && let Some(deref_trait_id) = cx.tcx.get_diagnostic_item(sym::Deref) - && cx.get_associated_type(cx.typeck_results().expr_ty(receiver), deref_trait_id, "Target") + && cx.get_associated_type(cx.typeck_results().expr_ty(receiver), deref_trait_id, sym::Target) != Some(cx.tcx.types.str_) { ".as_ref()" @@ -648,7 +648,7 @@ fn is_to_string_on_string_like<'a>( && let GenericArgKind::Type(ty) = generic_arg.unpack() && let Some(deref_trait_id) = cx.tcx.get_diagnostic_item(sym::Deref) && let Some(as_ref_trait_id) = cx.tcx.get_diagnostic_item(sym::AsRef) - && (cx.get_associated_type(ty, deref_trait_id, "Target") == Some(cx.tcx.types.str_) + && (cx.get_associated_type(ty, deref_trait_id, sym::Target) == Some(cx.tcx.types.str_) || implements_trait(cx, ty, as_ref_trait_id, &[cx.tcx.types.str_.into()])) { true diff --git a/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs b/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs index 7ee746365d10..e266c36b6e73 100644 --- a/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs +++ b/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs @@ -81,7 +81,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingTraitMethods { cx, MISSING_TRAIT_METHODS, cx.tcx.def_span(item.owner_id), - format!("missing trait method provided by default: `{}`", assoc.name), + format!("missing trait method provided by default: `{}`", assoc.name()), |diag| { diag.span_help(cx.tcx.def_span(assoc.def_id), "implement the method"); }, diff --git a/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs b/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs index f686cc912ddb..e579dd5947d7 100644 --- a/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs +++ b/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs @@ -299,7 +299,7 @@ fn has_ref_mut_self_method(cx: &LateContext<'_>, trait_def_id: DefId) -> bool { .associated_items(trait_def_id) .in_definition_order() .any(|assoc_item| { - if assoc_item.fn_has_self_parameter { + if assoc_item.is_method() { let self_ty = cx .tcx .fn_sig(assoc_item.def_id) diff --git a/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs b/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs index 8f1a1ee76c6a..96d3f7196c0c 100644 --- a/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs +++ b/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs @@ -179,7 +179,7 @@ fn find_first_mismatch(cx: &LateContext<'_>, pat: &Pat<'_>) -> Option<(Span, Mut }; if let Some(adjustments) = cx.typeck_results().pat_adjustments().get(adjust_pat.hir_id) { if let [first, ..] = **adjustments { - if let ty::Ref(.., mutability) = *first.kind() { + if let ty::Ref(.., mutability) = *first.source.kind() { let level = if p.hir_id == pat.hir_id { Level::Top } else { diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs index 50ef56db167c..901a1634ddc8 100644 --- a/src/tools/clippy/clippy_lints/src/ptr.rs +++ b/src/tools/clippy/clippy_lints/src/ptr.rs @@ -3,7 +3,7 @@ use clippy_utils::source::SpanRangeExt; use clippy_utils::sugg::Sugg; use clippy_utils::visitors::contains_unsafe_block; use clippy_utils::{get_expr_use_or_unification_node, is_lint_allowed, path_def_id, path_to_local, std_or_core}; -use hir::LifetimeName; +use hir::LifetimeKind; use rustc_abi::ExternAbi; use rustc_errors::{Applicability, MultiSpan}; use rustc_hir::hir_id::{HirId, HirIdMap}; @@ -432,7 +432,7 @@ fn check_fn_args<'cx, 'tcx: 'cx>( } None }) { - if let LifetimeName::Param(param_def_id) = lifetime.res + if let LifetimeKind::Param(param_def_id) = lifetime.kind && !lifetime.is_anonymous() && fn_sig .output() diff --git a/src/tools/clippy/clippy_lints/src/same_name_method.rs b/src/tools/clippy/clippy_lints/src/same_name_method.rs index 552135b15fd8..33815cc3bac1 100644 --- a/src/tools/clippy/clippy_lints/src/same_name_method.rs +++ b/src/tools/clippy/clippy_lints/src/same_name_method.rs @@ -3,7 +3,6 @@ use rustc_data_structures::fx::FxHashMap; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{HirId, Impl, ItemKind, Node, Path, QPath, TraitRef, TyKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::AssocKind; use rustc_session::declare_lint_pass; use rustc_span::Span; use rustc_span::symbol::Symbol; @@ -85,8 +84,8 @@ impl<'tcx> LateLintPass<'tcx> for SameNameMethod { cx.tcx .associated_items(did) .in_definition_order() - .filter(|assoc_item| matches!(assoc_item.kind, AssocKind::Fn)) - .map(|assoc_item| assoc_item.name) + .filter(|assoc_item| assoc_item.is_fn()) + .map(|assoc_item| assoc_item.name()) .collect() } else { BTreeSet::new() diff --git a/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs b/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs index 51c7d6fce312..0c17cc5d8f66 100644 --- a/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs +++ b/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs @@ -10,7 +10,7 @@ use rustc_hir::{Body, Expr, ExprKind, FnDecl, HirId, Item, ItemKind, Node, QPath use rustc_hir_analysis::lower_ty; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; -use rustc_middle::ty::{self, AssocKind, Ty, TyCtxt}; +use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_session::impl_lint_pass; use rustc_span::symbol::{Ident, kw}; use rustc_span::{Span, sym}; @@ -322,7 +322,7 @@ impl UnconditionalRecursion { .in_definition_order() // We're not interested in foreign implementations of the `Default` trait. .find(|item| { - item.kind == AssocKind::Fn && item.def_id.is_local() && item.name == kw::Default + item.is_fn() && item.def_id.is_local() && item.name() == kw::Default }) && let Some(body_node) = cx.tcx.hir_get_if_local(assoc_item.def_id) && let Some(body_id) = body_node.body_id() diff --git a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs index f43715d6752e..8966e6851ac2 100644 --- a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs +++ b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs @@ -224,6 +224,7 @@ fn transform_with_focus_on_idx(alternatives: &mut ThinVec>, focus_idx: us // We're trying to find whatever kind (~"constructor") we found in `alternatives[start..]`. let changed = match &mut focus_kind { + Missing => unreachable!(), // These pattern forms are "leafs" and do not have sub-patterns. // Therefore they are not some form of constructor `C`, // with which a pattern `C(p_0)` may be formed, diff --git a/src/tools/clippy/clippy_lints/src/unused_self.rs b/src/tools/clippy/clippy_lints/src/unused_self.rs index 582aa6e6001e..d0067b1a65e7 100644 --- a/src/tools/clippy/clippy_lints/src/unused_self.rs +++ b/src/tools/clippy/clippy_lints/src/unused_self.rs @@ -74,7 +74,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedSelf { .is_some() }; if let ItemKind::Impl(Impl { of_trait: None, .. }) = parent_item.kind - && assoc_item.fn_has_self_parameter + && assoc_item.is_method() && let ImplItemKind::Fn(.., body_id) = &impl_item.kind && (!cx.effective_visibilities.is_exported(impl_item.owner_id.def_id) || !self.avoid_breaking_exported_api) && let body = cx.tcx.hir_body(*body_id) diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index 4309cd2c9abd..b7dcd2ffb0ee 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -676,6 +676,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { } match pat.value.kind { + PatKind::Missing => unreachable!(), PatKind::Wild => kind!("Wild"), PatKind::Never => kind!("Never"), PatKind::Binding(ann, _, name, sub) => { diff --git a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs index eba576392ebc..c5dce26143be 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs @@ -33,6 +33,7 @@ pub fn eq_id(l: Ident, r: Ident) -> bool { pub fn eq_pat(l: &Pat, r: &Pat) -> bool { use PatKind::*; match (&l.kind, &r.kind) { + (Missing, _) | (_, Missing) => unreachable!(), (Paren(l), _) => eq_pat(l, r), (_, Paren(r)) => eq_pat(l, r), (Wild, Wild) | (Rest, Rest) => true, diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index 9938e64d2426..be295b59f609 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -8,7 +8,7 @@ use rustc_hir::MatchSource::TryDesugar; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{ AssocItemConstraint, BinOpKind, BindingMode, Block, BodyId, Closure, ConstArg, ConstArgKind, Expr, ExprField, - ExprKind, FnRetTy, GenericArg, GenericArgs, HirId, HirIdMap, InlineAsmOperand, LetExpr, Lifetime, LifetimeName, + ExprKind, FnRetTy, GenericArg, GenericArgs, HirId, HirIdMap, InlineAsmOperand, LetExpr, Lifetime, LifetimeKind, Pat, PatExpr, PatExprKind, PatField, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, StructTailExpr, TraitBoundModifiers, Ty, TyKind, TyPat, TyPatKind, }; @@ -483,7 +483,7 @@ impl HirEqInterExpr<'_, '_, '_> { } fn eq_lifetime(left: &Lifetime, right: &Lifetime) -> bool { - left.res == right.res + left.kind == right.kind } fn eq_pat_field(&mut self, left: &PatField<'_>, right: &PatField<'_>) -> bool { @@ -1124,6 +1124,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { pub fn hash_pat(&mut self, pat: &Pat<'_>) { std::mem::discriminant(&pat.kind).hash(&mut self.s); match pat.kind { + PatKind::Missing => unreachable!(), PatKind::Binding(BindingMode(by_ref, mutability), _, _, pat) => { std::mem::discriminant(&by_ref).hash(&mut self.s); std::mem::discriminant(&mutability).hash(&mut self.s); @@ -1244,8 +1245,8 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { pub fn hash_lifetime(&mut self, lifetime: &Lifetime) { lifetime.ident.name.hash(&mut self.s); - std::mem::discriminant(&lifetime.res).hash(&mut self.s); - if let LifetimeName::Param(param_id) = lifetime.res { + std::mem::discriminant(&lifetime.kind).hash(&mut self.s); + if let LifetimeKind::Param(param_id) = lifetime.kind { param_id.hash(&mut self.s); } } diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 6d2c2a2d692e..f715fc86e4e5 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -3,6 +3,7 @@ #![feature(f128)] #![feature(f16)] #![feature(if_let_guard)] +#![feature(macro_metavar_expr)] #![feature(macro_metavar_expr_concat)] #![feature(let_chains)] #![feature(never_type)] @@ -74,6 +75,7 @@ pub mod qualify_min_const_fn; pub mod source; pub mod str_utils; pub mod sugg; +pub mod sym; pub mod ty; pub mod usage; pub mod visitors; @@ -126,7 +128,7 @@ use rustc_middle::ty::{ use rustc_span::hygiene::{ExpnKind, MacroKind}; use rustc_span::source_map::SourceMap; use rustc_span::symbol::{Ident, Symbol, kw}; -use rustc_span::{InnerSpan, Span, sym}; +use rustc_span::{InnerSpan, Span}; use visitors::{Visitable, for_each_unconsumed_temporary}; use crate::consts::{ConstEvalCtxt, Constant, mir_to_const}; @@ -1858,6 +1860,7 @@ pub fn is_refutable(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool { } match pat.kind { + PatKind::Missing => unreachable!(), PatKind::Wild | PatKind::Never => false, // If `!` typechecked then the type is empty, so not refutable. PatKind::Binding(_, _, _, pat) => pat.is_some_and(|pat| is_refutable(cx, pat)), PatKind::Box(pat) | PatKind::Ref(pat, _) => is_refutable(cx, pat), @@ -2360,14 +2363,14 @@ pub fn is_no_std_crate(cx: &LateContext<'_>) -> bool { cx.tcx .hir_attrs(hir::CRATE_HIR_ID) .iter() - .any(|attr| attr.name_or_empty() == sym::no_std) + .any(|attr| attr.has_name(sym::no_std)) } pub fn is_no_core_crate(cx: &LateContext<'_>) -> bool { cx.tcx .hir_attrs(hir::CRATE_HIR_ID) .iter() - .any(|attr| attr.name_or_empty() == sym::no_core) + .any(|attr| attr.has_name(sym::no_core)) } /// Check if parent of a hir node is a trait implementation block. @@ -3501,7 +3504,7 @@ fn maybe_get_relative_path(from: &DefPath, to: &DefPath, max_super: usize) -> St // a::b::c ::d::sym refers to // e::f::sym:: :: // result should be super::super::super::super::e::f - if let DefPathData::TypeNs(Some(s)) = l { + if let DefPathData::TypeNs(s) = l { path.push(s.to_string()); } if let DefPathData::TypeNs(_) = r { @@ -3512,7 +3515,7 @@ fn maybe_get_relative_path(from: &DefPath, to: &DefPath, max_super: usize) -> St // a::b::sym:: :: refers to // c::d::e ::f::sym // when looking at `f` - Left(DefPathData::TypeNs(Some(sym))) => path.push(sym.to_string()), + Left(DefPathData::TypeNs(sym)) => path.push(sym.to_string()), // consider: // a::b::c ::d::sym refers to // e::f::sym:: :: @@ -3526,7 +3529,7 @@ fn maybe_get_relative_path(from: &DefPath, to: &DefPath, max_super: usize) -> St // `super` chain would be too long, just use the absolute path instead once(String::from("crate")) .chain(to.data.iter().filter_map(|el| { - if let DefPathData::TypeNs(Some(sym)) = el.data { + if let DefPathData::TypeNs(sym) = el.data { Some(sym.to_string()) } else { None diff --git a/src/tools/clippy/clippy_utils/src/sym.rs b/src/tools/clippy/clippy_utils/src/sym.rs new file mode 100644 index 000000000000..9cc72a5b3aaa --- /dev/null +++ b/src/tools/clippy/clippy_utils/src/sym.rs @@ -0,0 +1,23 @@ +#![allow(non_upper_case_globals)] + +use rustc_span::symbol::{Symbol, PREDEFINED_SYMBOLS_COUNT}; + +pub use rustc_span::sym::*; + +macro_rules! generate { + ($($sym:ident,)*) => { + /// To be supplied to `rustc_interface::Config` + pub const EXTRA_SYMBOLS: &[&str] = &[ + $(stringify!($sym),)* + ]; + + $( + pub const $sym: Symbol = Symbol::new(PREDEFINED_SYMBOLS_COUNT + ${index()}); + )* + }; +} + +generate! { + rustfmt_skip, + unused_extern_crates, +} diff --git a/src/tools/clippy/clippy_utils/src/ty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/mod.rs index 6fdf4c244f8d..d33e59342a59 100644 --- a/src/tools/clippy/clippy_utils/src/ty/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ty/mod.rs @@ -19,7 +19,7 @@ use rustc_middle::mir::interpret::Scalar; use rustc_middle::traits::EvaluationResult; use rustc_middle::ty::layout::ValidityRequirement; use rustc_middle::ty::{ - self, AdtDef, AliasTy, AssocItem, AssocKind, Binder, BoundRegion, FnSig, GenericArg, GenericArgKind, + self, AdtDef, AliasTy, AssocItem, AssocTag, Binder, BoundRegion, FnSig, GenericArg, GenericArgKind, GenericArgsRef, GenericParamDefKind, IntTy, ParamEnv, Region, RegionKind, TraitRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, UintTy, Upcast, VariantDef, VariantDiscr, }; @@ -156,7 +156,7 @@ pub fn contains_ty_adt_constructor_opaque<'tcx>(cx: &LateContext<'tcx>, ty: Ty<' pub fn get_iterator_item_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option> { cx.tcx .get_diagnostic_item(sym::Iterator) - .and_then(|iter_did| cx.get_associated_type(ty, iter_did, "Item")) + .and_then(|iter_did| cx.get_associated_type(ty, iter_did, sym::Item)) } /// Get the diagnostic name of a type, e.g. `sym::HashMap`. To check if a type @@ -1109,10 +1109,10 @@ pub fn make_projection<'tcx>( assoc_ty: Symbol, args: GenericArgsRef<'tcx>, ) -> Option> { - let Some(assoc_item) = tcx.associated_items(container_id).find_by_name_and_kind( + let Some(assoc_item) = tcx.associated_items(container_id).find_by_ident_and_kind( tcx, Ident::with_dummy_span(assoc_ty), - AssocKind::Type, + AssocTag::Type, container_id, ) else { debug_assert!(false, "type `{assoc_ty}` not found in `{container_id:?}`"); @@ -1345,7 +1345,7 @@ pub fn get_adt_inherent_method<'a>(cx: &'a LateContext<'_>, ty: Ty<'_>, method_n .associated_items(did) .filter_by_name_unhygienic(method_name) .next() - .filter(|item| item.kind == AssocKind::Fn) + .filter(|item| item.as_tag() == AssocTag::Fn) }) } else { None diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs index e4092bcd1056..df9c4e8e6ae9 100644 --- a/src/tools/clippy/src/driver.rs +++ b/src/tools/clippy/src/driver.rs @@ -160,6 +160,7 @@ impl rustc_driver::Callbacks for ClippyCallbacks { clippy_lints::register_lints(lint_store, conf); clippy_lints::register_pre_expansion_lints(lint_store, conf); })); + config.extra_symbols = clippy_utils::sym::EXTRA_SYMBOLS.into(); // FIXME: #4825; This is required, because Clippy lints that are based on MIR have to be // run on the unoptimized MIR. On the other hand this results in some false negatives. If diff --git a/src/tools/compiletest/Cargo.toml b/src/tools/compiletest/Cargo.toml index 4f8e475e7625..ba1b8f256586 100644 --- a/src/tools/compiletest/Cargo.toml +++ b/src/tools/compiletest/Cargo.toml @@ -1,31 +1,33 @@ [package] name = "compiletest" version = "0.0.0" -edition = "2021" +edition = "2024" [lib] doctest = false [dependencies] +# tidy-alphabetical-start anstyle-svg = "0.1.3" +build_helper = { path = "../../build_helper" } +camino = "1" colored = "2" diff = "0.1.10" -unified-diff = "0.2.1" getopts = "0.2" +glob = "0.3.0" +home = "0.5.5" indexmap = "2.0.0" miropt-test-tools = { path = "../miropt-test-tools" } -build_helper = { path = "../../build_helper" } -tracing = "0.1" -tracing-subscriber = { version = "0.3.3", default-features = false, features = ["ansi", "env-filter", "fmt", "parking_lot", "smallvec"] } regex = "1.0" +rustfix = "0.8.1" semver = { version = "1.0.23", features = ["serde"] } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" -rustfix = "0.8.1" +tracing = "0.1" +tracing-subscriber = { version = "0.3.3", default-features = false, features = ["ansi", "env-filter", "fmt", "parking_lot", "smallvec"] } +unified-diff = "0.2.1" walkdir = "2" -glob = "0.3.0" -anyhow = "1" -home = "0.5.5" +# tidy-alphabetical-end [target.'cfg(unix)'.dependencies] libc = "0.2" diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 9e35d2b46676..31c696ed41ff 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -1,18 +1,17 @@ use std::collections::{BTreeSet, HashMap, HashSet}; -use std::ffi::OsString; -use std::path::{Path, PathBuf}; use std::process::Command; use std::str::FromStr; use std::sync::OnceLock; use std::{fmt, iter}; use build_helper::git::GitConfig; +use camino::{Utf8Path, Utf8PathBuf}; use semver::Version; use serde::de::{Deserialize, Deserializer, Error as _}; pub use self::Mode::*; use crate::executor::{ColorConfig, OutputFormat}; -use crate::util::{PathBufExt, add_dylib_path}; +use crate::util::{Utf8PathBufExt, add_dylib_path}; macro_rules! string_enum { ($(#[$meta:meta])* $vis:vis enum $name:ident { $($variant:ident => $repr:expr,)* }) => { @@ -183,25 +182,25 @@ pub struct Config { pub fail_fast: bool, /// The library paths required for running the compiler. - pub compile_lib_path: PathBuf, + pub compile_lib_path: Utf8PathBuf, /// The library paths required for running compiled programs. - pub run_lib_path: PathBuf, + pub run_lib_path: Utf8PathBuf, /// The rustc executable. - pub rustc_path: PathBuf, + pub rustc_path: Utf8PathBuf, /// The cargo executable. - pub cargo_path: Option, + pub cargo_path: Option, /// Rustc executable used to compile run-make recipes. - pub stage0_rustc_path: Option, + pub stage0_rustc_path: Option, /// The rustdoc executable. - pub rustdoc_path: Option, + pub rustdoc_path: Option, /// The coverage-dump executable. - pub coverage_dump_path: Option, + pub coverage_dump_path: Option, /// The Python executable to use for LLDB and htmldocck. pub python: String, @@ -213,27 +212,27 @@ pub struct Config { pub jsondoclint_path: Option, /// The LLVM `FileCheck` binary path. - pub llvm_filecheck: Option, + pub llvm_filecheck: Option, /// Path to LLVM's bin directory. - pub llvm_bin_dir: Option, + pub llvm_bin_dir: Option, /// The path to the Clang executable to run Clang-based tests with. If /// `None` then these tests will be ignored. pub run_clang_based_tests_with: Option, /// The directory containing the sources. - pub src_root: PathBuf, + pub src_root: Utf8PathBuf, /// The directory containing the test suite sources. Must be a subdirectory of `src_root`. - pub src_test_suite_root: PathBuf, + pub src_test_suite_root: Utf8PathBuf, /// Root build directory (e.g. `build/`). - pub build_root: PathBuf, + pub build_root: Utf8PathBuf, /// Test suite specific build directory (e.g. `build/host/test/ui/`). - pub build_test_suite_root: PathBuf, + pub build_test_suite_root: Utf8PathBuf, /// The directory containing the compiler sysroot - pub sysroot_base: PathBuf, + pub sysroot_base: Utf8PathBuf, /// The number of the stage under test. pub stage: u32, @@ -275,9 +274,6 @@ pub struct Config { /// Explicitly enable or disable running. pub run: Option, - /// Write out a parseable log of tests that were run - pub logfile: Option, - /// A command line to prefix program execution with, /// for running under valgrind for example. /// @@ -304,7 +300,7 @@ pub struct Config { pub host: String, /// Path to / name of the Microsoft Console Debugger (CDB) executable - pub cdb: Option, + pub cdb: Option, /// Version of CDB pub cdb_version: Option<[u16; 4]>, @@ -325,7 +321,7 @@ pub struct Config { pub system_llvm: bool, /// Path to the android tools - pub android_cross_path: PathBuf, + pub android_cross_path: Utf8PathBuf, /// Extra parameter to run adb on arm-linux-androideabi pub adb_path: String, @@ -349,7 +345,7 @@ pub struct Config { pub color: ColorConfig, /// where to find the remote test client process, if we're using it - pub remote_test_client: Option, + pub remote_test_client: Option, /// mode describing what file the actual ui output will be compared to pub compare_mode: Option, @@ -398,6 +394,7 @@ pub struct Config { pub target_cfgs: OnceLock, pub builtin_cfg_names: OnceLock>, + pub supported_crate_types: OnceLock>, pub nocapture: bool, @@ -416,7 +413,12 @@ pub struct Config { /// Path to minicore aux library, used for `no_core` tests that need `core` stubs in /// cross-compilation scenarios that do not otherwise want/need to `-Zbuild-std`. Used in e.g. /// ABI tests. - pub minicore_path: PathBuf, + pub minicore_path: Utf8PathBuf, + + /// If true, run tests with the "new" executor that was written to replace + /// compiletest's dependency on libtest. Eventually this will become the + /// default, and the libtest dependency will be removed. + pub new_executor: bool, } impl Config { @@ -475,6 +477,11 @@ impl Config { self.builtin_cfg_names.get_or_init(|| builtin_cfg_names(self)) } + /// Get the list of crate types that the target platform supports. + pub fn supported_crate_types(&self) -> &HashSet { + self.supported_crate_types.get_or_init(|| supported_crate_types(self)) + } + pub fn has_threads(&self) -> bool { // Wasm targets don't have threads unless `-threads` is in the target // name, such as `wasm32-wasip1-threads`. @@ -748,6 +755,31 @@ fn builtin_cfg_names(config: &Config) -> HashSet { .collect() } +pub const KNOWN_CRATE_TYPES: &[&str] = + &["bin", "cdylib", "dylib", "lib", "proc-macro", "rlib", "staticlib"]; + +fn supported_crate_types(config: &Config) -> HashSet { + let crate_types: HashSet<_> = rustc_output( + config, + &["--target", &config.target, "--print=supported-crate-types", "-Zunstable-options"], + Default::default(), + ) + .lines() + .map(|l| l.to_string()) + .collect(); + + for crate_type in crate_types.iter() { + assert!( + KNOWN_CRATE_TYPES.contains(&crate_type.as_str()), + "unexpected crate type `{}`: known crate types are {:?}", + crate_type, + KNOWN_CRATE_TYPES + ); + } + + crate_types +} + fn rustc_output(config: &Config, args: &[&str], envs: HashMap) -> String { let mut command = Command::new(&config.rustc_path); add_dylib_path(&mut command, iter::once(&config.compile_lib_path)); @@ -776,8 +808,8 @@ fn serde_parse_u32<'de, D: Deserializer<'de>>(deserializer: D) -> Result, compare_mode: &Option, kind: &str, -) -> PathBuf { +) -> Utf8PathBuf { assert!(UI_EXTENSIONS.contains(&kind)); let mut parts = Vec::new(); @@ -837,7 +869,7 @@ pub const UI_COVERAGE_MAP: &str = "cov-map"; /// ``` /// /// This is created early when tests are collected to avoid race conditions. -pub fn output_relative_path(config: &Config, relative_dir: &Path) -> PathBuf { +pub fn output_relative_path(config: &Config, relative_dir: &Utf8Path) -> Utf8PathBuf { config.build_test_suite_root.join(relative_dir) } @@ -846,10 +878,10 @@ pub fn output_testname_unique( config: &Config, testpaths: &TestPaths, revision: Option<&str>, -) -> PathBuf { +) -> Utf8PathBuf { let mode = config.compare_mode.as_ref().map_or("", |m| m.to_str()); let debugger = config.debugger.as_ref().map_or("", |m| m.to_str()); - PathBuf::from(&testpaths.file.file_stem().unwrap()) + Utf8PathBuf::from(&testpaths.file.file_stem().unwrap()) .with_extra_extension(config.mode.output_dir_disambiguator()) .with_extra_extension(revision.unwrap_or("")) .with_extra_extension(mode) @@ -859,7 +891,11 @@ pub fn output_testname_unique( /// Absolute path to the directory where all output for the given /// test/revision should reside. Example: /// /path/to/build/host-tuple/test/ui/relative/testname.revision.mode/ -pub fn output_base_dir(config: &Config, testpaths: &TestPaths, revision: Option<&str>) -> PathBuf { +pub fn output_base_dir( + config: &Config, + testpaths: &TestPaths, + revision: Option<&str>, +) -> Utf8PathBuf { output_relative_path(config, &testpaths.relative_dir) .join(output_testname_unique(config, testpaths, revision)) } @@ -867,12 +903,20 @@ pub fn output_base_dir(config: &Config, testpaths: &TestPaths, revision: Option< /// Absolute path to the base filename used as output for the given /// test/revision. Example: /// /path/to/build/host-tuple/test/ui/relative/testname.revision.mode/testname -pub fn output_base_name(config: &Config, testpaths: &TestPaths, revision: Option<&str>) -> PathBuf { +pub fn output_base_name( + config: &Config, + testpaths: &TestPaths, + revision: Option<&str>, +) -> Utf8PathBuf { output_base_dir(config, testpaths, revision).join(testpaths.file.file_stem().unwrap()) } /// Absolute path to the directory to use for incremental compilation. Example: /// /path/to/build/host-tuple/test/ui/relative/testname.mode/testname.inc -pub fn incremental_dir(config: &Config, testpaths: &TestPaths, revision: Option<&str>) -> PathBuf { +pub fn incremental_dir( + config: &Config, + testpaths: &TestPaths, + revision: Option<&str>, +) -> Utf8PathBuf { output_base_name(config, testpaths, revision).with_extension("inc") } diff --git a/src/tools/compiletest/src/compute_diff.rs b/src/tools/compiletest/src/compute_diff.rs index 4c942c51bae1..509e7e117039 100644 --- a/src/tools/compiletest/src/compute_diff.rs +++ b/src/tools/compiletest/src/compute_diff.rs @@ -1,6 +1,7 @@ use std::collections::VecDeque; use std::fs::{File, FileType}; -use std::path::Path; + +use camino::Utf8Path; #[derive(Debug, PartialEq)] pub enum DiffLine { @@ -112,8 +113,8 @@ pub(crate) fn write_diff(expected: &str, actual: &str, context_size: usize) -> S /// Returns whether any data was actually written. pub(crate) fn write_filtered_diff( diff_filename: &str, - out_dir: &Path, - compare_dir: &Path, + out_dir: &Utf8Path, + compare_dir: &Utf8Path, verbose: bool, filter: Filter, ) -> bool @@ -123,19 +124,21 @@ where use std::io::{Read, Write}; let mut diff_output = File::create(diff_filename).unwrap(); let mut wrote_data = false; - for entry in walkdir::WalkDir::new(out_dir) { + for entry in walkdir::WalkDir::new(out_dir.as_std_path()) { let entry = entry.expect("failed to read file"); let extension = entry.path().extension().and_then(|p| p.to_str()); if filter(entry.file_type(), extension) { - let expected_path = compare_dir.join(entry.path().strip_prefix(&out_dir).unwrap()); + let expected_path = compare_dir + .as_std_path() + .join(entry.path().strip_prefix(&out_dir.as_std_path()).unwrap()); let expected = if let Ok(s) = std::fs::read(&expected_path) { s } else { continue }; let actual_path = entry.path(); let actual = std::fs::read(&actual_path).unwrap(); let diff = unified_diff::diff( &expected, - &expected_path.to_string_lossy(), + &expected_path.to_str().unwrap(), &actual, - &actual_path.to_string_lossy(), + &actual_path.to_str().unwrap(), 3, ); wrote_data |= !diff.is_empty(); diff --git a/src/tools/compiletest/src/debuggers.rs b/src/tools/compiletest/src/debuggers.rs index 20e3c8dfb9ee..c133d7fd4fbd 100644 --- a/src/tools/compiletest/src/debuggers.rs +++ b/src/tools/compiletest/src/debuggers.rs @@ -1,9 +1,9 @@ use std::env; -use std::ffi::OsString; -use std::path::{Path, PathBuf}; use std::process::Command; use std::sync::Arc; +use camino::{Utf8Path, Utf8PathBuf}; + use crate::common::{Config, Debugger}; pub(crate) fn configure_cdb(config: &Config) -> Option> { @@ -40,7 +40,9 @@ pub(crate) fn configure_gdb(config: &Config) -> Option> { // // we should figure out how to lift this restriction! (run them all // on different ports allocated dynamically). - env::set_var("RUST_TEST_THREADS", "1"); + // + // SAFETY: at this point we are still single-threaded. + unsafe { env::set_var("RUST_TEST_THREADS", "1") }; } Some(Arc::new(Config { debugger: Some(Debugger::Gdb), ..config.clone() })) @@ -76,12 +78,15 @@ fn is_pc_windows_msvc_target(target: &str) -> bool { target.ends_with("-pc-windows-msvc") } -fn find_cdb(target: &str) -> Option { +fn find_cdb(target: &str) -> Option { if !(cfg!(windows) && is_pc_windows_msvc_target(target)) { return None; } - let pf86 = env::var_os("ProgramFiles(x86)").or_else(|| env::var_os("ProgramFiles"))?; + let pf86 = Utf8PathBuf::from_path_buf( + env::var_os("ProgramFiles(x86)").or_else(|| env::var_os("ProgramFiles"))?.into(), + ) + .unwrap(); let cdb_arch = if cfg!(target_arch = "x86") { "x86" } else if cfg!(target_arch = "x86_64") { @@ -94,8 +99,7 @@ fn find_cdb(target: &str) -> Option { return None; // No compatible CDB.exe in the Windows 10 SDK }; - let mut path = PathBuf::new(); - path.push(pf86); + let mut path = pf86; path.push(r"Windows Kits\10\Debuggers"); // We could check 8.1 etc. too? path.push(cdb_arch); path.push(r"cdb.exe"); @@ -104,15 +108,15 @@ fn find_cdb(target: &str) -> Option { return None; } - Some(path.into_os_string()) + Some(path) } /// Returns Path to CDB pub(crate) fn analyze_cdb( cdb: Option, target: &str, -) -> (Option, Option<[u16; 4]>) { - let cdb = cdb.map(OsString::from).or_else(|| find_cdb(target)); +) -> (Option, Option<[u16; 4]>) { + let cdb = cdb.map(Utf8PathBuf::from).or_else(|| find_cdb(target)); let mut version = None; if let Some(cdb) = cdb.as_ref() { @@ -141,7 +145,7 @@ pub(crate) fn extract_cdb_version(full_version_line: &str) -> Option<[u16; 4]> { pub(crate) fn analyze_gdb( gdb: Option, target: &str, - android_cross_path: &Path, + android_cross_path: &Utf8Path, ) -> (Option, Option) { #[cfg(not(windows))] const GDB_FALLBACK: &str = "gdb"; @@ -150,10 +154,7 @@ pub(crate) fn analyze_gdb( let fallback_gdb = || { if is_android_gdb_target(target) { - let mut gdb_path = match android_cross_path.to_str() { - Some(x) => x.to_owned(), - None => panic!("cannot find android cross path"), - }; + let mut gdb_path = android_cross_path.to_string(); gdb_path.push_str("/bin/gdb"); gdb_path } else { diff --git a/src/tools/compiletest/src/directive-list.rs b/src/tools/compiletest/src/directive-list.rs index b2ad5a3b3d0b..1449e9af19aa 100644 --- a/src/tools/compiletest/src/directive-list.rs +++ b/src/tools/compiletest/src/directive-list.rs @@ -22,6 +22,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "dont-check-compiler-stderr", "dont-check-compiler-stdout", "dont-check-failure-status", + "dont-require-annotations", "edition", "error-pattern", "exact-llvm-major-version", @@ -43,6 +44,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "ignore-arm-unknown-linux-gnueabihf", "ignore-arm-unknown-linux-musleabi", "ignore-arm-unknown-linux-musleabihf", + "ignore-auxiliary", "ignore-avr", "ignore-beta", "ignore-cdb", @@ -132,6 +134,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "min-llvm-version", "min-system-llvm-version", "needs-asm-support", + "needs-crate-type", "needs-deterministic-layouts", "needs-dlltool", "needs-dynamic-linking", @@ -175,6 +178,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "only-32bit", "only-64bit", "only-aarch64", + "only-aarch64-apple-darwin", "only-aarch64-unknown-linux-gnu", "only-apple", "only-arm", @@ -188,6 +192,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "only-gnu", "only-i686-pc-windows-gnu", "only-i686-pc-windows-msvc", + "only-i686-unknown-linux-gnu", "only-ios", "only-linux", "only-loongarch64", @@ -219,6 +224,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "only-windows-msvc", "only-x86", "only-x86_64", + "only-x86_64-apple-darwin", "only-x86_64-fortanix-unknown-sgx", "only-x86_64-pc-windows-gnu", "only-x86_64-pc-windows-msvc", diff --git a/src/tools/compiletest/src/errors.rs b/src/tools/compiletest/src/errors.rs index b68f817146fd..3bb98276bf52 100644 --- a/src/tools/compiletest/src/errors.rs +++ b/src/tools/compiletest/src/errors.rs @@ -2,14 +2,13 @@ use std::fmt; use std::fs::File; use std::io::BufReader; use std::io::prelude::*; -use std::path::Path; -use std::str::FromStr; use std::sync::OnceLock; +use camino::Utf8Path; use regex::Regex; use tracing::*; -#[derive(Copy, Clone, Debug, PartialEq)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pub enum ErrorKind { Help, Error, @@ -18,30 +17,48 @@ pub enum ErrorKind { Warning, } -impl FromStr for ErrorKind { - type Err = (); - fn from_str(s: &str) -> Result { - let s = s.to_uppercase(); - let part0: &str = s.split(':').next().unwrap(); - match part0 { - "HELP" => Ok(ErrorKind::Help), - "ERROR" => Ok(ErrorKind::Error), - "NOTE" => Ok(ErrorKind::Note), - "SUGGESTION" => Ok(ErrorKind::Suggestion), - "WARN" | "WARNING" => Ok(ErrorKind::Warning), - _ => Err(()), +impl ErrorKind { + pub fn from_compiler_str(s: &str) -> ErrorKind { + match s { + "help" => ErrorKind::Help, + "error" | "error: internal compiler error" => ErrorKind::Error, + "note" | "failure-note" => ErrorKind::Note, + "warning" => ErrorKind::Warning, + _ => panic!("unexpected compiler diagnostic kind `{s}`"), } } + + /// Either the canonical uppercase string, or some additional versions for compatibility. + /// FIXME: consider keeping only the canonical versions here. + fn from_user_str(s: &str) -> Option { + Some(match s { + "HELP" | "help" => ErrorKind::Help, + "ERROR" | "error" => ErrorKind::Error, + "NOTE" | "note" => ErrorKind::Note, + "SUGGESTION" => ErrorKind::Suggestion, + "WARN" | "WARNING" | "warn" | "warning" => ErrorKind::Warning, + _ => return None, + }) + } + + pub fn expect_from_user_str(s: &str) -> ErrorKind { + ErrorKind::from_user_str(s).unwrap_or_else(|| { + panic!( + "unexpected diagnostic kind `{s}`, expected \ + `ERROR`, `WARN`, `NOTE`, `HELP` or `SUGGESTION`" + ) + }) + } } impl fmt::Display for ErrorKind { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { - ErrorKind::Help => write!(f, "help message"), - ErrorKind::Error => write!(f, "error"), - ErrorKind::Note => write!(f, "note"), - ErrorKind::Suggestion => write!(f, "suggestion"), - ErrorKind::Warning => write!(f, "warning"), + ErrorKind::Help => write!(f, "HELP"), + ErrorKind::Error => write!(f, "ERROR"), + ErrorKind::Note => write!(f, "NOTE"), + ErrorKind::Suggestion => write!(f, "SUGGESTION"), + ErrorKind::Warning => write!(f, "WARN"), } } } @@ -53,6 +70,10 @@ pub struct Error { /// `None` if not specified or unknown message kind. pub kind: Option, pub msg: String, + /// For some `Error`s, like secondary lines of multi-line diagnostics, line annotations + /// are not mandatory, even if they would otherwise be mandatory for primary errors. + /// Only makes sense for "actual" errors, not for "expected" errors. + pub require_annotation: bool, } impl Error { @@ -60,7 +81,7 @@ impl Error { use colored::Colorize; format!( "{: <10}line {: >3}: {}", - self.kind.map(|kind| kind.to_string()).unwrap_or_default().to_uppercase(), + self.kind.map(|kind| kind.to_string()).unwrap_or_default(), self.line_num_str(), self.msg.cyan(), ) @@ -81,8 +102,8 @@ impl Error { /// /// If revision is not None, then we look /// for `//[X]~` instead, where `X` is the current revision. -pub fn load_errors(testfile: &Path, revision: Option<&str>) -> Vec { - let rdr = BufReader::new(File::open(testfile).unwrap()); +pub fn load_errors(testfile: &Utf8Path, revision: Option<&str>) -> Vec { + let rdr = BufReader::new(File::open(testfile.as_std_path()).unwrap()); // `last_nonfollow_error` tracks the most recently seen // line with an error template that did not use the @@ -150,18 +171,12 @@ fn parse_expected( } // Get the part of the comment after the sigil (e.g. `~^^` or ~|). - let whole_match = captures.get(0).unwrap(); - let (_, mut msg) = line.split_at(whole_match.end()); - - let first_word = msg.split_whitespace().next().expect("Encountered unexpected empty comment"); - - // If we find `//~ ERROR foo` or something like that, skip the first word. - let kind = first_word.parse::().ok(); - if kind.is_some() { - msg = &msg.trim_start().split_at(first_word.len()).1; - } - - let msg = msg.trim().to_owned(); + let tag = captures.get(0).unwrap(); + let rest = line[tag.end()..].trim_start(); + let (kind_str, _) = rest.split_once(|c: char| !c.is_ascii_alphabetic()).unwrap_or((rest, "")); + let kind = ErrorKind::from_user_str(kind_str); + let untrimmed_msg = if kind.is_some() { &rest[kind_str.len()..] } else { rest }; + let msg = untrimmed_msg.strip_prefix(':').unwrap_or(untrimmed_msg).trim().to_owned(); let line_num_adjust = &captures["adjust"]; let (follow_prev, line_num) = if line_num_adjust == "|" { @@ -177,12 +192,12 @@ fn parse_expected( debug!( "line={:?} tag={:?} follow_prev={:?} kind={:?} msg={:?}", line_num, - whole_match.as_str(), + tag.as_str(), follow_prev, kind, msg ); - Some((follow_prev, Error { line_num, kind, msg })) + Some((follow_prev, Error { line_num, kind, msg, require_annotation: true })) } #[cfg(test)] diff --git a/src/tools/compiletest/src/executor.rs b/src/tools/compiletest/src/executor.rs index 7588fee2b2b0..0c173d476aff 100644 --- a/src/tools/compiletest/src/executor.rs +++ b/src/tools/compiletest/src/executor.rs @@ -1,22 +1,251 @@ -//! This module encapsulates all of the code that interacts directly with -//! libtest, to execute the collected tests. -//! -//! This will hopefully make it easier to migrate away from libtest someday. +//! This module contains a reimplementation of the subset of libtest +//! functionality needed by compiletest. use std::borrow::Cow; -use std::io; -use std::sync::Arc; +use std::collections::HashMap; +use std::hash::{BuildHasherDefault, DefaultHasher}; +use std::num::NonZero; +use std::sync::{Arc, Mutex, mpsc}; +use std::{env, hint, io, mem, panic, thread}; use crate::common::{Config, TestPaths}; -/// Delegates to libtest to run the list of collected tests. -/// -/// Returns `Ok(true)` if all tests passed, or `Ok(false)` if one or more tests failed. -pub(crate) fn execute_tests(config: &Config, tests: Vec) -> io::Result { - let opts = test_opts(config); - let tests = tests.into_iter().map(|t| t.into_libtest()).collect::>(); +mod deadline; +mod json; +pub(crate) mod libtest; - test::run_tests_console(&opts, tests) +pub(crate) fn run_tests(config: &Config, tests: Vec) -> bool { + let tests_len = tests.len(); + let filtered = filter_tests(config, tests); + // Iterator yielding tests that haven't been started yet. + let mut fresh_tests = (0..).map(TestId).zip(&filtered); + + let concurrency = get_concurrency(); + assert!(concurrency > 0); + let concurrent_capacity = concurrency.min(filtered.len()); + + let mut listener = json::Listener::new(); + let mut running_tests = HashMap::with_capacity_and_hasher( + concurrent_capacity, + BuildHasherDefault::::new(), + ); + let mut deadline_queue = deadline::DeadlineQueue::with_capacity(concurrent_capacity); + + let num_filtered_out = tests_len - filtered.len(); + listener.suite_started(filtered.len(), num_filtered_out); + + // Channel used by test threads to report the test outcome when done. + let (completion_tx, completion_rx) = mpsc::channel::(); + + // Unlike libtest, we don't have a separate code path for concurrency=1. + // In that case, the tests will effectively be run serially anyway. + loop { + // Spawn new test threads, up to the concurrency limit. + // FIXME(let_chains): Use a let-chain here when stable in bootstrap. + 'spawn: while running_tests.len() < concurrency { + let Some((id, test)) = fresh_tests.next() else { break 'spawn }; + listener.test_started(test); + deadline_queue.push(id, test); + let join_handle = spawn_test_thread(id, test, completion_tx.clone()); + running_tests.insert(id, RunningTest { test, join_handle }); + } + + // If all running tests have finished, and there weren't any unstarted + // tests to spawn, then we're done. + if running_tests.is_empty() { + break; + } + + let completion = deadline_queue + .read_channel_while_checking_deadlines(&completion_rx, |_id, test| { + listener.test_timed_out(test); + }) + .expect("receive channel should never be closed early"); + + let RunningTest { test, join_handle } = running_tests.remove(&completion.id).unwrap(); + if let Some(join_handle) = join_handle { + join_handle.join().unwrap_or_else(|_| { + panic!("thread for `{}` panicked after reporting completion", test.desc.name) + }); + } + + listener.test_finished(test, &completion); + + if completion.outcome.is_failed() && config.fail_fast { + // Prevent any other in-flight threads from panicking when they + // write to the completion channel. + mem::forget(completion_rx); + break; + } + } + + let suite_passed = listener.suite_finished(); + suite_passed +} + +/// Spawns a thread to run a single test, and returns the thread's join handle. +/// +/// Returns `None` if the test was ignored, so no thread was spawned. +fn spawn_test_thread( + id: TestId, + test: &CollectedTest, + completion_tx: mpsc::Sender, +) -> Option> { + if test.desc.ignore && !test.config.run_ignored { + completion_tx + .send(TestCompletion { id, outcome: TestOutcome::Ignored, stdout: None }) + .unwrap(); + return None; + } + + let runnable_test = RunnableTest::new(test); + let should_panic = test.desc.should_panic; + let run_test = move || run_test_inner(id, should_panic, runnable_test, completion_tx); + + let thread_builder = thread::Builder::new().name(test.desc.name.clone()); + let join_handle = thread_builder.spawn(run_test).unwrap(); + Some(join_handle) +} + +/// Runs a single test, within the dedicated thread spawned by the caller. +fn run_test_inner( + id: TestId, + should_panic: ShouldPanic, + runnable_test: RunnableTest, + completion_sender: mpsc::Sender, +) { + let is_capture = !runnable_test.config.nocapture; + let capture_buf = is_capture.then(|| Arc::new(Mutex::new(vec![]))); + + if let Some(capture_buf) = &capture_buf { + io::set_output_capture(Some(Arc::clone(capture_buf))); + } + + let panic_payload = panic::catch_unwind(move || runnable_test.run()).err(); + + if is_capture { + io::set_output_capture(None); + } + + let outcome = match (should_panic, panic_payload) { + (ShouldPanic::No, None) | (ShouldPanic::Yes, Some(_)) => TestOutcome::Succeeded, + (ShouldPanic::No, Some(_)) => TestOutcome::Failed { message: None }, + (ShouldPanic::Yes, None) => { + TestOutcome::Failed { message: Some("test did not panic as expected") } + } + }; + let stdout = capture_buf.map(|mutex| mutex.lock().unwrap_or_else(|e| e.into_inner()).to_vec()); + + completion_sender.send(TestCompletion { id, outcome, stdout }).unwrap(); +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +struct TestId(usize); + +struct RunnableTest { + config: Arc, + testpaths: TestPaths, + revision: Option, +} + +impl RunnableTest { + fn new(test: &CollectedTest) -> Self { + let config = Arc::clone(&test.config); + let testpaths = test.testpaths.clone(); + let revision = test.revision.clone(); + Self { config, testpaths, revision } + } + + fn run(&self) { + __rust_begin_short_backtrace(|| { + crate::runtest::run( + Arc::clone(&self.config), + &self.testpaths, + self.revision.as_deref(), + ); + }); + } +} + +/// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`. +#[inline(never)] +fn __rust_begin_short_backtrace T>(f: F) -> T { + let result = f(); + + // prevent this frame from being tail-call optimised away + hint::black_box(result) +} + +struct RunningTest<'a> { + test: &'a CollectedTest, + join_handle: Option>, +} + +/// Test completion message sent by individual test threads when their test +/// finishes (successfully or unsuccessfully). +struct TestCompletion { + id: TestId, + outcome: TestOutcome, + stdout: Option>, +} + +#[derive(Clone, Debug, PartialEq, Eq)] +enum TestOutcome { + Succeeded, + Failed { message: Option<&'static str> }, + Ignored, +} + +impl TestOutcome { + fn is_failed(&self) -> bool { + matches!(self, Self::Failed { .. }) + } +} + +/// Applies command-line arguments for filtering/skipping tests by name. +/// +/// Adapted from `filter_tests` in libtest. +/// +/// FIXME(#139660): After the libtest dependency is removed, redesign the whole +/// filtering system to do a better job of understanding and filtering _paths_, +/// instead of being tied to libtest's substring/exact matching behaviour. +fn filter_tests(opts: &Config, tests: Vec) -> Vec { + let mut filtered = tests; + + let matches_filter = |test: &CollectedTest, filter_str: &str| { + let test_name = &test.desc.name; + if opts.filter_exact { test_name == filter_str } else { test_name.contains(filter_str) } + }; + + // Remove tests that don't match the test filter + if !opts.filters.is_empty() { + filtered.retain(|test| opts.filters.iter().any(|filter| matches_filter(test, filter))); + } + + // Skip tests that match any of the skip filters + if !opts.skip.is_empty() { + filtered.retain(|test| !opts.skip.iter().any(|sf| matches_filter(test, sf))); + } + + filtered +} + +/// Determines the number of tests to run concurrently. +/// +/// Copied from `get_concurrency` in libtest. +/// +/// FIXME(#139660): After the libtest dependency is removed, consider making +/// bootstrap specify the number of threads on the command-line, instead of +/// propagating the `RUST_TEST_THREADS` environment variable. +fn get_concurrency() -> usize { + if let Ok(value) = env::var("RUST_TEST_THREADS") { + match value.parse::>().ok() { + Some(n) => n.get(), + _ => panic!("RUST_TEST_THREADS is `{value}`, should be a positive integer."), + } + } else { + thread::available_parallelism().map(|n| n.get()).unwrap_or(1) + } } /// Information needed to create a `test::TestDescAndFn`. @@ -35,45 +264,6 @@ pub(crate) struct CollectedTestDesc { pub(crate) should_panic: ShouldPanic, } -impl CollectedTest { - fn into_libtest(self) -> test::TestDescAndFn { - let Self { desc, config, testpaths, revision } = self; - let CollectedTestDesc { name, ignore, ignore_message, should_panic } = desc; - - // Libtest requires the ignore message to be a &'static str, so we might - // have to leak memory to create it. This is fine, as we only do so once - // per test, so the leak won't grow indefinitely. - let ignore_message = ignore_message.map(|msg| match msg { - Cow::Borrowed(s) => s, - Cow::Owned(s) => &*String::leak(s), - }); - - let desc = test::TestDesc { - name: test::DynTestName(name), - ignore, - ignore_message, - source_file: "", - start_line: 0, - start_col: 0, - end_line: 0, - end_col: 0, - should_panic: should_panic.to_libtest(), - compile_fail: false, - no_run: false, - test_type: test::TestType::Unknown, - }; - - // This closure is invoked when libtest returns control to compiletest - // to execute the test. - let testfn = test::DynTestFn(Box::new(move || { - crate::runtest::run(config, &testpaths, revision.as_deref()); - Ok(()) - })); - - test::TestDescAndFn { desc, testfn } - } -} - /// Whether console output should be colored or not. #[derive(Copy, Clone, Default, Debug)] pub enum ColorConfig { @@ -83,16 +273,6 @@ pub enum ColorConfig { NeverColor, } -impl ColorConfig { - fn to_libtest(self) -> test::ColorConfig { - match self { - Self::AutoColor => test::ColorConfig::AutoColor, - Self::AlwaysColor => test::ColorConfig::AlwaysColor, - Self::NeverColor => test::ColorConfig::NeverColor, - } - } -} - /// Format of the test results output. #[derive(Copy, Clone, Debug, Default, PartialEq, Eq)] pub enum OutputFormat { @@ -105,52 +285,9 @@ pub enum OutputFormat { Json, } -impl OutputFormat { - fn to_libtest(self) -> test::OutputFormat { - match self { - Self::Pretty => test::OutputFormat::Pretty, - Self::Terse => test::OutputFormat::Terse, - Self::Json => test::OutputFormat::Json, - } - } -} - /// Whether test is expected to panic or not. #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pub(crate) enum ShouldPanic { No, Yes, } - -impl ShouldPanic { - fn to_libtest(self) -> test::ShouldPanic { - match self { - Self::No => test::ShouldPanic::No, - Self::Yes => test::ShouldPanic::Yes, - } - } -} - -fn test_opts(config: &Config) -> test::TestOpts { - test::TestOpts { - exclude_should_panic: false, - filters: config.filters.clone(), - filter_exact: config.filter_exact, - run_ignored: if config.run_ignored { test::RunIgnored::Yes } else { test::RunIgnored::No }, - format: config.format.to_libtest(), - logfile: config.logfile.clone(), - run_tests: true, - bench_benchmarks: true, - nocapture: config.nocapture, - color: config.color.to_libtest(), - shuffle: false, - shuffle_seed: None, - test_threads: None, - skip: config.skip.clone(), - list: false, - options: test::Options::new(), - time_options: None, - force_run_in_process: false, - fail_fast: config.fail_fast, - } -} diff --git a/src/tools/compiletest/src/executor/deadline.rs b/src/tools/compiletest/src/executor/deadline.rs new file mode 100644 index 000000000000..83b8591a4164 --- /dev/null +++ b/src/tools/compiletest/src/executor/deadline.rs @@ -0,0 +1,78 @@ +use std::collections::VecDeque; +use std::sync::mpsc::{self, RecvError, RecvTimeoutError}; +use std::time::{Duration, Instant}; + +use crate::executor::{CollectedTest, TestId}; + +const TEST_WARN_TIMEOUT_S: u64 = 60; + +struct DeadlineEntry<'a> { + id: TestId, + test: &'a CollectedTest, + deadline: Instant, +} + +pub(crate) struct DeadlineQueue<'a> { + queue: VecDeque>, +} + +impl<'a> DeadlineQueue<'a> { + pub(crate) fn with_capacity(capacity: usize) -> Self { + Self { queue: VecDeque::with_capacity(capacity) } + } + + pub(crate) fn push(&mut self, id: TestId, test: &'a CollectedTest) { + let deadline = Instant::now() + Duration::from_secs(TEST_WARN_TIMEOUT_S); + self.queue.push_back(DeadlineEntry { id, test, deadline }); + } + + /// Equivalent to `rx.read()`, except that if any test exceeds its deadline + /// during the wait, the given callback will also be called for that test. + pub(crate) fn read_channel_while_checking_deadlines( + &mut self, + rx: &mpsc::Receiver, + mut on_deadline_passed: impl FnMut(TestId, &CollectedTest), + ) -> Result { + loop { + let Some(next_deadline) = self.next_deadline() else { + // All currently-running tests have already exceeded their + // deadline, so do a normal receive. + return rx.recv(); + }; + let wait_duration = next_deadline.saturating_duration_since(Instant::now()); + + let recv_result = rx.recv_timeout(wait_duration); + match recv_result { + Ok(value) => return Ok(value), + Err(RecvTimeoutError::Timeout) => { + // Notify the callback of tests that have exceeded their + // deadline, then loop and do annother channel read. + for DeadlineEntry { id, test, .. } in self.remove_tests_past_deadline() { + on_deadline_passed(id, test); + } + } + Err(RecvTimeoutError::Disconnected) => return Err(RecvError), + } + } + } + + fn next_deadline(&self) -> Option { + Some(self.queue.front()?.deadline) + } + + fn remove_tests_past_deadline(&mut self) -> Vec> { + let now = Instant::now(); + let mut timed_out = vec![]; + while let Some(deadline_entry) = pop_front_if(&mut self.queue, |entry| now < entry.deadline) + { + timed_out.push(deadline_entry); + } + timed_out + } +} + +/// FIXME(vec_deque_pop_if): Use `VecDeque::pop_front_if` when it is stable in bootstrap. +fn pop_front_if(queue: &mut VecDeque, predicate: impl FnOnce(&T) -> bool) -> Option { + let first = queue.front()?; + if predicate(first) { queue.pop_front() } else { None } +} diff --git a/src/tools/compiletest/src/executor/json.rs b/src/tools/compiletest/src/executor/json.rs new file mode 100644 index 000000000000..c74ed81a36b8 --- /dev/null +++ b/src/tools/compiletest/src/executor/json.rs @@ -0,0 +1,111 @@ +//! Collects statistics and emits suite/test events as JSON messages, using +//! the same JSON format as libtest's JSON formatter. +//! +//! These messages are then parsed by bootstrap, which replaces them with +//! user-friendly terminal output. + +use std::time::Instant; + +use serde_json::json; + +use crate::executor::{CollectedTest, TestCompletion, TestOutcome}; + +pub(crate) struct Listener { + suite_start: Option, + passed: usize, + failed: usize, + ignored: usize, + filtered_out: usize, +} + +impl Listener { + pub(crate) fn new() -> Self { + Self { suite_start: None, passed: 0, failed: 0, ignored: 0, filtered_out: 0 } + } + + fn print_message(&self, message: &serde_json::Value) { + println!("{message}"); + } + + fn now(&self) -> Instant { + Instant::now() + } + + pub(crate) fn suite_started(&mut self, test_count: usize, filtered_out: usize) { + self.suite_start = Some(self.now()); + self.filtered_out = filtered_out; + let message = json!({ "type": "suite", "event": "started", "test_count": test_count }); + self.print_message(&message); + } + + pub(crate) fn test_started(&mut self, test: &CollectedTest) { + let name = test.desc.name.as_str(); + let message = json!({ "type": "test", "event": "started", "name": name }); + self.print_message(&message); + } + + pub(crate) fn test_timed_out(&mut self, test: &CollectedTest) { + let name = test.desc.name.as_str(); + let message = json!({ "type": "test", "event": "timeout", "name": name }); + self.print_message(&message); + } + + pub(crate) fn test_finished(&mut self, test: &CollectedTest, completion: &TestCompletion) { + let event; + let name = test.desc.name.as_str(); + let mut maybe_message = None; + let maybe_stdout = completion.stdout.as_deref().map(String::from_utf8_lossy); + + match completion.outcome { + TestOutcome::Succeeded => { + self.passed += 1; + event = "ok"; + } + TestOutcome::Failed { message } => { + self.failed += 1; + maybe_message = message; + event = "failed"; + } + TestOutcome::Ignored => { + self.ignored += 1; + maybe_message = test.desc.ignore_message.as_deref(); + event = "ignored"; + } + }; + + // This emits optional fields as `null`, instead of omitting them + // completely as libtest does, but bootstrap can parse the result + // either way. + let json = json!({ + "type": "test", + "event": event, + "name": name, + "message": maybe_message, + "stdout": maybe_stdout, + }); + + self.print_message(&json); + } + + pub(crate) fn suite_finished(&mut self) -> bool { + let exec_time = self.suite_start.map(|start| (self.now() - start).as_secs_f64()); + let suite_passed = self.failed == 0; + + let event = if suite_passed { "ok" } else { "failed" }; + let message = json!({ + "type": "suite", + "event": event, + "passed": self.passed, + "failed": self.failed, + "ignored": self.ignored, + // Compiletest doesn't run any benchmarks, but we still need to set this + // field to 0 so that bootstrap's JSON parser can read our message. + "measured": 0, + "filtered_out": self.filtered_out, + "exec_time": exec_time, + }); + + self.print_message(&message); + suite_passed + } +} diff --git a/src/tools/compiletest/src/executor/libtest.rs b/src/tools/compiletest/src/executor/libtest.rs new file mode 100644 index 000000000000..032b3f4fa9a8 --- /dev/null +++ b/src/tools/compiletest/src/executor/libtest.rs @@ -0,0 +1,111 @@ +//! This submodule encapsulates all of the code that actually interacts with +//! libtest, so that it can be easily removed after the new executor becomes +//! the default. + +use std::borrow::Cow; +use std::io; + +use crate::common::Config; +use crate::executor::{CollectedTest, CollectedTestDesc, ColorConfig, OutputFormat, ShouldPanic}; + +/// Delegates to libtest to run the list of collected tests. +/// +/// Returns `Ok(true)` if all tests passed, or `Ok(false)` if one or more tests failed. +pub(crate) fn execute_tests(config: &Config, tests: Vec) -> io::Result { + let opts = test_opts(config); + let tests = tests.into_iter().map(|t| t.into_libtest()).collect::>(); + + test::run_tests_console(&opts, tests) +} + +impl CollectedTest { + fn into_libtest(self) -> test::TestDescAndFn { + let Self { desc, config, testpaths, revision } = self; + let CollectedTestDesc { name, ignore, ignore_message, should_panic } = desc; + + // Libtest requires the ignore message to be a &'static str, so we might + // have to leak memory to create it. This is fine, as we only do so once + // per test, so the leak won't grow indefinitely. + let ignore_message = ignore_message.map(|msg| match msg { + Cow::Borrowed(s) => s, + Cow::Owned(s) => &*String::leak(s), + }); + + let desc = test::TestDesc { + name: test::DynTestName(name), + ignore, + ignore_message, + source_file: "", + start_line: 0, + start_col: 0, + end_line: 0, + end_col: 0, + should_panic: should_panic.to_libtest(), + compile_fail: false, + no_run: false, + test_type: test::TestType::Unknown, + }; + + // This closure is invoked when libtest returns control to compiletest + // to execute the test. + let testfn = test::DynTestFn(Box::new(move || { + crate::runtest::run(config, &testpaths, revision.as_deref()); + Ok(()) + })); + + test::TestDescAndFn { desc, testfn } + } +} + +impl ColorConfig { + fn to_libtest(self) -> test::ColorConfig { + match self { + Self::AutoColor => test::ColorConfig::AutoColor, + Self::AlwaysColor => test::ColorConfig::AlwaysColor, + Self::NeverColor => test::ColorConfig::NeverColor, + } + } +} + +impl OutputFormat { + fn to_libtest(self) -> test::OutputFormat { + match self { + Self::Pretty => test::OutputFormat::Pretty, + Self::Terse => test::OutputFormat::Terse, + Self::Json => test::OutputFormat::Json, + } + } +} + +impl ShouldPanic { + fn to_libtest(self) -> test::ShouldPanic { + match self { + Self::No => test::ShouldPanic::No, + Self::Yes => test::ShouldPanic::Yes, + } + } +} + +fn test_opts(config: &Config) -> test::TestOpts { + test::TestOpts { + exclude_should_panic: false, + filters: config.filters.clone(), + filter_exact: config.filter_exact, + run_ignored: if config.run_ignored { test::RunIgnored::Yes } else { test::RunIgnored::No }, + format: config.format.to_libtest(), + logfile: None, + run_tests: true, + bench_benchmarks: true, + nocapture: config.nocapture, + color: config.color.to_libtest(), + shuffle: false, + shuffle_seed: None, + test_threads: None, + skip: config.skip.clone(), + list: false, + options: test::Options::new(), + time_options: None, + force_run_in_process: false, + fail_fast: config.fail_fast, + } +} diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index a0178f4bcc57..2b203bb309c6 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -3,14 +3,15 @@ use std::env; use std::fs::File; use std::io::BufReader; use std::io::prelude::*; -use std::path::{Path, PathBuf}; use std::process::Command; +use camino::{Utf8Path, Utf8PathBuf}; use semver::Version; use tracing::*; use crate::common::{Config, Debugger, FailMode, Mode, PassMode}; use crate::debuggers::{extract_cdb_version, extract_gdb_version}; +use crate::errors::ErrorKind; use crate::executor::{CollectedTestDesc, ShouldPanic}; use crate::header::auxiliary::{AuxProps, parse_and_update_aux}; use crate::header::needs::CachedNeedsConditions; @@ -44,12 +45,12 @@ pub struct EarlyProps { } impl EarlyProps { - pub fn from_file(config: &Config, testfile: &Path) -> Self { - let file = File::open(testfile).expect("open test file to parse earlyprops"); + pub fn from_file(config: &Config, testfile: &Utf8Path) -> Self { + let file = File::open(testfile.as_std_path()).expect("open test file to parse earlyprops"); Self::from_reader(config, testfile, file) } - pub fn from_reader(config: &Config, testfile: &Path, rdr: R) -> Self { + pub fn from_reader(config: &Config, testfile: &Utf8Path, rdr: R) -> Self { let mut props = EarlyProps::default(); let mut poisoned = false; iter_header( @@ -65,7 +66,7 @@ impl EarlyProps { ); if poisoned { - eprintln!("errors encountered during EarlyProps parsing: {}", testfile.display()); + eprintln!("errors encountered during EarlyProps parsing: {}", testfile); panic!("errors encountered during EarlyProps parsing"); } @@ -87,7 +88,7 @@ pub struct TestProps { pub doc_flags: Vec, // If present, the name of a file that this test should match when // pretty-printed - pub pp_exact: Option, + pub pp_exact: Option, /// Auxiliary crates that should be built and made available to this test. pub(crate) aux: AuxProps, // Environment settings to use for compiling @@ -133,7 +134,7 @@ pub struct TestProps { // not set by end-users; rather it is set by the incremental // testing harness and used when generating compilation // arguments. (In particular, it propagates to the aux-builds.) - pub incremental_dir: Option, + pub incremental_dir: Option, // If `true`, this test will use incremental compilation. // // This can be set manually with the `incremental` header, or implicitly @@ -196,6 +197,8 @@ pub struct TestProps { /// Build and use `minicore` as `core` stub for `no_core` tests in cross-compilation scenarios /// that don't otherwise want/need `-Z build-std`. pub add_core_stubs: bool, + /// Whether line annotatins are required for the given error kind. + pub dont_require_annotations: HashSet, } mod directives { @@ -212,6 +215,7 @@ mod directives { pub const CHECK_RUN_RESULTS: &'static str = "check-run-results"; pub const DONT_CHECK_COMPILER_STDOUT: &'static str = "dont-check-compiler-stdout"; pub const DONT_CHECK_COMPILER_STDERR: &'static str = "dont-check-compiler-stderr"; + pub const DONT_REQUIRE_ANNOTATIONS: &'static str = "dont-require-annotations"; pub const NO_PREFER_DYNAMIC: &'static str = "no-prefer-dynamic"; pub const PRETTY_MODE: &'static str = "pretty-mode"; pub const PRETTY_COMPARE_ONLY: &'static str = "pretty-compare-only"; @@ -297,10 +301,16 @@ impl TestProps { no_auto_check_cfg: false, has_enzyme: false, add_core_stubs: false, + dont_require_annotations: Default::default(), } } - pub fn from_aux_file(&self, testfile: &Path, revision: Option<&str>, config: &Config) -> Self { + pub fn from_aux_file( + &self, + testfile: &Utf8Path, + revision: Option<&str>, + config: &Config, + ) -> Self { let mut props = TestProps::new(); // copy over select properties to the aux build: @@ -311,10 +321,10 @@ impl TestProps { props } - pub fn from_file(testfile: &Path, revision: Option<&str>, config: &Config) -> Self { + pub fn from_file(testfile: &Utf8Path, revision: Option<&str>, config: &Config) -> Self { let mut props = TestProps::new(); props.load_from(testfile, revision, config); - props.exec_env.push(("RUSTC".to_string(), config.rustc_path.display().to_string())); + props.exec_env.push(("RUSTC".to_string(), config.rustc_path.to_string())); match (props.pass_mode, props.fail_mode) { (None, None) if config.mode == Mode::Ui => props.fail_mode = Some(FailMode::Check), @@ -329,10 +339,10 @@ impl TestProps { /// tied to a particular revision `foo` (indicated by writing /// `//@[foo]`), then the property is ignored unless `test_revision` is /// `Some("foo")`. - fn load_from(&mut self, testfile: &Path, test_revision: Option<&str>, config: &Config) { + fn load_from(&mut self, testfile: &Utf8Path, test_revision: Option<&str>, config: &Config) { let mut has_edition = false; if !testfile.is_dir() { - let file = File::open(testfile).unwrap(); + let file = File::open(testfile.as_std_path()).unwrap(); let mut poisoned = false; @@ -378,14 +388,22 @@ impl TestProps { } if let Some(flags) = config.parse_name_value_directive(ln, COMPILE_FLAGS) { - self.compile_flags.extend(split_flags(&flags)); + let flags = split_flags(&flags); + for flag in &flags { + if flag == "--edition" || flag.starts_with("--edition=") { + panic!("you must use `//@ edition` to configure the edition"); + } + } + self.compile_flags.extend(flags); } if config.parse_name_value_directive(ln, INCORRECT_COMPILER_FLAGS).is_some() { panic!("`compiler-flags` directive should be spelled `compile-flags`"); } if let Some(edition) = config.parse_edition(ln) { - self.compile_flags.push(format!("--edition={}", edition.trim())); + // The edition is added at the start, since flags from //@compile-flags must + // be passed to rustc last. + self.compile_flags.insert(0, format!("--edition={}", edition.trim())); has_edition = true; } @@ -441,7 +459,7 @@ impl TestProps { ln, UNSET_EXEC_ENV, &mut self.unset_exec_env, - |r| r, + |r| r.trim().to_owned(), ); config.push_name_value_directive( ln, @@ -453,7 +471,7 @@ impl TestProps { ln, UNSET_RUSTC_ENV, &mut self.unset_rustc_env, - |r| r, + |r| r.trim().to_owned(), ); config.push_name_value_directive( ln, @@ -570,11 +588,18 @@ impl TestProps { config.set_name_directive(ln, NO_AUTO_CHECK_CFG, &mut self.no_auto_check_cfg); self.update_add_core_stubs(ln, config); + + if let Some(err_kind) = + config.parse_name_value_directive(ln, DONT_REQUIRE_ANNOTATIONS) + { + self.dont_require_annotations + .insert(ErrorKind::expect_from_user_str(err_kind.trim())); + } }, ); if poisoned { - eprintln!("errors encountered during TestProps parsing: {}", testfile.display()); + eprintln!("errors encountered during TestProps parsing: {}", testfile); panic!("errors encountered during TestProps parsing"); } } @@ -606,7 +631,9 @@ impl TestProps { } if let (Some(edition), false) = (&config.edition, has_edition) { - self.compile_flags.push(format!("--edition={}", edition)); + // The edition is added at the start, since flags from //@compile-flags must be passed + // to rustc last. + self.compile_flags.insert(0, format!("--edition={}", edition)); } } @@ -843,7 +870,7 @@ fn iter_header( mode: Mode, _suite: &str, poisoned: &mut bool, - testfile: &Path, + testfile: &Utf8Path, rdr: impl Read, it: &mut dyn FnMut(DirectiveLine<'_>), ) { @@ -895,9 +922,7 @@ fn iter_header( eprintln!( "error: detected unknown compiletest test directive `{}` in {}:{}", - directive_line.raw_directive, - testfile.display(), - line_number, + directive_line.raw_directive, testfile, line_number, ); return; @@ -909,10 +934,7 @@ fn iter_header( eprintln!( "error: detected trailing compiletest test directive `{}` in {}:{}\n \ help: put the trailing directive in it's own line: `//@ {}`", - trailing_directive, - testfile.display(), - line_number, - trailing_directive, + trailing_directive, testfile, line_number, trailing_directive, ); return; @@ -924,7 +946,12 @@ fn iter_header( } impl Config { - fn parse_and_update_revisions(&self, testfile: &Path, line: &str, existing: &mut Vec) { + fn parse_and_update_revisions( + &self, + testfile: &Utf8Path, + line: &str, + existing: &mut Vec, + ) { const FORBIDDEN_REVISION_NAMES: [&str; 2] = [ // `//@ revisions: true false` Implying `--cfg=true` and `--cfg=false` makes it very // weird for the test, since if the test writer wants a cfg of the same revision name @@ -937,26 +964,19 @@ impl Config { if let Some(raw) = self.parse_name_value_directive(line, "revisions") { if self.mode == Mode::RunMake { - panic!("`run-make` tests do not support revisions: {}", testfile.display()); + panic!("`run-make` tests do not support revisions: {}", testfile); } let mut duplicates: HashSet<_> = existing.iter().cloned().collect(); for revision in raw.split_whitespace() { if !duplicates.insert(revision.to_string()) { - panic!( - "duplicate revision: `{}` in line `{}`: {}", - revision, - raw, - testfile.display() - ); + panic!("duplicate revision: `{}` in line `{}`: {}", revision, raw, testfile); } if FORBIDDEN_REVISION_NAMES.contains(&revision) { panic!( "revision name `{revision}` is not permitted: `{}` in line `{}`: {}", - revision, - raw, - testfile.display() + revision, raw, testfile ); } @@ -967,8 +987,7 @@ impl Config { "revision name `{revision}` is not permitted in a test suite that uses \ `FileCheck` annotations as it is confusing when used as custom `FileCheck` \ prefix: `{revision}` in line `{}`: {}", - raw, - testfile.display() + raw, testfile ); } @@ -979,23 +998,20 @@ impl Config { fn parse_env(nv: String) -> (String, String) { // nv is either FOO or FOO=BAR - let mut strs: Vec = nv.splitn(2, '=').map(str::to_owned).collect(); - - match strs.len() { - 1 => (strs.pop().unwrap(), String::new()), - 2 => { - let end = strs.pop().unwrap(); - (strs.pop().unwrap(), end) - } - n => panic!("Expected 1 or 2 strings, not {}", n), - } + // FIXME(Zalathar): The form without `=` seems to be unused; should + // we drop support for it? + let (name, value) = nv.split_once('=').unwrap_or((&nv, "")); + // Trim whitespace from the name, so that `//@ exec-env: FOO=BAR` + // sees the name as `FOO` and not ` FOO`. + let name = name.trim(); + (name.to_owned(), value.to_owned()) } - fn parse_pp_exact(&self, line: &str, testfile: &Path) -> Option { + fn parse_pp_exact(&self, line: &str, testfile: &Utf8Path) -> Option { if let Some(s) = self.parse_name_value_directive(line, "pp-exact") { - Some(PathBuf::from(&s)) + Some(Utf8PathBuf::from(&s)) } else if self.parse_name_directive(line, "pp-exact") { - testfile.file_name().map(PathBuf::from) + testfile.file_name().map(Utf8PathBuf::from) } else { None } @@ -1101,20 +1117,19 @@ fn expand_variables(mut value: String, config: &Config) -> String { if value.contains(CWD) { let cwd = env::current_dir().unwrap(); - value = value.replace(CWD, &cwd.to_string_lossy()); + value = value.replace(CWD, &cwd.to_str().unwrap()); } if value.contains(SRC_BASE) { - value = value.replace(SRC_BASE, &config.src_test_suite_root.to_str().unwrap()); + value = value.replace(SRC_BASE, &config.src_test_suite_root.as_str()); } if value.contains(TEST_SUITE_BUILD_BASE) { - value = - value.replace(TEST_SUITE_BUILD_BASE, &config.build_test_suite_root.to_str().unwrap()); + value = value.replace(TEST_SUITE_BUILD_BASE, &config.build_test_suite_root.as_str()); } if value.contains(SYSROOT_BASE) { - value = value.replace(SYSROOT_BASE, &config.sysroot_base.to_str().unwrap()); + value = value.replace(SYSROOT_BASE, &config.sysroot_base.as_str()); } if value.contains(TARGET_LINKER) { @@ -1127,9 +1142,9 @@ fn expand_variables(mut value: String, config: &Config) -> String { if value.contains(RUST_SRC_BASE) { let src_base = config.sysroot_base.join("lib/rustlib/src/rust"); - src_base.try_exists().expect(&*format!("{} should exists", src_base.display())); - let src_base = src_base.read_link().unwrap_or(src_base); - value = value.replace(RUST_SRC_BASE, &src_base.to_string_lossy()); + src_base.try_exists().expect(&*format!("{} should exists", src_base)); + let src_base = src_base.read_link_utf8().unwrap_or(src_base); + value = value.replace(RUST_SRC_BASE, &src_base.as_str()); } value @@ -1232,14 +1247,14 @@ pub fn llvm_has_libzstd(config: &Config) -> bool { // contains a path to that static lib, and that it exists. // // See compiler/rustc_llvm/build.rs for more details and similar expectations. - fn is_zstd_in_config(llvm_bin_dir: &Path) -> Option<()> { + fn is_zstd_in_config(llvm_bin_dir: &Utf8Path) -> Option<()> { let llvm_config_path = llvm_bin_dir.join("llvm-config"); let output = Command::new(llvm_config_path).arg("--system-libs").output().ok()?; assert!(output.status.success(), "running llvm-config --system-libs failed"); let libs = String::from_utf8(output.stdout).ok()?; for lib in libs.split_whitespace() { - if lib.ends_with("libzstd.a") && Path::new(lib).exists() { + if lib.ends_with("libzstd.a") && Utf8Path::new(lib).exists() { return Some(()); } } @@ -1257,7 +1272,7 @@ pub fn llvm_has_libzstd(config: &Config) -> bool { // `lld` supports it. If not, an error will be emitted: "LLVM was not built with // LLVM_ENABLE_ZSTD or did not find zstd at build time". #[cfg(unix)] - fn is_lld_built_with_zstd(llvm_bin_dir: &Path) -> Option<()> { + fn is_lld_built_with_zstd(llvm_bin_dir: &Utf8Path) -> Option<()> { let lld_path = llvm_bin_dir.join("lld"); if lld_path.exists() { // We can't call `lld` as-is, it expects to be invoked by a compiler driver using a @@ -1293,7 +1308,7 @@ pub fn llvm_has_libzstd(config: &Config) -> bool { } #[cfg(not(unix))] - fn is_lld_built_with_zstd(_llvm_bin_dir: &Path) -> Option<()> { + fn is_lld_built_with_zstd(_llvm_bin_dir: &Utf8Path) -> Option<()> { None } @@ -1360,7 +1375,7 @@ pub(crate) fn make_test_description( config: &Config, cache: &HeadersCache, name: String, - path: &Path, + path: &Utf8Path, src: R, test_revision: Option<&str>, poisoned: &mut bool, @@ -1391,7 +1406,7 @@ pub(crate) fn make_test_description( ignore_message = Some(reason.into()); } IgnoreDecision::Error { message } => { - eprintln!("error: {}:{line_number}: {message}", path.display()); + eprintln!("error: {}:{line_number}: {message}", path); *poisoned = true; return; } @@ -1421,7 +1436,7 @@ pub(crate) fn make_test_description( ); if local_poisoned { - eprintln!("errors encountered when trying to make test description: {}", path.display()); + eprintln!("errors encountered when trying to make test description: {}", path); panic!("errors encountered when trying to make test description"); } @@ -1530,7 +1545,7 @@ fn ignore_lldb(config: &Config, line: &str) -> IgnoreDecision { IgnoreDecision::Continue } -fn ignore_llvm(config: &Config, path: &Path, line: &str) -> IgnoreDecision { +fn ignore_llvm(config: &Config, path: &Utf8Path, line: &str) -> IgnoreDecision { if let Some(needed_components) = config.parse_name_value_directive(line, "needs-llvm-components") { @@ -1542,8 +1557,7 @@ fn ignore_llvm(config: &Config, path: &Path, line: &str) -> IgnoreDecision { if env::var_os("COMPILETEST_REQUIRE_ALL_LLVM_COMPONENTS").is_some() { panic!( "missing LLVM component {}, and COMPILETEST_REQUIRE_ALL_LLVM_COMPONENTS is set: {}", - missing_component, - path.display() + missing_component, path ); } return IgnoreDecision::Ignore { diff --git a/src/tools/compiletest/src/header/cfg.rs b/src/tools/compiletest/src/header/cfg.rs index c369fff97f4f..f1f1384afb97 100644 --- a/src/tools/compiletest/src/header/cfg.rs +++ b/src/tools/compiletest/src/header/cfg.rs @@ -100,6 +100,10 @@ fn parse_cfg_name_directive<'a>( name: "test", message: "always" } + condition! { + name: "auxiliary", + message: "used by another main test file" + } condition! { name: &config.target, allowed_names: &target_cfgs.all_targets, diff --git a/src/tools/compiletest/src/header/needs.rs b/src/tools/compiletest/src/header/needs.rs index 12f0790fb104..2ace40c490bf 100644 --- a/src/tools/compiletest/src/header/needs.rs +++ b/src/tools/compiletest/src/header/needs.rs @@ -1,4 +1,4 @@ -use crate::common::{Config, KNOWN_TARGET_HAS_ATOMIC_WIDTHS, Sanitizer}; +use crate::common::{Config, KNOWN_CRATE_TYPES, KNOWN_TARGET_HAS_ATOMIC_WIDTHS, Sanitizer}; use crate::header::{IgnoreDecision, llvm_has_libzstd}; pub(super) fn handle_needs( @@ -6,7 +6,7 @@ pub(super) fn handle_needs( config: &Config, ln: &str, ) -> IgnoreDecision { - // Note thet we intentionally still put the needs- prefix here to make the file show up when + // Note that we intentionally still put the needs- prefix here to make the file show up when // grepping for a directive name, even though we could technically strip that. let needs = &[ Need { @@ -224,6 +224,50 @@ pub(super) fn handle_needs( } } + // FIXME(jieyouxu): share multi-value directive logic with `needs-target-has-atomic` above. + if name == "needs-crate-type" { + let Some(rest) = rest else { + return IgnoreDecision::Error { + message: + "expected `needs-crate-type` to have a comma-separated list of crate types" + .to_string(), + }; + }; + + // Expect directive value to be a list of comma-separated crate-types. + let specified_crate_types = rest + .split(',') + .map(|crate_type| crate_type.trim()) + .map(ToString::to_string) + .collect::>(); + + for crate_type in &specified_crate_types { + if !KNOWN_CRATE_TYPES.contains(&crate_type.as_str()) { + return IgnoreDecision::Error { + message: format!( + "unknown crate type specified in `needs-crate-type`: `{crate_type}` is not \ + a known crate type, known values are `{:?}`", + KNOWN_CRATE_TYPES + ), + }; + } + } + + let satisfies_all_crate_types = specified_crate_types + .iter() + .all(|specified| config.supported_crate_types().contains(specified)); + if satisfies_all_crate_types { + return IgnoreDecision::Continue; + } else { + return IgnoreDecision::Ignore { + reason: format!( + "skipping test as target does not support all of the crate types `{:?}`", + specified_crate_types + ), + }; + } + } + if !name.starts_with("needs-") { return IgnoreDecision::Continue; } diff --git a/src/tools/compiletest/src/header/tests.rs b/src/tools/compiletest/src/header/tests.rs index ff6bc49b72a1..2525e0adc838 100644 --- a/src/tools/compiletest/src/header/tests.rs +++ b/src/tools/compiletest/src/header/tests.rs @@ -1,6 +1,6 @@ use std::io::Read; -use std::path::Path; +use camino::Utf8Path; use semver::Version; use super::{ @@ -13,7 +13,7 @@ use crate::executor::{CollectedTestDesc, ShouldPanic}; fn make_test_description( config: &Config, name: String, - path: &Path, + path: &Utf8Path, src: R, revision: Option<&str>, ) -> CollectedTestDesc { @@ -230,12 +230,12 @@ fn cfg() -> ConfigBuilder { fn parse_rs(config: &Config, contents: &str) -> EarlyProps { let bytes = contents.as_bytes(); - EarlyProps::from_reader(config, Path::new("a.rs"), bytes) + EarlyProps::from_reader(config, Utf8Path::new("a.rs"), bytes) } fn check_ignore(config: &Config, contents: &str) -> bool { let tn = String::new(); - let p = Path::new("a.rs"); + let p = Utf8Path::new("a.rs"); let d = make_test_description(&config, tn, p, std::io::Cursor::new(contents), None); d.ignore } @@ -244,7 +244,7 @@ fn check_ignore(config: &Config, contents: &str) -> bool { fn should_fail() { let config: Config = cfg().build(); let tn = String::new(); - let p = Path::new("a.rs"); + let p = Utf8Path::new("a.rs"); let d = make_test_description(&config, tn.clone(), p, std::io::Cursor::new(""), None); assert_eq!(d.should_panic, ShouldPanic::No); @@ -459,9 +459,6 @@ fn profiler_runtime() { #[test] fn asm_support() { let asms = [ - #[cfg(bootstrap)] - ("avr-unknown-gnu-atmega328", false), - #[cfg(not(bootstrap))] ("avr-none", false), ("i686-unknown-netbsd", true), ("riscv32gc-unknown-linux-gnu", true), @@ -787,7 +784,7 @@ fn threads_support() { } } -fn run_path(poisoned: &mut bool, path: &Path, buf: &[u8]) { +fn run_path(poisoned: &mut bool, path: &Utf8Path, buf: &[u8]) { let rdr = std::io::Cursor::new(&buf); iter_header(Mode::Ui, "ui", poisoned, path, rdr, &mut |_| {}); } @@ -797,7 +794,7 @@ fn test_unknown_directive_check() { let mut poisoned = false; run_path( &mut poisoned, - Path::new("a.rs"), + Utf8Path::new("a.rs"), include_bytes!("./test-auxillary/unknown_directive.rs"), ); assert!(poisoned); @@ -808,7 +805,7 @@ fn test_known_directive_check_no_error() { let mut poisoned = false; run_path( &mut poisoned, - Path::new("a.rs"), + Utf8Path::new("a.rs"), include_bytes!("./test-auxillary/known_directive.rs"), ); assert!(!poisoned); @@ -819,7 +816,7 @@ fn test_error_annotation_no_error() { let mut poisoned = false; run_path( &mut poisoned, - Path::new("a.rs"), + Utf8Path::new("a.rs"), include_bytes!("./test-auxillary/error_annotation.rs"), ); assert!(!poisoned); @@ -830,7 +827,7 @@ fn test_non_rs_unknown_directive_not_checked() { let mut poisoned = false; run_path( &mut poisoned, - Path::new("a.Makefile"), + Utf8Path::new("a.Makefile"), include_bytes!("./test-auxillary/not_rs.Makefile"), ); assert!(!poisoned); @@ -839,21 +836,21 @@ fn test_non_rs_unknown_directive_not_checked() { #[test] fn test_trailing_directive() { let mut poisoned = false; - run_path(&mut poisoned, Path::new("a.rs"), b"//@ only-x86 only-arm"); + run_path(&mut poisoned, Utf8Path::new("a.rs"), b"//@ only-x86 only-arm"); assert!(poisoned); } #[test] fn test_trailing_directive_with_comment() { let mut poisoned = false; - run_path(&mut poisoned, Path::new("a.rs"), b"//@ only-x86 only-arm with comment"); + run_path(&mut poisoned, Utf8Path::new("a.rs"), b"//@ only-x86 only-arm with comment"); assert!(poisoned); } #[test] fn test_not_trailing_directive() { let mut poisoned = false; - run_path(&mut poisoned, Path::new("a.rs"), b"//@ revisions: incremental"); + run_path(&mut poisoned, Utf8Path::new("a.rs"), b"//@ revisions: incremental"); assert!(!poisoned); } @@ -905,3 +902,47 @@ fn test_rustc_abi() { assert!(!check_ignore(&config, "//@ ignore-rustc_abi-x86-sse2")); assert!(check_ignore(&config, "//@ only-rustc_abi-x86-sse2")); } + +#[test] +fn test_supported_crate_types() { + // Basic assumptions check on under-test compiler's `--print=supported-crate-types` output based + // on knowledge about the cherry-picked `x86_64-unknown-linux-gnu` and `wasm32-unknown-unknown` + // targets. Also smoke tests the `needs-crate-type` directive itself. + + use std::collections::HashSet; + + let config = cfg().target("x86_64-unknown-linux-gnu").build(); + assert_eq!( + config.supported_crate_types().iter().map(String::as_str).collect::>(), + HashSet::from(["bin", "cdylib", "dylib", "lib", "proc-macro", "rlib", "staticlib"]), + ); + assert!(!check_ignore(&config, "//@ needs-crate-type: rlib")); + assert!(!check_ignore(&config, "//@ needs-crate-type: dylib")); + assert!(!check_ignore( + &config, + "//@ needs-crate-type: bin, cdylib, dylib, lib, proc-macro, rlib, staticlib" + )); + + let config = cfg().target("wasm32-unknown-unknown").build(); + assert_eq!( + config.supported_crate_types().iter().map(String::as_str).collect::>(), + HashSet::from(["bin", "cdylib", "lib", "rlib", "staticlib"]), + ); + + // rlib is supported + assert!(!check_ignore(&config, "//@ needs-crate-type: rlib")); + // dylib is not + assert!(check_ignore(&config, "//@ needs-crate-type: dylib")); + // If multiple crate types are specified, then all specified crate types need to be supported. + assert!(check_ignore(&config, "//@ needs-crate-type: cdylib, dylib")); + assert!(check_ignore( + &config, + "//@ needs-crate-type: bin, cdylib, dylib, lib, proc-macro, rlib, staticlib" + )); +} + +#[test] +fn test_ignore_auxiliary() { + let config = cfg().build(); + assert!(check_ignore(&config, "//@ ignore-auxiliary")); +} diff --git a/src/tools/compiletest/src/json.rs b/src/tools/compiletest/src/json.rs index 9bc26fedf8f4..62fe538ee32e 100644 --- a/src/tools/compiletest/src/json.rs +++ b/src/tools/compiletest/src/json.rs @@ -1,7 +1,6 @@ //! These structs are a subset of the ones found in `rustc_errors::json`. use std::path::{Path, PathBuf}; -use std::str::FromStr; use std::sync::OnceLock; use regex::Regex; @@ -142,43 +141,34 @@ pub fn extract_rendered(output: &str) -> String { } pub fn parse_output(file_name: &str, output: &str, proc_res: &ProcRes) -> Vec { - output.lines().flat_map(|line| parse_line(file_name, line, output, proc_res)).collect() -} - -fn parse_line(file_name: &str, line: &str, output: &str, proc_res: &ProcRes) -> Vec { - // The compiler sometimes intermingles non-JSON stuff into the - // output. This hack just skips over such lines. Yuck. - if line.starts_with('{') { - match serde_json::from_str::(line) { - Ok(diagnostic) => { - let mut expected_errors = vec![]; - push_expected_errors(&mut expected_errors, &diagnostic, &[], file_name); - expected_errors - } - Err(error) => { - // Ignore the future compat report message - this is handled - // by `extract_rendered` - if serde_json::from_str::(line).is_ok() { - vec![] - } else { - proc_res.fatal( + let mut errors = Vec::new(); + for line in output.lines() { + // The compiler sometimes intermingles non-JSON stuff into the + // output. This hack just skips over such lines. Yuck. + if line.starts_with('{') { + match serde_json::from_str::(line) { + Ok(diagnostic) => push_actual_errors(&mut errors, &diagnostic, &[], file_name), + Err(error) => { + // Ignore the future compat report message - this is handled + // by `extract_rendered` + if serde_json::from_str::(line).is_err() { + proc_res.fatal( Some(&format!( - "failed to decode compiler output as json: \ - `{}`\nline: {}\noutput: {}", + "failed to decode compiler output as json: `{}`\nline: {}\noutput: {}", error, line, output )), || (), ); + } } } } - } else { - vec![] } + errors } -fn push_expected_errors( - expected_errors: &mut Vec, +fn push_actual_errors( + errors: &mut Vec, diagnostic: &Diagnostic, default_spans: &[&DiagnosticSpan], file_name: &str, @@ -236,44 +226,47 @@ fn push_expected_errors( } }; - // Convert multi-line messages into multiple expected - // errors. We expect to replace these with something - // more structured shortly anyhow. + // Convert multi-line messages into multiple errors. + // We expect to replace these with something more structured anyhow. let mut message_lines = diagnostic.message.lines(); - if let Some(first_line) = message_lines.next() { - let ignore = |s| { - static RE: OnceLock = OnceLock::new(); - RE.get_or_init(|| { - Regex::new(r"aborting due to \d+ previous errors?|\d+ warnings? emitted").unwrap() - }) - .is_match(s) - }; - - if primary_spans.is_empty() && !ignore(first_line) { - let msg = with_code(None, first_line); - let kind = ErrorKind::from_str(&diagnostic.level).ok(); - expected_errors.push(Error { line_num: None, kind, msg }); - } else { - for span in primary_spans { - let msg = with_code(Some(span), first_line); - let kind = ErrorKind::from_str(&diagnostic.level).ok(); - expected_errors.push(Error { line_num: Some(span.line_start), kind, msg }); - } + let kind = Some(ErrorKind::from_compiler_str(&diagnostic.level)); + let first_line = message_lines.next().unwrap_or(&diagnostic.message); + if primary_spans.is_empty() { + static RE: OnceLock = OnceLock::new(); + let re_init = + || Regex::new(r"aborting due to \d+ previous errors?|\d+ warnings? emitted").unwrap(); + errors.push(Error { + line_num: None, + kind, + msg: with_code(None, first_line), + require_annotation: diagnostic.level != "failure-note" + && !RE.get_or_init(re_init).is_match(first_line), + }); + } else { + for span in primary_spans { + errors.push(Error { + line_num: Some(span.line_start), + kind, + msg: with_code(Some(span), first_line), + require_annotation: true, + }); } } for next_line in message_lines { if primary_spans.is_empty() { - expected_errors.push(Error { + errors.push(Error { line_num: None, - kind: None, + kind, msg: with_code(None, next_line), + require_annotation: false, }); } else { for span in primary_spans { - expected_errors.push(Error { + errors.push(Error { line_num: Some(span.line_start), - kind: None, + kind, msg: with_code(Some(span), next_line), + require_annotation: false, }); } } @@ -283,10 +276,11 @@ fn push_expected_errors( for span in primary_spans { if let Some(ref suggested_replacement) = span.suggested_replacement { for (index, line) in suggested_replacement.lines().enumerate() { - expected_errors.push(Error { + errors.push(Error { line_num: Some(span.line_start + index), kind: Some(ErrorKind::Suggestion), msg: line.to_string(), + require_annotation: true, }); } } @@ -295,39 +289,41 @@ fn push_expected_errors( // Add notes for the backtrace for span in primary_spans { if let Some(frame) = &span.expansion { - push_backtrace(expected_errors, frame, file_name); + push_backtrace(errors, frame, file_name); } } // Add notes for any labels that appear in the message. for span in spans_in_this_file.iter().filter(|span| span.label.is_some()) { - expected_errors.push(Error { + errors.push(Error { line_num: Some(span.line_start), kind: Some(ErrorKind::Note), msg: span.label.clone().unwrap(), + require_annotation: true, }); } // Flatten out the children. for child in &diagnostic.children { - push_expected_errors(expected_errors, child, primary_spans, file_name); + push_actual_errors(errors, child, primary_spans, file_name); } } fn push_backtrace( - expected_errors: &mut Vec, + errors: &mut Vec, expansion: &DiagnosticSpanMacroExpansion, file_name: &str, ) { if Path::new(&expansion.span.file_name) == Path::new(&file_name) { - expected_errors.push(Error { + errors.push(Error { line_num: Some(expansion.span.line_start), kind: Some(ErrorKind::Note), msg: format!("in this expansion of {}", expansion.macro_decl_name), + require_annotation: true, }); } if let Some(previous_expansion) = &expansion.span.expansion { - push_backtrace(expected_errors, previous_expansion, file_name); + push_backtrace(errors, previous_expansion, file_name); } } diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index 8145ae1c1bce..4bbd4ab4790d 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -1,7 +1,8 @@ #![crate_name = "compiletest"] -// The `test` crate is the only unstable feature -// allowed here, just to share similar code. +// Needed by the libtest-based test executor. #![feature(test)] +// Needed by the "new" test executor that does not depend on libtest. +#![feature(internal_output_capture)] extern crate test; @@ -22,16 +23,15 @@ pub mod util; use core::panic; use std::collections::HashSet; -use std::ffi::OsString; use std::fmt::Write; use std::io::{self, ErrorKind}; -use std::path::{Path, PathBuf}; use std::process::{Command, Stdio}; use std::sync::{Arc, OnceLock}; use std::time::SystemTime; use std::{env, fs, vec}; use build_helper::git::{get_git_modified_files, get_git_untracked_files}; +use camino::{Utf8Path, Utf8PathBuf}; use getopts::Options; use tracing::*; use walkdir::WalkDir; @@ -139,7 +139,6 @@ pub fn parse_config(args: Vec) -> Config { .optflag("", "quiet", "print one character per test instead of one line") .optopt("", "color", "coloring: auto, always, never", "WHEN") .optflag("", "json", "emit json output instead of plaintext output") - .optopt("", "logfile", "file to log test execution to", "FILE") .optopt("", "target", "the target to build for", "TARGET") .optopt("", "host", "the host to build for", "HOST") .optopt("", "cdb", "path to CDB to use for CDB debuginfo tests", "PATH") @@ -204,6 +203,7 @@ pub fn parse_config(args: Vec) -> Config { "COMMAND", ) .reqopt("", "minicore-path", "path to minicore aux library", "PATH") + .optflag("n", "new-executor", "enables the new test executor instead of using libtest") .optopt( "", "debugger", @@ -231,15 +231,19 @@ pub fn parse_config(args: Vec) -> Config { panic!() } - fn opt_path(m: &getopts::Matches, nm: &str) -> PathBuf { - match m.opt_str(nm) { - Some(s) => PathBuf::from(&s), - None => panic!("no option (=path) found for {}", nm), + fn make_absolute(path: Utf8PathBuf) -> Utf8PathBuf { + if path.is_relative() { + Utf8PathBuf::try_from(env::current_dir().unwrap()).unwrap().join(path) + } else { + path } } - fn make_absolute(path: PathBuf) -> PathBuf { - if path.is_relative() { env::current_dir().unwrap().join(path) } else { path } + fn opt_path(m: &getopts::Matches, nm: &str) -> Utf8PathBuf { + match m.opt_str(nm) { + Some(s) => Utf8PathBuf::from(&s), + None => panic!("no option (=path) found for {}", nm), + } } let target = opt_str2(matches.opt_str("target")); @@ -280,12 +284,12 @@ pub fn parse_config(args: Vec) -> Config { .free .iter() .map(|f| { - let path = Path::new(f); + let path = Utf8Path::new(f); let mut iter = path.iter().skip(1); // We skip the test folder and check if the user passed `rmake.rs`. if iter.next().is_some_and(|s| s == "rmake.rs") && iter.next().is_none() { - path.parent().unwrap().to_str().unwrap().to_string() + path.parent().unwrap().to_string() } else { f.to_string() } @@ -317,8 +321,8 @@ pub fn parse_config(args: Vec) -> Config { assert!( src_test_suite_root.starts_with(&src_root), "`src-root` must be a parent of `src-test-suite-root`: `src-root`=`{}`, `src-test-suite-root` = `{}`", - src_root.display(), - src_test_suite_root.display() + src_root, + src_test_suite_root ); let build_root = opt_path(matches, "build-root"); @@ -333,16 +337,16 @@ pub fn parse_config(args: Vec) -> Config { compile_lib_path: make_absolute(opt_path(matches, "compile-lib-path")), run_lib_path: make_absolute(opt_path(matches, "run-lib-path")), rustc_path: opt_path(matches, "rustc-path"), - cargo_path: matches.opt_str("cargo-path").map(PathBuf::from), - stage0_rustc_path: matches.opt_str("stage0-rustc-path").map(PathBuf::from), - rustdoc_path: matches.opt_str("rustdoc-path").map(PathBuf::from), - coverage_dump_path: matches.opt_str("coverage-dump-path").map(PathBuf::from), + cargo_path: matches.opt_str("cargo-path").map(Utf8PathBuf::from), + stage0_rustc_path: matches.opt_str("stage0-rustc-path").map(Utf8PathBuf::from), + rustdoc_path: matches.opt_str("rustdoc-path").map(Utf8PathBuf::from), + coverage_dump_path: matches.opt_str("coverage-dump-path").map(Utf8PathBuf::from), python: matches.opt_str("python").unwrap(), jsondocck_path: matches.opt_str("jsondocck-path"), jsondoclint_path: matches.opt_str("jsondoclint-path"), run_clang_based_tests_with: matches.opt_str("run-clang-based-tests-with"), - llvm_filecheck: matches.opt_str("llvm-filecheck").map(PathBuf::from), - llvm_bin_dir: matches.opt_str("llvm-bin-dir").map(PathBuf::from), + llvm_filecheck: matches.opt_str("llvm-filecheck").map(Utf8PathBuf::from), + llvm_bin_dir: matches.opt_str("llvm-bin-dir").map(Utf8PathBuf::from), src_root, src_test_suite_root, @@ -378,7 +382,6 @@ pub fn parse_config(args: Vec) -> Config { "never" => Some(false), _ => panic!("unknown `--run` option `{}` given", mode), }), - logfile: matches.opt_str("logfile").map(|s| PathBuf::from(&s)), runner: matches.opt_str("runner"), host_rustcflags: matches.opt_strs("host-rustcflags"), target_rustcflags: matches.opt_strs("target-rustcflags"), @@ -409,7 +412,7 @@ pub fn parse_config(args: Vec) -> Config { }, only_modified: matches.opt_present("only-modified"), color, - remote_test_client: matches.opt_str("remote-test-client").map(PathBuf::from), + remote_test_client: matches.opt_str("remote-test-client").map(Utf8PathBuf::from), compare_mode, rustfix_coverage: matches.opt_present("rustfix-coverage"), has_html_tidy, @@ -433,6 +436,7 @@ pub fn parse_config(args: Vec) -> Config { target_cfgs: OnceLock::new(), builtin_cfg_names: OnceLock::new(), + supported_crate_types: OnceLock::new(), nocapture: matches.opt_present("no-capture"), @@ -445,25 +449,27 @@ pub fn parse_config(args: Vec) -> Config { diff_command: matches.opt_str("compiletest-diff-tool"), minicore_path: opt_path(matches, "minicore-path"), + + new_executor: matches.opt_present("new-executor"), } } pub fn log_config(config: &Config) { let c = config; logv(c, "configuration:".to_string()); - logv(c, format!("compile_lib_path: {:?}", config.compile_lib_path)); - logv(c, format!("run_lib_path: {:?}", config.run_lib_path)); - logv(c, format!("rustc_path: {:?}", config.rustc_path.display())); + logv(c, format!("compile_lib_path: {}", config.compile_lib_path)); + logv(c, format!("run_lib_path: {}", config.run_lib_path)); + logv(c, format!("rustc_path: {}", config.rustc_path)); logv(c, format!("cargo_path: {:?}", config.cargo_path)); logv(c, format!("rustdoc_path: {:?}", config.rustdoc_path)); - logv(c, format!("src_root: {}", config.src_root.display())); - logv(c, format!("src_test_suite_root: {}", config.src_test_suite_root.display())); + logv(c, format!("src_root: {}", config.src_root)); + logv(c, format!("src_test_suite_root: {}", config.src_test_suite_root)); - logv(c, format!("build_root: {}", config.build_root.display())); - logv(c, format!("build_test_suite_root: {}", config.build_test_suite_root.display())); + logv(c, format!("build_root: {}", config.build_root)); + logv(c, format!("build_test_suite_root: {}", config.build_test_suite_root)); - logv(c, format!("sysroot_base: {}", config.sysroot_base.display())); + logv(c, format!("sysroot_base: {}", config.sysroot_base)); logv(c, format!("stage: {}", config.stage)); logv(c, format!("stage_id: {}", config.stage_id)); @@ -481,16 +487,16 @@ pub fn log_config(config: &Config) { logv(c, format!("target-rustcflags: {:?}", config.target_rustcflags)); logv(c, format!("target: {}", config.target)); logv(c, format!("host: {}", config.host)); - logv(c, format!("android-cross-path: {:?}", config.android_cross_path.display())); - logv(c, format!("adb_path: {:?}", config.adb_path)); - logv(c, format!("adb_test_dir: {:?}", config.adb_test_dir)); + logv(c, format!("android-cross-path: {}", config.android_cross_path)); + logv(c, format!("adb_path: {}", config.adb_path)); + logv(c, format!("adb_test_dir: {}", config.adb_test_dir)); logv(c, format!("adb_device_status: {}", config.adb_device_status)); logv(c, format!("ar: {}", config.ar)); logv(c, format!("target-linker: {:?}", config.target_linker)); logv(c, format!("host-linker: {:?}", config.host_linker)); logv(c, format!("verbose: {}", config.verbose)); logv(c, format!("format: {:?}", config.format)); - logv(c, format!("minicore_path: {:?}", config.minicore_path.display())); + logv(c, format!("minicore_path: {}", config.minicore_path)); logv(c, "\n".to_string()); } @@ -518,7 +524,7 @@ pub fn run_tests(config: Arc) { coverage_file_path.push("rustfix_missing_coverage.txt"); if coverage_file_path.exists() { if let Err(e) = fs::remove_file(&coverage_file_path) { - panic!("Could not delete {} due to {}", coverage_file_path.display(), e) + panic!("Could not delete {} due to {}", coverage_file_path, e) } } } @@ -531,10 +537,14 @@ pub fn run_tests(config: Arc) { } // Prevent issue #21352 UAC blocking .exe containing 'patch' etc. on Windows // If #11207 is resolved (adding manifest to .exe) this becomes unnecessary - env::set_var("__COMPAT_LAYER", "RunAsInvoker"); + // + // SAFETY: at this point we're still single-threaded. + unsafe { env::set_var("__COMPAT_LAYER", "RunAsInvoker") }; - // Let tests know which target they're running as - env::set_var("TARGET", &config.target); + // Let tests know which target they're running as. + // + // SAFETY: at this point we're still single-threaded. + unsafe { env::set_var("TARGET", &config.target) }; let mut configs = Vec::new(); if let Mode::DebugInfo = config.mode { @@ -564,10 +574,14 @@ pub fn run_tests(config: Arc) { tests.sort_by(|a, b| Ord::cmp(&a.desc.name, &b.desc.name)); - // Delegate to libtest to filter and run the big list of structures created - // during test discovery. When libtest decides to run a test, it will - // return control to compiletest by invoking a closure. - let res = crate::executor::execute_tests(&config, tests); + // Delegate to the executor to filter and run the big list of test structures + // created during test discovery. When the executor decides to run a test, + // it will return control to the rest of compiletest by calling `runtest::run`. + let res = if config.new_executor { + Ok(executor::run_tests(&config, tests)) + } else { + crate::executor::libtest::execute_tests(&config, tests) + }; // Check the outcome reported by libtest. match res { @@ -616,13 +630,13 @@ struct TestCollectorCx { config: Arc, cache: HeadersCache, common_inputs_stamp: Stamp, - modified_tests: Vec, + modified_tests: Vec, } /// Mutable state used during test collection. struct TestCollector { tests: Vec, - found_path_stems: HashSet, + found_path_stems: HashSet, poisoned: bool, } @@ -632,14 +646,13 @@ struct TestCollector { /// regardless of whether any filters/tests were specified on the command-line, /// because filtering is handled later by libtest. pub(crate) fn collect_and_make_tests(config: Arc) -> Vec { - debug!("making tests from {}", config.src_test_suite_root.display()); + debug!("making tests from {}", config.src_test_suite_root); let common_inputs_stamp = common_inputs_stamp(&config); let modified_tests = modified_tests(&config, &config.src_test_suite_root).unwrap_or_else(|err| { panic!( "modified_tests got error from dir: {}, error: {}", - config.src_test_suite_root.display(), - err + config.src_test_suite_root, err ) }); let cache = HeadersCache::load(&config); @@ -648,12 +661,9 @@ pub(crate) fn collect_and_make_tests(config: Arc) -> Vec let mut collector = TestCollector { tests: vec![], found_path_stems: HashSet::new(), poisoned: false }; - collect_tests_from_dir(&cx, &mut collector, &cx.config.src_test_suite_root, Path::new("")) + collect_tests_from_dir(&cx, &mut collector, &cx.config.src_test_suite_root, Utf8Path::new("")) .unwrap_or_else(|reason| { - panic!( - "Could not read tests from {}: {reason}", - cx.config.src_test_suite_root.display() - ) + panic!("Could not read tests from {}: {reason}", cx.config.src_test_suite_root) }); let TestCollector { tests, found_path_stems, poisoned } = collector; @@ -722,24 +732,29 @@ fn common_inputs_stamp(config: &Config) -> Stamp { /// the `--only-modified` flag is in use. /// /// (Might be inaccurate in some cases.) -fn modified_tests(config: &Config, dir: &Path) -> Result, String> { +fn modified_tests(config: &Config, dir: &Utf8Path) -> Result, String> { // If `--only-modified` wasn't passed, the list of modified tests won't be // used for anything, so avoid some work and just return an empty list. if !config.only_modified { return Ok(vec![]); } - let files = - get_git_modified_files(&config.git_config(), Some(dir), &vec!["rs", "stderr", "fixed"])?; + let files = get_git_modified_files( + &config.git_config(), + Some(dir.as_std_path()), + &vec!["rs", "stderr", "fixed"], + )?; // Add new test cases to the list, it will be convenient in daily development. let untracked_files = get_git_untracked_files(&config.git_config(), None)?.unwrap_or(vec![]); let all_paths = [&files[..], &untracked_files[..]].concat(); let full_paths = { - let mut full_paths: Vec = all_paths + let mut full_paths: Vec = all_paths .into_iter() - .map(|f| PathBuf::from(f).with_extension("").with_extension("rs")) - .filter_map(|f| if Path::new(&f).exists() { f.canonicalize().ok() } else { None }) + .map(|f| Utf8PathBuf::from(f).with_extension("").with_extension("rs")) + .filter_map( + |f| if Utf8Path::new(&f).exists() { f.canonicalize_utf8().ok() } else { None }, + ) .collect(); full_paths.dedup(); full_paths.sort_unstable(); @@ -753,8 +768,8 @@ fn modified_tests(config: &Config, dir: &Path) -> Result, String> { fn collect_tests_from_dir( cx: &TestCollectorCx, collector: &mut TestCollector, - dir: &Path, - relative_dir_path: &Path, + dir: &Utf8Path, + relative_dir_path: &Utf8Path, ) -> io::Result<()> { // Ignore directories that contain a file named `compiletest-ignore-dir`. if dir.join("compiletest-ignore-dir").exists() { @@ -787,16 +802,16 @@ fn collect_tests_from_dir( // subdirectories we find, except for `auxiliary` directories. // FIXME: this walks full tests tree, even if we have something to ignore // use walkdir/ignore like in tidy? - for file in fs::read_dir(dir)? { + for file in fs::read_dir(dir.as_std_path())? { let file = file?; - let file_path = file.path(); - let file_name = file.file_name(); + let file_path = Utf8PathBuf::try_from(file.path()).unwrap(); + let file_name = file_path.file_name().unwrap(); - if is_test(&file_name) + if is_test(file_name) && (!cx.config.only_modified || cx.modified_tests.contains(&file_path)) { // We found a test file, so create the corresponding libtest structures. - debug!("found test file: {:?}", file_path.display()); + debug!(%file_path, "found test file"); // Record the stem of the test file, to check for overlaps later. let rel_test_path = relative_dir_path.join(file_path.file_stem().unwrap()); @@ -807,22 +822,20 @@ fn collect_tests_from_dir( make_test(cx, collector, &paths); } else if file_path.is_dir() { // Recurse to find more tests in a subdirectory. - let relative_file_path = relative_dir_path.join(file.file_name()); - if &file_name != "auxiliary" { - debug!("found directory: {:?}", file_path.display()); + let relative_file_path = relative_dir_path.join(file_name); + if file_name != "auxiliary" { + debug!(%file_path, "found directory"); collect_tests_from_dir(cx, collector, &file_path, &relative_file_path)?; } } else { - debug!("found other file/directory: {:?}", file_path.display()); + debug!(%file_path, "found other file/directory"); } } Ok(()) } /// Returns true if `file_name` looks like a proper test file name. -pub fn is_test(file_name: &OsString) -> bool { - let file_name = file_name.to_str().unwrap(); - +pub fn is_test(file_name: &str) -> bool { if !file_name.ends_with(".rs") { return false; } @@ -841,7 +854,7 @@ fn make_test(cx: &TestCollectorCx, collector: &mut TestCollector, testpaths: &Te let test_path = if cx.config.mode == Mode::RunMake { testpaths.file.join("rmake.rs") } else { - PathBuf::from(&testpaths.file) + testpaths.file.clone() }; // Scan the test file to discover its revisions, if any. @@ -896,7 +909,7 @@ fn make_test(cx: &TestCollectorCx, collector: &mut TestCollector, testpaths: &Te /// The path of the `stamp` file that gets created or updated whenever a /// particular test completes successfully. -fn stamp_file_path(config: &Config, testpaths: &TestPaths, revision: Option<&str>) -> PathBuf { +fn stamp_file_path(config: &Config, testpaths: &TestPaths, revision: Option<&str>) -> Utf8PathBuf { output_base_dir(config, testpaths, revision).join("stamp") } @@ -909,7 +922,7 @@ fn files_related_to_test( testpaths: &TestPaths, props: &EarlyProps, revision: Option<&str>, -) -> Vec { +) -> Vec { let mut related = vec![]; if testpaths.file.is_dir() { @@ -917,7 +930,7 @@ fn files_related_to_test( for entry in WalkDir::new(&testpaths.file) { let path = entry.unwrap().into_path(); if path.is_file() { - related.push(path); + related.push(Utf8PathBuf::try_from(path).unwrap()); } } } else { @@ -988,7 +1001,7 @@ struct Stamp { impl Stamp { /// Creates a timestamp holding the last-modified time of the specified file. - fn from_path(path: &Path) -> Self { + fn from_path(path: &Utf8Path) -> Self { let mut stamp = Stamp { time: SystemTime::UNIX_EPOCH }; stamp.add_path(path); stamp @@ -996,8 +1009,8 @@ impl Stamp { /// Updates this timestamp to the last-modified time of the specified file, /// if it is later than the currently-stored timestamp. - fn add_path(&mut self, path: &Path) { - let modified = fs::metadata(path) + fn add_path(&mut self, path: &Utf8Path) { + let modified = fs::metadata(path.as_std_path()) .and_then(|metadata| metadata.modified()) .unwrap_or(SystemTime::UNIX_EPOCH); self.time = self.time.max(modified); @@ -1006,7 +1019,8 @@ impl Stamp { /// Updates this timestamp to the most recent last-modified time of all files /// recursively contained in the given directory, if it is later than the /// currently-stored timestamp. - fn add_dir(&mut self, path: &Path) { + fn add_dir(&mut self, path: &Utf8Path) { + let path = path.as_std_path(); for entry in WalkDir::new(path) { let entry = entry.unwrap(); if entry.file_type().is_file() { @@ -1039,7 +1053,7 @@ fn make_test_name(config: &Config, testpaths: &TestPaths, revision: Option<&str> config.mode, debugger, mode_suffix, - path.display(), + path, revision.map_or("".to_string(), |rev| format!("#{}", rev)) ) } @@ -1061,7 +1075,7 @@ fn make_test_name(config: &Config, testpaths: &TestPaths, revision: Option<&str> /// To avoid problems, we forbid test names from overlapping in this way. /// /// See for more context. -fn check_for_overlapping_test_paths(found_path_stems: &HashSet) { +fn check_for_overlapping_test_paths(found_path_stems: &HashSet) { let mut collisions = Vec::new(); for path in found_path_stems { for ancestor in path.ancestors().skip(1) { @@ -1074,7 +1088,7 @@ fn check_for_overlapping_test_paths(found_path_stems: &HashSet) { collisions.sort(); let collisions: String = collisions .into_iter() - .map(|(path, check_parent)| format!("test {path:?} clashes with {check_parent:?}\n")) + .map(|(path, check_parent)| format!("test {path} clashes with {check_parent}\n")) .collect(); panic!( "{collisions}\n\ diff --git a/src/tools/compiletest/src/raise_fd_limit.rs b/src/tools/compiletest/src/raise_fd_limit.rs index 7b12ba946b9e..653b125a6b41 100644 --- a/src/tools/compiletest/src/raise_fd_limit.rs +++ b/src/tools/compiletest/src/raise_fd_limit.rs @@ -6,6 +6,7 @@ /// This fixes issue #7772. #[cfg(target_vendor = "apple")] #[allow(non_camel_case_types)] +// FIXME(#139616): document caller contract. pub unsafe fn raise_fd_limit() { use std::ptr::null_mut; use std::{cmp, io}; @@ -21,8 +22,10 @@ pub unsafe fn raise_fd_limit() { let mut mib: [libc::c_int; 2] = [CTL_KERN, KERN_MAXFILESPERPROC]; let mut maxfiles: libc::c_int = 0; let mut size: libc::size_t = size_of_val(&maxfiles) as libc::size_t; - if libc::sysctl(&mut mib[0], 2, &mut maxfiles as *mut _ as *mut _, &mut size, null_mut(), 0) - != 0 + // FIXME(#139616): justify why this is sound. + if unsafe { + libc::sysctl(&mut mib[0], 2, &mut maxfiles as *mut _ as *mut _, &mut size, null_mut(), 0) + } != 0 { let err = io::Error::last_os_error(); panic!("raise_fd_limit: error calling sysctl: {}", err); @@ -30,7 +33,8 @@ pub unsafe fn raise_fd_limit() { // Fetch the current resource limits let mut rlim = libc::rlimit { rlim_cur: 0, rlim_max: 0 }; - if libc::getrlimit(libc::RLIMIT_NOFILE, &mut rlim) != 0 { + // FIXME(#139616): justify why this is sound. + if unsafe { libc::getrlimit(libc::RLIMIT_NOFILE, &mut rlim) } != 0 { let err = io::Error::last_os_error(); panic!("raise_fd_limit: error calling getrlimit: {}", err); } @@ -41,7 +45,8 @@ pub unsafe fn raise_fd_limit() { rlim.rlim_cur = cmp::min(maxfiles as libc::rlim_t, rlim.rlim_max); // Set our newly-increased resource limit. - if libc::setrlimit(libc::RLIMIT_NOFILE, &rlim) != 0 { + // FIXME(#139616): justify why this is sound. + if unsafe { libc::setrlimit(libc::RLIMIT_NOFILE, &rlim) } != 0 { let err = io::Error::last_os_error(); panic!("raise_fd_limit: error calling setrlimit: {}", err); } diff --git a/src/tools/compiletest/src/read2.rs b/src/tools/compiletest/src/read2.rs index 28ca5589992a..2213dd07160a 100644 --- a/src/tools/compiletest/src/read2.rs +++ b/src/tools/compiletest/src/read2.rs @@ -165,6 +165,7 @@ mod imp { mut err_pipe: ChildStderr, data: &mut dyn FnMut(bool, &mut Vec, bool), ) -> io::Result<()> { + // FIXME(#139616): justify why this is sound. unsafe { libc::fcntl(out_pipe.as_raw_fd(), libc::F_SETFL, libc::O_NONBLOCK); libc::fcntl(err_pipe.as_raw_fd(), libc::F_SETFL, libc::O_NONBLOCK); @@ -175,6 +176,7 @@ mod imp { let mut out = Vec::new(); let mut err = Vec::new(); + // FIXME(#139616): justify why this is sound. let mut fds: [libc::pollfd; 2] = unsafe { mem::zeroed() }; fds[0].fd = out_pipe.as_raw_fd(); fds[0].events = libc::POLLIN; @@ -185,6 +187,7 @@ mod imp { while nfds > 0 { // wait for either pipe to become readable using `select` + // FIXME(#139616): justify why this is sound. let r = unsafe { libc::poll(fds.as_mut_ptr(), nfds, -1) }; if r == -1 { let err = io::Error::last_os_error(); @@ -256,6 +259,7 @@ mod imp { port.add_handle(0, &out_pipe)?; port.add_handle(1, &err_pipe)?; + // FIXME(#139616): justify why this is sound. unsafe { let mut out_pipe = Pipe::new(out_pipe, &mut out); let mut err_pipe = Pipe::new(err_pipe, &mut err); @@ -284,18 +288,23 @@ mod imp { } impl<'a> Pipe<'a> { + // FIXME(#139616): document caller contract. unsafe fn new(p: P, dst: &'a mut Vec) -> Pipe<'a> { Pipe { dst, - pipe: NamedPipe::from_raw_handle(p.into_raw_handle()), + // FIXME(#139616): justify why this is sound. + pipe: unsafe { NamedPipe::from_raw_handle(p.into_raw_handle()) }, overlapped: Overlapped::zero(), done: false, } } + // FIXME(#139616): document caller contract. unsafe fn read(&mut self) -> io::Result<()> { - let dst = slice_to_end(self.dst); - match self.pipe.read_overlapped(dst, self.overlapped.raw()) { + // FIXME(#139616): justify why this is sound. + let dst = unsafe { slice_to_end(self.dst) }; + // FIXME(#139616): justify why this is sound. + match unsafe { self.pipe.read_overlapped(dst, self.overlapped.raw()) } { Ok(_) => Ok(()), Err(e) => { if e.raw_os_error() == Some(ERROR_BROKEN_PIPE.0 as i32) { @@ -308,15 +317,18 @@ mod imp { } } + // FIXME(#139616): document caller contract. unsafe fn complete(&mut self, status: &CompletionStatus) { let prev = self.dst.len(); - self.dst.set_len(prev + status.bytes_transferred() as usize); + // FIXME(#139616): justify why this is sound. + unsafe { self.dst.set_len(prev + status.bytes_transferred() as usize) }; if status.bytes_transferred() == 0 { self.done = true; } } } + // FIXME(#139616): document caller contract. unsafe fn slice_to_end(v: &mut Vec) -> &mut [u8] { if v.capacity() == 0 { v.reserve(16); @@ -324,6 +336,12 @@ mod imp { if v.capacity() == v.len() { v.reserve(1); } - slice::from_raw_parts_mut(v.as_mut_ptr().offset(v.len() as isize), v.capacity() - v.len()) + // FIXME(#139616): justify why this is sound. + unsafe { + slice::from_raw_parts_mut( + v.as_mut_ptr().offset(v.len() as isize), + v.capacity() - v.len(), + ) + } } } diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index c8a60b68da8b..d11f5c1a3a6f 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -1,16 +1,16 @@ use std::borrow::Cow; use std::collections::{HashMap, HashSet}; -use std::ffi::{OsStr, OsString}; +use std::ffi::OsString; use std::fs::{self, File, create_dir_all}; use std::hash::{DefaultHasher, Hash, Hasher}; use std::io::prelude::*; use std::io::{self, BufReader}; -use std::path::{Path, PathBuf}; use std::process::{Child, Command, ExitStatus, Output, Stdio}; use std::sync::Arc; use std::{env, iter, str}; -use anyhow::Context; +use build_helper::fs::remove_and_create_dir_all; +use camino::{Utf8Path, Utf8PathBuf}; use colored::Colorize; use regex::{Captures, Regex}; use tracing::*; @@ -23,10 +23,10 @@ use crate::common::{ output_base_dir, output_base_name, output_testname_unique, }; use crate::compute_diff::{DiffLine, make_diff, write_diff, write_filtered_diff}; -use crate::errors::{self, Error, ErrorKind}; +use crate::errors::{Error, ErrorKind}; use crate::header::TestProps; use crate::read2::{Truncated, read2_abbreviated}; -use crate::util::{PathBufExt, add_dylib_path, logv, static_regex}; +use crate::util::{Utf8PathBufExt, add_dylib_path, logv, static_regex}; use crate::{ColorConfig, json, stamp_file_path}; mod debugger; @@ -132,7 +132,7 @@ pub fn run(config: Arc, testpaths: &TestPaths, revision: Option<&str>) { // We're going to be dumping a lot of info. Start on a new line. print!("\n\n"); } - debug!("running {:?}", testpaths.file.display()); + debug!("running {}", testpaths.file); let mut props = TestProps::from_file(&testpaths.file, revision, &config); // For non-incremental (i.e. regular UI) tests, the incremental directory @@ -143,11 +143,11 @@ pub fn run(config: Arc, testpaths: &TestPaths, revision: Option<&str>) { } let cx = TestCx { config: &config, props: &props, testpaths, revision }; - create_dir_all(&cx.output_base_dir()) - .with_context(|| { - format!("failed to create output base directory {}", cx.output_base_dir().display()) - }) - .unwrap(); + + if let Err(e) = create_dir_all(&cx.output_base_dir()) { + panic!("failed to create output base directory {}: {e}", cx.output_base_dir()); + } + if props.incremental { cx.init_incremental_test(); } @@ -178,6 +178,7 @@ pub fn compute_stamp_hash(config: &Config) -> String { let mut hash = DefaultHasher::new(); config.stage_id.hash(&mut hash); config.run.hash(&mut hash); + config.edition.hash(&mut hash); match config.debugger { Some(Debugger::Cdb) => { @@ -207,11 +208,6 @@ pub fn compute_stamp_hash(config: &Config) -> String { format!("{:x}", hash.finish()) } -fn remove_and_create_dir_all(path: &Path) { - let _ = fs::remove_dir_all(path); - fs::create_dir_all(path).unwrap(); -} - #[derive(Copy, Clone, Debug)] struct TestCx<'test> { config: &'test Config, @@ -423,7 +419,7 @@ impl<'test> TestCx<'test> { let aux_dir = self.aux_output_dir_name(); let input: &str = match read_from { ReadFrom::Stdin(_) => "-", - ReadFrom::Path => self.testpaths.file.to_str().unwrap(), + ReadFrom::Path => self.testpaths.file.as_str(), }; let mut rustc = Command::new(&self.config.rustc_path); @@ -446,8 +442,8 @@ impl<'test> TestCx<'test> { self.compose_and_run( rustc, - self.config.compile_lib_path.to_str().unwrap(), - Some(aux_dir.to_str().unwrap()), + self.config.compile_lib_path.as_path(), + Some(aux_dir.as_path()), src, ) } @@ -522,7 +518,9 @@ impl<'test> TestCx<'test> { let mut rustc = Command::new(&self.config.rustc_path); let out_dir = self.output_base_name().with_extension("pretty-out"); - remove_and_create_dir_all(&out_dir); + remove_and_create_dir_all(&out_dir).unwrap_or_else(|e| { + panic!("failed to remove and recreate output directory `{out_dir}`: {e}") + }); let target = if self.props.force_host { &*self.config.host } else { &*self.config.target }; @@ -590,10 +588,7 @@ impl<'test> TestCx<'test> { // FIXME(#65865) return; } else { - self.fatal(&format!( - "no error pattern specified in {:?}", - self.testpaths.file.display() - )); + self.fatal(&format!("no error pattern specified in {}", self.testpaths.file)); } } @@ -675,7 +670,7 @@ impl<'test> TestCx<'test> { } } - fn check_expected_errors(&self, expected_errors: Vec, proc_res: &ProcRes) { + fn check_expected_errors(&self, expected_errors: Vec, proc_res: &ProcRes) { debug!( "check_expected_errors: expected_errors={:?} proc_res.status={:?}", expected_errors, proc_res.status @@ -697,25 +692,25 @@ impl<'test> TestCx<'test> { } // On Windows, translate all '\' path separators to '/' - let file_name = format!("{}", self.testpaths.file.display()).replace(r"\", "/"); + let file_name = self.testpaths.file.to_string().replace(r"\", "/"); // On Windows, keep all '\' path separators to match the paths reported in the JSON output // from the compiler let diagnostic_file_name = if self.props.remap_src_base { - let mut p = PathBuf::from(FAKE_SRC_BASE); + let mut p = Utf8PathBuf::from(FAKE_SRC_BASE); p.push(&self.testpaths.relative_dir); p.push(self.testpaths.file.file_name().unwrap()); - p.display().to_string() + p.to_string() } else { - self.testpaths.file.display().to_string() + self.testpaths.file.to_string() }; - // If the testcase being checked contains at least one expected "help" - // message, then we'll ensure that all "help" messages are expected. - // Otherwise, all "help" messages reported by the compiler will be ignored. - // This logic also applies to "note" messages. - let expect_help = expected_errors.iter().any(|ee| ee.kind == Some(ErrorKind::Help)); - let expect_note = expected_errors.iter().any(|ee| ee.kind == Some(ErrorKind::Note)); + // Errors and warnings are always expected, other diagnostics are only expected + // if one of them actually occurs in the test. + let expected_kinds: HashSet<_> = [ErrorKind::Error, ErrorKind::Warning] + .into_iter() + .chain(expected_errors.iter().filter_map(|e| e.kind)) + .collect(); // Parse the JSON output from the compiler and extract out the messages. let actual_errors = json::parse_output(&diagnostic_file_name, &proc_res.stderr, proc_res); @@ -741,8 +736,11 @@ impl<'test> TestCx<'test> { } None => { - // If the test is a known bug, don't require that the error is annotated - if self.is_unexpected_compiler_message(&actual_error, expect_help, expect_note) + if actual_error.require_annotation + && actual_error.kind.map_or(false, |kind| { + expected_kinds.contains(&kind) + && !self.props.dont_require_annotations.contains(&kind) + }) { self.error(&format!( "{}:{}: unexpected {}: '{}'", @@ -800,25 +798,6 @@ impl<'test> TestCx<'test> { } } - /// Returns `true` if we should report an error about `actual_error`, - /// which did not match any of the expected error. We always require - /// errors/warnings to be explicitly listed, but only require - /// helps/notes if there are explicit helps/notes given. - fn is_unexpected_compiler_message( - &self, - actual_error: &Error, - expect_help: bool, - expect_note: bool, - ) -> bool { - !actual_error.msg.is_empty() - && match actual_error.kind { - Some(ErrorKind::Help) => expect_help, - Some(ErrorKind::Note) => expect_note, - Some(ErrorKind::Error) | Some(ErrorKind::Warning) => true, - Some(ErrorKind::Suggestion) | None => false, - } - } - fn should_emit_metadata(&self, pm: Option) -> Emit { match (pm, self.props.fail_mode, self.config.mode) { (Some(PassMode::Check), ..) | (_, Some(FailMode::Check), Ui) => Emit::Metadata, @@ -889,7 +868,7 @@ impl<'test> TestCx<'test> { /// `root_out_dir` and `root_testpaths` refer to the parameters of the actual test being run. /// Auxiliaries, no matter how deep, have the same root_out_dir and root_testpaths. - fn document(&self, root_out_dir: &Path, root_testpaths: &TestPaths) -> ProcRes { + fn document(&self, root_out_dir: &Utf8Path, root_testpaths: &TestPaths) -> ProcRes { if self.props.build_aux_docs { for rel_ab in &self.props.aux.builds { let aux_testpaths = self.compute_aux_test_paths(root_testpaths, rel_ab); @@ -918,13 +897,13 @@ impl<'test> TestCx<'test> { // actual --out-dir given to the auxiliary or test, as opposed to the root out dir for the entire // test - let out_dir: Cow<'_, Path> = if self.props.unique_doc_out_dir { + let out_dir: Cow<'_, Utf8Path> = if self.props.unique_doc_out_dir { let file_name = self.testpaths.file.file_stem().expect("file name should not be empty"); - let out_dir = PathBuf::from_iter([ + let out_dir = Utf8PathBuf::from_iter([ root_out_dir, - Path::new("docs"), - Path::new(file_name), - Path::new("doc"), + Utf8Path::new("docs"), + Utf8Path::new(file_name), + Utf8Path::new("doc"), ]); create_dir_all(&out_dir).unwrap(); Cow::Owned(out_dir) @@ -937,7 +916,7 @@ impl<'test> TestCx<'test> { rustdoc.current_dir(current_dir); rustdoc .arg("-L") - .arg(self.config.run_lib_path.to_str().unwrap()) + .arg(self.config.run_lib_path.as_path()) .arg("-L") .arg(aux_dir) .arg("-o") @@ -971,16 +950,16 @@ impl<'test> TestCx<'test> { delete_after_success: bool, ) -> ProcRes { let prepare_env = |cmd: &mut Command| { - for key in &self.props.unset_exec_env { - cmd.env_remove(key); - } - for (key, val) in &self.props.exec_env { cmd.env(key, val); } for (key, val) in env_extra { cmd.env(key, val); } + + for key in &self.props.unset_exec_env { + cmd.env_remove(key); + } }; let proc_res = match &*self.config.target { @@ -1023,8 +1002,8 @@ impl<'test> TestCx<'test> { self.compose_and_run( test_client, - self.config.run_lib_path.to_str().unwrap(), - Some(aux_dir.to_str().unwrap()), + self.config.run_lib_path.as_path(), + Some(aux_dir.as_path()), None, ) } @@ -1038,8 +1017,8 @@ impl<'test> TestCx<'test> { self.compose_and_run( wr_run, - self.config.run_lib_path.to_str().unwrap(), - Some(aux_dir.to_str().unwrap()), + self.config.run_lib_path.as_path(), + Some(aux_dir.as_path()), None, ) } @@ -1053,8 +1032,8 @@ impl<'test> TestCx<'test> { self.compose_and_run( program, - self.config.run_lib_path.to_str().unwrap(), - Some(aux_dir.to_str().unwrap()), + self.config.run_lib_path.as_path(), + Some(aux_dir.as_path()), None, ) } @@ -1075,7 +1054,7 @@ impl<'test> TestCx<'test> { let test_ab = of.file.parent().expect("test file path has no parent").join("auxiliary").join(rel_ab); if !test_ab.exists() { - self.fatal(&format!("aux-build `{}` source not found", test_ab.display())) + self.fatal(&format!("aux-build `{}` source not found", test_ab)) } TestPaths { @@ -1112,23 +1091,29 @@ impl<'test> TestCx<'test> { || !self.props.aux.proc_macros.is_empty() } - fn aux_output_dir(&self) -> PathBuf { + fn aux_output_dir(&self) -> Utf8PathBuf { let aux_dir = self.aux_output_dir_name(); if !self.props.aux.builds.is_empty() { - remove_and_create_dir_all(&aux_dir); + remove_and_create_dir_all(&aux_dir).unwrap_or_else(|e| { + panic!("failed to remove and recreate output directory `{aux_dir}`: {e}") + }); } if !self.props.aux.bins.is_empty() { let aux_bin_dir = self.aux_bin_output_dir_name(); - remove_and_create_dir_all(&aux_dir); - remove_and_create_dir_all(&aux_bin_dir); + remove_and_create_dir_all(&aux_dir).unwrap_or_else(|e| { + panic!("failed to remove and recreate output directory `{aux_dir}`: {e}") + }); + remove_and_create_dir_all(&aux_bin_dir).unwrap_or_else(|e| { + panic!("failed to remove and recreate output directory `{aux_bin_dir}`: {e}") + }); } aux_dir } - fn build_all_auxiliary(&self, of: &TestPaths, aux_dir: &Path, rustc: &mut Command) { + fn build_all_auxiliary(&self, of: &TestPaths, aux_dir: &Utf8Path, rustc: &mut Command) { for rel_ab in &self.props.aux.builds { self.build_auxiliary(of, rel_ab, &aux_dir, None); } @@ -1148,12 +1133,7 @@ impl<'test> TestCx<'test> { |rustc: &mut Command, aux_name: &str, aux_path: &str, aux_type: AuxType| { let lib_name = get_lib_name(&path_to_crate_name(aux_path), aux_type); if let Some(lib_name) = lib_name { - rustc.arg("--extern").arg(format!( - "{}={}/{}", - aux_name, - aux_dir.display(), - lib_name - )); + rustc.arg("--extern").arg(format!("{}={}/{}", aux_name, aux_dir, lib_name)); } }; @@ -1174,7 +1154,7 @@ impl<'test> TestCx<'test> { let aux_type = self.build_auxiliary(of, aux_file, aux_dir, None); if let Some(lib_name) = get_lib_name(aux_file.trim_end_matches(".rs"), aux_type) { let lib_path = aux_dir.join(&lib_name); - rustc.arg(format!("-Zcodegen-backend={}", lib_path.display())); + rustc.arg(format!("-Zcodegen-backend={}", lib_path)); } } } @@ -1190,7 +1170,7 @@ impl<'test> TestCx<'test> { if self.props.add_core_stubs { let minicore_path = self.build_minicore(); rustc.arg("--extern"); - rustc.arg(&format!("minicore={}", minicore_path.to_str().unwrap())); + rustc.arg(&format!("minicore={}", minicore_path)); } let aux_dir = self.aux_output_dir(); @@ -1200,15 +1180,15 @@ impl<'test> TestCx<'test> { self.props.unset_rustc_env.iter().fold(&mut rustc, Command::env_remove); self.compose_and_run( rustc, - self.config.compile_lib_path.to_str().unwrap(), - Some(aux_dir.to_str().unwrap()), + self.config.compile_lib_path.as_path(), + Some(aux_dir.as_path()), input, ) } /// Builds `minicore`. Returns the path to the minicore rlib within the base test output /// directory. - fn build_minicore(&self) -> PathBuf { + fn build_minicore(&self) -> Utf8PathBuf { let output_file_path = self.output_base_dir().join("libminicore.rlib"); let mut rustc = self.make_compile_args( &self.config.minicore_path, @@ -1222,14 +1202,10 @@ impl<'test> TestCx<'test> { rustc.args(&["--crate-type", "rlib"]); rustc.arg("-Cpanic=abort"); - let res = - self.compose_and_run(rustc, self.config.compile_lib_path.to_str().unwrap(), None, None); + let res = self.compose_and_run(rustc, self.config.compile_lib_path.as_path(), None, None); if !res.status.success() { self.fatal_proc_rec( - &format!( - "auxiliary build of {:?} failed to compile: ", - self.config.minicore_path.display() - ), + &format!("auxiliary build of {} failed to compile: ", self.config.minicore_path), &res, ); } @@ -1244,7 +1220,7 @@ impl<'test> TestCx<'test> { &self, of: &TestPaths, source_path: &str, - aux_dir: &Path, + aux_dir: &Utf8Path, aux_type: Option, ) -> AuxType { let aux_testpaths = self.compute_aux_test_paths(of, source_path); @@ -1335,16 +1311,13 @@ impl<'test> TestCx<'test> { let auxres = aux_cx.compose_and_run( aux_rustc, - aux_cx.config.compile_lib_path.to_str().unwrap(), - Some(aux_dir.to_str().unwrap()), + aux_cx.config.compile_lib_path.as_path(), + Some(aux_dir.as_path()), None, ); if !auxres.status.success() { self.fatal_proc_rec( - &format!( - "auxiliary build of {:?} failed to compile: ", - aux_testpaths.file.display() - ), + &format!("auxiliary build of {} failed to compile: ", aux_testpaths.file), &auxres, ); } @@ -1353,8 +1326,8 @@ impl<'test> TestCx<'test> { fn read2_abbreviated(&self, child: Child) -> (Output, Truncated) { let mut filter_paths_from_len = Vec::new(); - let mut add_path = |path: &Path| { - let path = path.display().to_string(); + let mut add_path = |path: &Utf8Path| { + let path = path.to_string(); let windows = path.replace("\\", "\\\\"); if windows != path { filter_paths_from_len.push(windows); @@ -1376,8 +1349,8 @@ impl<'test> TestCx<'test> { fn compose_and_run( &self, mut command: Command, - lib_path: &str, - aux_path: Option<&str>, + lib_path: &Utf8Path, + aux_path: Option<&Utf8Path>, input: Option, ) -> ProcRes { let cmdline = { @@ -1422,9 +1395,9 @@ impl<'test> TestCx<'test> { matches!(self.config.suite.as_str(), "rustdoc-ui" | "rustdoc-js" | "rustdoc-json") } - fn get_mir_dump_dir(&self) -> PathBuf { + fn get_mir_dump_dir(&self) -> Utf8PathBuf { let mut mir_dump_dir = self.config.build_test_suite_root.clone(); - debug!("input_file: {:?}", self.testpaths.file); + debug!("input_file: {}", self.testpaths.file); mir_dump_dir.push(&self.testpaths.relative_dir); mir_dump_dir.push(self.testpaths.file.file_stem().unwrap()); mir_dump_dir @@ -1432,7 +1405,7 @@ impl<'test> TestCx<'test> { fn make_compile_args( &self, - input_file: &Path, + input_file: &Utf8Path, output_file: TargetLocation, emit: Emit, allow_unused: AllowUnused, @@ -1473,7 +1446,7 @@ impl<'test> TestCx<'test> { // Similarly, vendored sources shouldn't be shown when running from a dist tarball. rustc.arg("-Z").arg(format!( "ignore-directory-in-diagnostics-source-blocks={}", - self.config.src_root.join("vendor").to_str().unwrap(), + self.config.src_root.join("vendor"), )); // Optionally prevent default --sysroot if specified in test compile-flags. @@ -1497,7 +1470,7 @@ impl<'test> TestCx<'test> { if !is_rustdoc { if let Some(ref incremental_dir) = self.props.incremental_dir { - rustc.args(&["-C", &format!("incremental={}", incremental_dir.display())]); + rustc.args(&["-C", &format!("incremental={}", incremental_dir)]); rustc.args(&["-Z", "incremental-verify-ich"]); } @@ -1539,9 +1512,11 @@ impl<'test> TestCx<'test> { let set_mir_dump_dir = |rustc: &mut Command| { let mir_dump_dir = self.get_mir_dump_dir(); - remove_and_create_dir_all(&mir_dump_dir); + remove_and_create_dir_all(&mir_dump_dir).unwrap_or_else(|e| { + panic!("failed to remove and recreate output directory `{mir_dump_dir}`: {e}") + }); let mut dir_opt = "-Zdump-mir-dir=".to_string(); - dir_opt.push_str(mir_dump_dir.to_str().unwrap()); + dir_opt.push_str(mir_dump_dir.as_str()); debug!("dir_opt: {:?}", dir_opt); rustc.arg(dir_opt); }; @@ -1634,8 +1609,7 @@ impl<'test> TestCx<'test> { if self.props.remap_src_base { rustc.arg(format!( "--remap-path-prefix={}={}", - self.config.src_test_suite_root.to_str().unwrap(), - FAKE_SRC_BASE, + self.config.src_test_suite_root, FAKE_SRC_BASE, )); } @@ -1758,7 +1732,7 @@ impl<'test> TestCx<'test> { rustc } - fn make_exe_name(&self) -> PathBuf { + fn make_exe_name(&self) -> Utf8PathBuf { // Using a single letter here to keep the path length down for // Windows. Some test names get very long. rustc creates `rcgu` // files with the module name appended to it which can more than @@ -1809,7 +1783,7 @@ impl<'test> TestCx<'test> { } } - fn make_cmdline(&self, command: &Command, libpath: &str) -> String { + fn make_cmdline(&self, command: &Command, libpath: &Utf8Path) -> String { use crate::util; // Linux and mac don't require adjusting the library search path @@ -1822,7 +1796,7 @@ impl<'test> TestCx<'test> { format!("{}=\"{}\"", util::lib_path_env_var(), util::make_new_path(path)) } - format!("{} {:?}", lib_path_cmd_prefix(libpath), command) + format!("{} {:?}", lib_path_cmd_prefix(libpath.as_str()), command) } } @@ -1836,20 +1810,19 @@ impl<'test> TestCx<'test> { return; } - let path = Path::new(proc_name); + let path = Utf8Path::new(proc_name); let proc_name = if path.file_stem().is_some_and(|p| p == "rmake") { - OsString::from_iter( + String::from_iter( path.parent() .unwrap() .file_name() .into_iter() - .chain(Some(OsStr::new("/"))) + .chain(Some("/")) .chain(path.file_name()), ) } else { path.file_name().unwrap().into() }; - let proc_name = proc_name.to_string_lossy(); println!("------{proc_name} stdout------------------------------"); println!("{}", out); println!("------{proc_name} stderr------------------------------"); @@ -1859,18 +1832,18 @@ impl<'test> TestCx<'test> { fn dump_output_file(&self, out: &str, extension: &str) { let outfile = self.make_out_name(extension); - fs::write(&outfile, out).unwrap(); + fs::write(outfile.as_std_path(), out).unwrap(); } /// Creates a filename for output with the given extension. /// E.g., `/.../testname.revision.mode/testname.extension`. - fn make_out_name(&self, extension: &str) -> PathBuf { + fn make_out_name(&self, extension: &str) -> Utf8PathBuf { self.output_base_name().with_extension(extension) } /// Gets the directory where auxiliary files are written. /// E.g., `/.../testname.revision.mode/auxiliary/`. - fn aux_output_dir_name(&self) -> PathBuf { + fn aux_output_dir_name(&self) -> Utf8PathBuf { self.output_base_dir() .join("auxiliary") .with_extra_extension(self.config.mode.aux_dir_disambiguator()) @@ -1878,12 +1851,12 @@ impl<'test> TestCx<'test> { /// Gets the directory where auxiliary binaries are written. /// E.g., `/.../testname.revision.mode/auxiliary/bin`. - fn aux_bin_output_dir_name(&self) -> PathBuf { + fn aux_bin_output_dir_name(&self) -> Utf8PathBuf { self.aux_output_dir_name().join("bin") } /// Generates a unique name for the test, such as `testname.revision.mode`. - fn output_testname_unique(&self) -> PathBuf { + fn output_testname_unique(&self) -> Utf8PathBuf { output_testname_unique(self.config, self.testpaths, self.safe_revision()) } @@ -1896,14 +1869,14 @@ impl<'test> TestCx<'test> { /// Gets the absolute path to the directory where all output for the given /// test/revision should reside. /// E.g., `/path/to/build/host-tuple/test/ui/relative/testname.revision.mode/`. - fn output_base_dir(&self) -> PathBuf { + fn output_base_dir(&self) -> Utf8PathBuf { output_base_dir(self.config, self.testpaths, self.safe_revision()) } /// Gets the absolute path to the base filename used as output for the given /// test/revision. /// E.g., `/.../relative/testname.revision.mode/testname`. - fn output_base_name(&self) -> PathBuf { + fn output_base_name(&self) -> Utf8PathBuf { output_base_name(self.config, self.testpaths, self.safe_revision()) } @@ -1938,7 +1911,7 @@ impl<'test> TestCx<'test> { // codegen tests (using FileCheck) - fn compile_test_and_save_ir(&self) -> (ProcRes, PathBuf) { + fn compile_test_and_save_ir(&self) -> (ProcRes, Utf8PathBuf) { let output_path = self.output_base_name().with_extension("ll"); let input_file = &self.testpaths.file; let rustc = self.make_compile_args( @@ -1954,7 +1927,7 @@ impl<'test> TestCx<'test> { (proc_res, output_path) } - fn verify_with_filecheck(&self, output: &Path) -> ProcRes { + fn verify_with_filecheck(&self, output: &Utf8Path) -> ProcRes { let mut filecheck = Command::new(self.config.llvm_filecheck.as_ref().unwrap()); filecheck.arg("--input-file").arg(output).arg(&self.testpaths.file); @@ -1983,7 +1956,8 @@ impl<'test> TestCx<'test> { // Add custom flags supplied by the `filecheck-flags:` test header. filecheck.args(&self.props.filecheck_flags); - self.compose_and_run(filecheck, "", None, None) + // FIXME(jieyouxu): don't pass an empty Path + self.compose_and_run(filecheck, Utf8Path::new(""), None, None) } fn charset() -> &'static str { @@ -1991,7 +1965,7 @@ impl<'test> TestCx<'test> { if cfg!(target_os = "freebsd") { "ISO-8859-1" } else { "UTF-8" } } - fn compare_to_default_rustdoc(&mut self, out_dir: &Path) { + fn compare_to_default_rustdoc(&mut self, out_dir: &Utf8Path) { if !self.config.has_html_tidy { return; } @@ -2000,7 +1974,9 @@ impl<'test> TestCx<'test> { let suffix = self.safe_revision().map_or("nightly".into(), |path| path.to_owned() + "-nightly"); let compare_dir = output_base_dir(self.config, self.testpaths, Some(&suffix)); - remove_and_create_dir_all(&compare_dir); + remove_and_create_dir_all(&compare_dir).unwrap_or_else(|e| { + panic!("failed to remove and recreate output directory `{compare_dir}`: {e}") + }); // We need to create a new struct for the lifetimes on `config` to work. let new_rustdoc = TestCx { @@ -2143,12 +2119,8 @@ impl<'test> TestCx<'test> { }; } - fn get_lines>( - &self, - path: &P, - mut other_files: Option<&mut Vec>, - ) -> Vec { - let content = fs::read_to_string(&path).unwrap(); + fn get_lines(&self, path: &Utf8Path, mut other_files: Option<&mut Vec>) -> Vec { + let content = fs::read_to_string(path.as_std_path()).unwrap(); let mut ignore = false; content .lines() @@ -2194,8 +2166,8 @@ impl<'test> TestCx<'test> { for other_file in other_files { let mut path = self.testpaths.file.clone(); path.set_file_name(&format!("{}.rs", other_file)); - let path = fs::canonicalize(path).expect("failed to canonicalize"); - let normalized = path.to_str().unwrap().replace('\\', "/"); + let path = path.canonicalize_utf8().expect("failed to canonicalize"); + let normalized = path.as_str().replace('\\', "/"); files.insert(normalized, self.get_lines(&path, None)); } @@ -2379,26 +2351,24 @@ impl<'test> TestCx<'test> { let mut normalized = output.to_string(); - let mut normalize_path = |from: &Path, to: &str| { - let mut from = from.display().to_string(); - if json { - from = from.replace("\\", "\\\\"); - } - normalized = normalized.replace(&from, to); + let mut normalize_path = |from: &Utf8Path, to: &str| { + let from = if json { &from.as_str().replace("\\", "\\\\") } else { from.as_str() }; + + normalized = normalized.replace(from, to); }; let parent_dir = self.testpaths.file.parent().unwrap(); normalize_path(parent_dir, "$DIR"); if self.props.remap_src_base { - let mut remapped_parent_dir = PathBuf::from(FAKE_SRC_BASE); - if self.testpaths.relative_dir != Path::new("") { + let mut remapped_parent_dir = Utf8PathBuf::from(FAKE_SRC_BASE); + if self.testpaths.relative_dir != Utf8Path::new("") { remapped_parent_dir.push(&self.testpaths.relative_dir); } normalize_path(&remapped_parent_dir, "$DIR"); } - let base_dir = Path::new("/rustc/FAKE_PREFIX"); + let base_dir = Utf8Path::new("/rustc/FAKE_PREFIX"); // Fake paths into the libstd/libcore normalize_path(&base_dir.join("library"), "$SRC_DIR"); // `ui-fulldeps` tests can show paths to the compiler source when testing macros from @@ -2408,19 +2378,26 @@ impl<'test> TestCx<'test> { // Real paths into the libstd/libcore let rust_src_dir = &self.config.sysroot_base.join("lib/rustlib/src/rust"); - rust_src_dir.try_exists().expect(&*format!("{} should exists", rust_src_dir.display())); - let rust_src_dir = rust_src_dir.read_link().unwrap_or(rust_src_dir.to_path_buf()); + rust_src_dir.try_exists().expect(&*format!("{} should exists", rust_src_dir)); + let rust_src_dir = rust_src_dir.read_link_utf8().unwrap_or(rust_src_dir.to_path_buf()); normalize_path(&rust_src_dir.join("library"), "$SRC_DIR_REAL"); // eg. // /home/user/rust/build/x86_64-unknown-linux-gnu/test/ui//$name.$revision.$mode/ normalize_path(&self.output_base_dir(), "$TEST_BUILD_DIR"); + // Same as above, but with a canonicalized path. + // This is required because some tests print canonical paths inside test build directory, + // so if the build directory is a symlink, normalization doesn't help. + // + // NOTE: There are also tests which print the non-canonical name, so we need both this and + // the above normalizations. + normalize_path(&self.output_base_dir().canonicalize_utf8().unwrap(), "$TEST_BUILD_DIR"); // eg. /home/user/rust/build normalize_path(&self.config.build_root, "$BUILD_DIR"); if json { // escaped newlines in json strings should be readable - // in the stderr files. There's no point int being correct, + // in the stderr files. There's no point in being correct, // since only humans process the stderr files. // Thus we just turn escaped newlines back into newlines. normalized = normalized.replace("\\n", "\n"); @@ -2549,7 +2526,7 @@ impl<'test> TestCx<'test> { .replace("\r\n", "\n") } - fn expected_output_path(&self, kind: &str) -> PathBuf { + fn expected_output_path(&self, kind: &str) -> Utf8PathBuf { let mut path = expected_output_path(&self.testpaths, self.revision, &self.config.compare_mode, kind); @@ -2578,19 +2555,18 @@ impl<'test> TestCx<'test> { } } - fn load_expected_output_from_path(&self, path: &Path) -> Result { - fs::read_to_string(path).map_err(|err| { - format!("failed to load expected output from `{}`: {}", path.display(), err) - }) + fn load_expected_output_from_path(&self, path: &Utf8Path) -> Result { + fs::read_to_string(path) + .map_err(|err| format!("failed to load expected output from `{}`: {}", path, err)) } - fn delete_file(&self, file: &Path) { + fn delete_file(&self, file: &Utf8Path) { if !file.exists() { // Deleting a nonexistent file would error. return; } - if let Err(e) = fs::remove_file(file) { - self.fatal(&format!("failed to delete `{}`: {}", file.display(), e,)); + if let Err(e) = fs::remove_file(file.as_std_path()) { + self.fatal(&format!("failed to delete `{}`: {}", file, e,)); } } @@ -2696,8 +2672,8 @@ impl<'test> TestCx<'test> { fn show_diff( &self, stream: &str, - expected_path: &Path, - actual_path: &Path, + expected_path: &Utf8Path, + actual_path: &Utf8Path, expected: &str, actual: &str, actual_unnormalized: &str, @@ -2836,7 +2812,7 @@ impl<'test> TestCx<'test> { fs::create_dir_all(&incremental_dir).unwrap(); if self.config.verbose { - println!("init_incremental_test: incremental_dir={}", incremental_dir.display()); + println!("init_incremental_test: incremental_dir={incremental_dir}"); } } } @@ -2894,8 +2870,8 @@ impl ProcRes { #[derive(Debug)] enum TargetLocation { - ThisFile(PathBuf), - ThisDirectory(PathBuf), + ThisFile(Utf8PathBuf), + ThisDirectory(Utf8PathBuf), } enum AllowUnused { diff --git a/src/tools/compiletest/src/runtest/assembly.rs b/src/tools/compiletest/src/runtest/assembly.rs index 89d7de58c203..91d4f620f719 100644 --- a/src/tools/compiletest/src/runtest/assembly.rs +++ b/src/tools/compiletest/src/runtest/assembly.rs @@ -1,4 +1,4 @@ -use std::path::PathBuf; +use camino::Utf8PathBuf; use super::{AllowUnused, Emit, LinkToAux, ProcRes, TargetLocation, TestCx}; @@ -19,7 +19,7 @@ impl TestCx<'_> { } } - fn compile_test_and_save_assembly(&self) -> (ProcRes, PathBuf) { + fn compile_test_and_save_assembly(&self) -> (ProcRes, Utf8PathBuf) { // This works with both `--emit asm` (as default output name for the assembly) // and `ptx-linker` because the latter can write output at requested location. let output_path = self.output_base_name().with_extension("s"); diff --git a/src/tools/compiletest/src/runtest/codegen_units.rs b/src/tools/compiletest/src/runtest/codegen_units.rs index 6c866cbef21a..8dfa8d18d1a0 100644 --- a/src/tools/compiletest/src/runtest/codegen_units.rs +++ b/src/tools/compiletest/src/runtest/codegen_units.rs @@ -26,9 +26,7 @@ impl TestCx<'_> { .stdout .lines() .filter(|line| line.starts_with(PREFIX)) - .map(|line| { - line.replace(&self.testpaths.file.display().to_string(), "TEST_PATH").to_string() - }) + .map(|line| line.replace(&self.testpaths.file.as_str(), "TEST_PATH").to_string()) .map(|line| str_to_mono_item(&line, true)) .collect(); diff --git a/src/tools/compiletest/src/runtest/coverage.rs b/src/tools/compiletest/src/runtest/coverage.rs index 56fc5baf5f24..41cfeaee35ff 100644 --- a/src/tools/compiletest/src/runtest/coverage.rs +++ b/src/tools/compiletest/src/runtest/coverage.rs @@ -1,9 +1,9 @@ //! Code specific to the coverage test suites. use std::ffi::OsStr; -use std::path::{Path, PathBuf}; use std::process::Command; +use camino::{Utf8Path, Utf8PathBuf}; use glob::glob; use crate::common::{UI_COVERAGE, UI_COVERAGE_MAP}; @@ -11,7 +11,7 @@ use crate::runtest::{Emit, ProcRes, TestCx, WillExecute}; use crate::util::static_regex; impl<'test> TestCx<'test> { - fn coverage_dump_path(&self) -> &Path { + fn coverage_dump_path(&self) -> &Utf8Path { self.config .coverage_dump_path .as_deref() @@ -79,10 +79,8 @@ impl<'test> TestCx<'test> { std::fs::remove_file(&profdata_path).unwrap(); } - let proc_res = self.exec_compiled_test_general( - &[("LLVM_PROFILE_FILE", &profraw_path.to_str().unwrap())], - false, - ); + let proc_res = + self.exec_compiled_test_general(&[("LLVM_PROFILE_FILE", profraw_path.as_str())], false); if self.props.failure_status.is_some() { self.check_correct_failure_status(&proc_res); } else if !proc_res.status.success() { @@ -158,8 +156,8 @@ impl<'test> TestCx<'test> { /// `.profraw` files and doctest executables to the given vectors. fn run_doctests_for_coverage( &self, - profraw_paths: &mut Vec, - bin_paths: &mut Vec, + profraw_paths: &mut Vec, + bin_paths: &mut Vec, ) { // Put .profraw files and doctest executables in dedicated directories, // to make it easier to glob them all later. @@ -204,10 +202,9 @@ impl<'test> TestCx<'test> { self.fatal_proc_rec("rustdoc --test failed!", &proc_res) } - fn glob_iter(path: impl AsRef) -> impl Iterator { - let path_str = path.as_ref().to_str().unwrap(); - let iter = glob(path_str).unwrap(); - iter.map(Result::unwrap) + fn glob_iter(path: impl AsRef) -> impl Iterator { + let iter = glob(path.as_ref().as_str()).unwrap(); + iter.map(Result::unwrap).map(Utf8PathBuf::try_from).map(Result::unwrap) } // Find all profraw files in the profraw directory. diff --git a/src/tools/compiletest/src/runtest/debugger.rs b/src/tools/compiletest/src/runtest/debugger.rs index d9e5c3fa0d8f..a4103c5b4a9a 100644 --- a/src/tools/compiletest/src/runtest/debugger.rs +++ b/src/tools/compiletest/src/runtest/debugger.rs @@ -1,7 +1,8 @@ use std::fmt::Write; use std::fs::File; use std::io::{BufRead, BufReader}; -use std::path::{Path, PathBuf}; + +use camino::{Utf8Path, Utf8PathBuf}; use crate::common::Config; use crate::runtest::ProcRes; @@ -15,11 +16,15 @@ pub(super) struct DebuggerCommands { /// Contains the source line number to check and the line itself check_lines: Vec<(usize, String)>, /// Source file name - file: PathBuf, + file: Utf8PathBuf, } impl DebuggerCommands { - pub fn parse_from(file: &Path, config: &Config, debugger_prefix: &str) -> Result { + pub fn parse_from( + file: &Utf8Path, + config: &Config, + debugger_prefix: &str, + ) -> Result { let command_directive = format!("{debugger_prefix}-command"); let check_directive = format!("{debugger_prefix}-check"); @@ -27,7 +32,7 @@ impl DebuggerCommands { let mut commands = vec![]; let mut check_lines = vec![]; let mut counter = 0; - let reader = BufReader::new(File::open(file).unwrap()); + let reader = BufReader::new(File::open(file.as_std_path()).unwrap()); for (line_no, line) in reader.lines().enumerate() { counter += 1; let line = line.map_err(|e| format!("Error while parsing debugger commands: {}", e))?; @@ -50,7 +55,7 @@ impl DebuggerCommands { } } - Ok(Self { commands, breakpoint_lines, check_lines, file: file.to_owned() }) + Ok(Self { commands, breakpoint_lines, check_lines, file: file.to_path_buf() }) } /// Given debugger output and lines to check, ensure that every line is @@ -81,10 +86,10 @@ impl DebuggerCommands { if missing.is_empty() { Ok(()) } else { - let fname = self.file.file_name().unwrap().to_string_lossy(); + let fname = self.file.file_name().unwrap(); let mut msg = format!( "check directive(s) from `{}` not found in debugger output. errors:", - self.file.display() + self.file ); for (src_lineno, err_line) in missing { diff --git a/src/tools/compiletest/src/runtest/debuginfo.rs b/src/tools/compiletest/src/runtest/debuginfo.rs index 170b8a809968..31240dff9a19 100644 --- a/src/tools/compiletest/src/runtest/debuginfo.rs +++ b/src/tools/compiletest/src/runtest/debuginfo.rs @@ -1,9 +1,9 @@ use std::ffi::{OsStr, OsString}; use std::fs::File; use std::io::{BufRead, BufReader, Read}; -use std::path::Path; use std::process::{Command, Output, Stdio}; +use camino::Utf8Path; use tracing::debug; use super::debugger::DebuggerCommands; @@ -73,11 +73,11 @@ impl TestCx<'_> { let mut js_extension = self.testpaths.file.clone(); js_extension.set_extension("cdb.js"); if js_extension.exists() { - script_str.push_str(&format!(".scriptload \"{}\"\n", js_extension.to_string_lossy())); + script_str.push_str(&format!(".scriptload \"{}\"\n", js_extension)); } // Set breakpoints on every line that contains the string "#break" - let source_file_name = self.testpaths.file.file_name().unwrap().to_string_lossy(); + let source_file_name = self.testpaths.file.file_name().unwrap(); for line in &dbg_cmds.breakpoint_lines { script_str.push_str(&format!("bp `{}:{}`\n", source_file_name, line)); } @@ -104,7 +104,7 @@ impl TestCx<'_> { let debugger_run_result = self.compose_and_run( cdb, - self.config.run_lib_path.to_str().unwrap(), + self.config.run_lib_path.as_path(), None, // aux_path None, // input ); @@ -151,16 +151,11 @@ impl TestCx<'_> { if is_android_gdb_target(&self.config.target) { cmds = cmds.replace("run", "continue"); - let tool_path = match self.config.android_cross_path.to_str() { - Some(x) => x.to_owned(), - None => self.fatal("cannot find android cross path"), - }; - // write debugger script let mut script_str = String::with_capacity(2048); script_str.push_str(&format!("set charset {}\n", Self::charset())); - script_str.push_str(&format!("set sysroot {}\n", tool_path)); - script_str.push_str(&format!("file {}\n", exe_file.to_str().unwrap())); + script_str.push_str(&format!("set sysroot {}\n", &self.config.android_cross_path)); + script_str.push_str(&format!("file {}\n", exe_file)); script_str.push_str("target remote :5039\n"); script_str.push_str(&format!( "set solib-search-path \ @@ -169,12 +164,8 @@ impl TestCx<'_> { )); for line in &dbg_cmds.breakpoint_lines { script_str.push_str( - format!( - "break {:?}:{}\n", - self.testpaths.file.file_name().unwrap().to_string_lossy(), - *line - ) - .as_str(), + format!("break {}:{}\n", self.testpaths.file.file_name().unwrap(), *line) + .as_str(), ); } script_str.push_str(&cmds); @@ -203,7 +194,7 @@ impl TestCx<'_> { self.config.adb_test_dir.clone(), if self.config.target.contains("aarch64") { "64" } else { "" }, self.config.adb_test_dir.clone(), - exe_file.file_name().unwrap().to_str().unwrap() + exe_file.file_name().unwrap() ); debug!("adb arg: {}", adb_arg); @@ -241,7 +232,8 @@ impl TestCx<'_> { let cmdline = { let mut gdb = Command::new(&format!("{}-gdb", self.config.target)); gdb.args(debugger_opts); - let cmdline = self.make_cmdline(&gdb, ""); + // FIXME(jieyouxu): don't pass an empty Path + let cmdline = self.make_cmdline(&gdb, Utf8Path::new("")); logv(self.config, format!("executing {}", cmdline)); cmdline }; @@ -258,7 +250,6 @@ impl TestCx<'_> { } } else { let rust_pp_module_abs_path = self.config.src_root.join("src").join("etc"); - let rust_pp_module_abs_path = rust_pp_module_abs_path.to_str().unwrap(); // write debugger script let mut script_str = String::with_capacity(2048); script_str.push_str(&format!("set charset {}\n", Self::charset())); @@ -273,17 +264,15 @@ impl TestCx<'_> { // GDB's script auto loading safe path script_str.push_str(&format!( "add-auto-load-safe-path {}\n", - rust_pp_module_abs_path.replace(r"\", r"\\") + rust_pp_module_abs_path.as_str().replace(r"\", r"\\") )); - let output_base_dir = self.output_base_dir().to_str().unwrap().to_owned(); - // Add the directory containing the output binary to // include embedded pretty printers to GDB's script // auto loading safe path script_str.push_str(&format!( "add-auto-load-safe-path {}\n", - output_base_dir.replace(r"\", r"\\") + self.output_base_dir().as_str().replace(r"\", r"\\") )); } } @@ -300,12 +289,13 @@ impl TestCx<'_> { script_str.push_str("set print pretty off\n"); // Add the pretty printer directory to GDB's source-file search path - script_str - .push_str(&format!("directory {}\n", rust_pp_module_abs_path.replace(r"\", r"\\"))); + script_str.push_str(&format!( + "directory {}\n", + rust_pp_module_abs_path.as_str().replace(r"\", r"\\") + )); // Load the target executable - script_str - .push_str(&format!("file {}\n", exe_file.to_str().unwrap().replace(r"\", r"\\"))); + script_str.push_str(&format!("file {}\n", exe_file.as_str().replace(r"\", r"\\"))); // Force GDB to print values in the Rust format. script_str.push_str("set language rust\n"); @@ -314,7 +304,7 @@ impl TestCx<'_> { for line in &dbg_cmds.breakpoint_lines { script_str.push_str(&format!( "break '{}':{}\n", - self.testpaths.file.file_name().unwrap().to_string_lossy(), + self.testpaths.file.file_name().unwrap(), *line )); } @@ -340,7 +330,7 @@ impl TestCx<'_> { gdb.args(debugger_opts).env("PYTHONPATH", pythonpath); debugger_run_result = - self.compose_and_run(gdb, self.config.run_lib_path.to_str().unwrap(), None, None); + self.compose_and_run(gdb, self.config.run_lib_path.as_path(), None, None); } if !debugger_run_result.status.success() { @@ -409,14 +399,14 @@ impl TestCx<'_> { script_str.push_str(&format!( "command script import {}/lldb_lookup.py\n", - rust_pp_module_abs_path.to_str().unwrap() + rust_pp_module_abs_path )); File::open(rust_pp_module_abs_path.join("lldb_commands")) .and_then(|mut file| file.read_to_string(&mut script_str)) .expect("Failed to read lldb_commands"); // Set breakpoints on every line that contains the string "#break" - let source_file_name = self.testpaths.file.file_name().unwrap().to_string_lossy(); + let source_file_name = self.testpaths.file.file_name().unwrap(); for line in &dbg_cmds.breakpoint_lines { script_str.push_str(&format!( "breakpoint set --file '{}' --line {}\n", @@ -450,7 +440,7 @@ impl TestCx<'_> { } } - fn run_lldb(&self, test_executable: &Path, debugger_script: &Path) -> ProcRes { + fn run_lldb(&self, test_executable: &Utf8Path, debugger_script: &Utf8Path) -> ProcRes { // Prepare the lldb_batchmode which executes the debugger script let lldb_script_path = self.config.src_root.join("src/etc/lldb_batchmode.py"); let pythonpath = if let Ok(pp) = std::env::var("PYTHONPATH") { diff --git a/src/tools/compiletest/src/runtest/js_doc.rs b/src/tools/compiletest/src/runtest/js_doc.rs index d630affbec10..fd53f01ca174 100644 --- a/src/tools/compiletest/src/runtest/js_doc.rs +++ b/src/tools/compiletest/src/runtest/js_doc.rs @@ -9,8 +9,7 @@ impl TestCx<'_> { self.document(&out_dir, &self.testpaths); - let file_stem = - self.testpaths.file.file_stem().and_then(|f| f.to_str()).expect("no file stem"); + let file_stem = self.testpaths.file.file_stem().expect("no file stem"); let res = self.run_command_to_procres( Command::new(&nodejs) .arg(self.config.src_root.join("src/tools/rustdoc-js/tester.js")) diff --git a/src/tools/compiletest/src/runtest/mir_opt.rs b/src/tools/compiletest/src/runtest/mir_opt.rs index d1ec00357449..ded6a68fe587 100644 --- a/src/tools/compiletest/src/runtest/mir_opt.rs +++ b/src/tools/compiletest/src/runtest/mir_opt.rs @@ -1,6 +1,6 @@ use std::fs; -use std::path::{Path, PathBuf}; +use camino::{Utf8Path, Utf8PathBuf}; use glob::glob; use miropt_test_tools::{MiroptTest, MiroptTestFile, files_for_miropt_test}; use tracing::debug; @@ -14,7 +14,7 @@ impl TestCx<'_> { let should_run = self.should_run(pm); let mut test_info = files_for_miropt_test( - &self.testpaths.file, + &self.testpaths.file.as_std_path(), self.config.get_pointer_width(), self.config.target_cfg().panic.for_miropt_test_tools(), ); @@ -38,20 +38,15 @@ impl TestCx<'_> { fn check_mir_dump(&self, test_info: MiroptTest) { let test_dir = self.testpaths.file.parent().unwrap(); - let test_crate = - self.testpaths.file.file_stem().unwrap().to_str().unwrap().replace('-', "_"); + let test_crate = self.testpaths.file.file_stem().unwrap().replace('-', "_"); let MiroptTest { run_filecheck, suffix, files, passes: _ } = test_info; if self.config.bless { - for e in - glob(&format!("{}/{}.*{}.mir", test_dir.display(), test_crate, suffix)).unwrap() - { + for e in glob(&format!("{}/{}.*{}.mir", test_dir, test_crate, suffix)).unwrap() { fs::remove_file(e.unwrap()).unwrap(); } - for e in - glob(&format!("{}/{}.*{}.diff", test_dir.display(), test_crate, suffix)).unwrap() - { + for e in glob(&format!("{}/{}.*{}.diff", test_dir, test_crate, suffix)).unwrap() { fs::remove_file(e.unwrap()).unwrap(); } } @@ -60,19 +55,15 @@ impl TestCx<'_> { let dumped_string = if let Some(after) = to_file { self.diff_mir_files(from_file.into(), after.into()) } else { - let mut output_file = PathBuf::new(); + let mut output_file = Utf8PathBuf::new(); output_file.push(self.get_mir_dump_dir()); output_file.push(&from_file); - debug!( - "comparing the contents of: {} with {}", - output_file.display(), - expected_file.display() - ); + debug!("comparing the contents of: {} with {:?}", output_file, expected_file); if !output_file.exists() { panic!( "Output file `{}` from test does not exist, available files are in `{}`", - output_file.display(), - output_file.parent().unwrap().display() + output_file, + output_file.parent().unwrap() ); } self.check_mir_test_timestamp(&from_file, &output_file); @@ -107,21 +98,20 @@ impl TestCx<'_> { } } - fn diff_mir_files(&self, before: PathBuf, after: PathBuf) -> String { - let to_full_path = |path: PathBuf| { + fn diff_mir_files(&self, before: Utf8PathBuf, after: Utf8PathBuf) -> String { + let to_full_path = |path: Utf8PathBuf| { let full = self.get_mir_dump_dir().join(&path); if !full.exists() { panic!( "the mir dump file for {} does not exist (requested in {})", - path.display(), - self.testpaths.file.display(), + path, self.testpaths.file, ); } full }; let before = to_full_path(before); let after = to_full_path(after); - debug!("comparing the contents of: {} with {}", before.display(), after.display()); + debug!("comparing the contents of: {} with {}", before, after); let before = fs::read_to_string(before).unwrap(); let after = fs::read_to_string(after).unwrap(); let before = self.normalize_output(&before, &[]); @@ -138,8 +128,8 @@ impl TestCx<'_> { dumped_string } - fn check_mir_test_timestamp(&self, test_name: &str, output_file: &Path) { - let t = |file| fs::metadata(file).unwrap().modified().unwrap(); + fn check_mir_test_timestamp(&self, test_name: &str, output_file: &Utf8Path) { + let t = |file: &Utf8Path| fs::metadata(file.as_std_path()).unwrap().modified().unwrap(); let source_file = &self.testpaths.file; let output_time = t(output_file); let source_time = t(source_file); @@ -147,8 +137,7 @@ impl TestCx<'_> { debug!("source file time: {:?} output file time: {:?}", source_time, output_time); panic!( "test source file `{}` is newer than potentially stale output file `{}`.", - source_file.display(), - test_name + source_file, test_name ); } } diff --git a/src/tools/compiletest/src/runtest/run_make.rs b/src/tools/compiletest/src/runtest/run_make.rs index 073116933bdb..a5ce929f9b8e 100644 --- a/src/tools/compiletest/src/runtest/run_make.rs +++ b/src/tools/compiletest/src/runtest/run_make.rs @@ -1,8 +1,8 @@ -use std::path::Path; use std::process::{Command, Output, Stdio}; use std::{env, fs}; use build_helper::fs::{ignore_not_found, recursive_remove}; +use camino::{Utf8Path, Utf8PathBuf}; use super::{ProcRes, TestCx, disable_error_reporting}; use crate::util::{copy_dir_all, dylib_env_var}; @@ -39,14 +39,16 @@ impl TestCx<'_> { // Copy all input files (apart from rmake.rs) to the temporary directory, // so that the input directory structure from `tests/run-make/` is mirrored // to the `rmake_out` directory. - for path in walkdir::WalkDir::new(&self.testpaths.file).min_depth(1) { - let path = path.unwrap().path().to_path_buf(); + for entry in walkdir::WalkDir::new(&self.testpaths.file).min_depth(1) { + let entry = entry.unwrap(); + let path = entry.path(); + let path = <&Utf8Path>::try_from(path).unwrap(); if path.file_name().is_some_and(|s| s != "rmake.rs") { let target = rmake_out_dir.join(path.strip_prefix(&self.testpaths.file).unwrap()); if path.is_dir() { - copy_dir_all(&path, target).unwrap(); + copy_dir_all(&path, &target).unwrap(); } else { - fs::copy(&path, target).unwrap(); + fs::copy(path.as_std_path(), target).unwrap(); } } } @@ -83,8 +85,10 @@ impl TestCx<'_> { // on some linux distros. // 2. Specific library paths in `self.config.compile_lib_path` needed for running rustc. - let base_dylib_search_paths = - Vec::from_iter(env::split_paths(&env::var(dylib_env_var()).unwrap())); + let base_dylib_search_paths = Vec::from_iter( + env::split_paths(&env::var(dylib_env_var()).unwrap()) + .map(|p| Utf8PathBuf::try_from(p).expect("dylib env var contains non-UTF8 paths")), + ); // Calculate the paths of the recipe binary. As previously discussed, this is placed at // `/` with `bin_name` being `rmake` or `rmake.exe` depending on @@ -113,13 +117,13 @@ impl TestCx<'_> { .arg("-o") .arg(&recipe_bin) // Specify library search paths for `run_make_support`. - .arg(format!("-Ldependency={}", &support_lib_path.parent().unwrap().to_string_lossy())) - .arg(format!("-Ldependency={}", &support_lib_deps.to_string_lossy())) - .arg(format!("-Ldependency={}", &support_lib_deps_deps.to_string_lossy())) + .arg(format!("-Ldependency={}", &support_lib_path.parent().unwrap())) + .arg(format!("-Ldependency={}", &support_lib_deps)) + .arg(format!("-Ldependency={}", &support_lib_deps_deps)) // Provide `run_make_support` as extern prelude, so test writers don't need to write // `extern run_make_support;`. .arg("--extern") - .arg(format!("run_make_support={}", &support_lib_path.to_string_lossy())) + .arg(format!("run_make_support={}", &support_lib_path)) .arg("--edition=2021") .arg(&self.testpaths.file.join("rmake.rs")) .arg("-Cprefer-dynamic"); @@ -240,7 +244,7 @@ impl TestCx<'_> { if self.config.target.contains("msvc") && !self.config.cc.is_empty() { // We need to pass a path to `lib.exe`, so assume that `cc` is `cl.exe` // and that `lib.exe` lives next to it. - let lib = Path::new(&self.config.cc).parent().unwrap().join("lib.exe"); + let lib = Utf8Path::new(&self.config.cc).parent().unwrap().join("lib.exe"); // MSYS doesn't like passing flags of the form `/foo` as it thinks it's // a path and instead passes `C:\msys64\foo`, so convert all @@ -262,8 +266,8 @@ impl TestCx<'_> { cmd.env("IS_MSVC", "1") .env("IS_WINDOWS", "1") - .env("MSVC_LIB", format!("'{}' -nologo", lib.display())) - .env("MSVC_LIB_PATH", format!("{}", lib.display())) + .env("MSVC_LIB", format!("'{}' -nologo", lib)) + .env("MSVC_LIB_PATH", &lib) // Note: we diverge from legacy run_make and don't lump `CC` the compiler and // default flags together. .env("CC_DEFAULT_FLAGS", &cflags) diff --git a/src/tools/compiletest/src/runtest/rustdoc.rs b/src/tools/compiletest/src/runtest/rustdoc.rs index 2583ae96a678..637ea833357a 100644 --- a/src/tools/compiletest/src/runtest/rustdoc.rs +++ b/src/tools/compiletest/src/runtest/rustdoc.rs @@ -7,7 +7,9 @@ impl TestCx<'_> { assert!(self.revision.is_none(), "revisions not relevant here"); let out_dir = self.output_base_dir(); - remove_and_create_dir_all(&out_dir); + remove_and_create_dir_all(&out_dir).unwrap_or_else(|e| { + panic!("failed to remove and recreate output directory `{out_dir}`: {e}") + }); let proc_res = self.document(&out_dir, &self.testpaths); if !proc_res.status.success() { diff --git a/src/tools/compiletest/src/runtest/rustdoc_json.rs b/src/tools/compiletest/src/runtest/rustdoc_json.rs index bf7eb2e109a4..9f88faca8926 100644 --- a/src/tools/compiletest/src/runtest/rustdoc_json.rs +++ b/src/tools/compiletest/src/runtest/rustdoc_json.rs @@ -9,7 +9,9 @@ impl TestCx<'_> { assert!(self.revision.is_none(), "revisions not relevant here"); let out_dir = self.output_base_dir(); - remove_and_create_dir_all(&out_dir); + remove_and_create_dir_all(&out_dir).unwrap_or_else(|e| { + panic!("failed to remove and recreate output directory `{out_dir}`: {e}") + }); let proc_res = self.document(&out_dir, &self.testpaths); if !proc_res.status.success() { diff --git a/src/tools/compiletest/src/runtest/ui.rs b/src/tools/compiletest/src/runtest/ui.rs index 974e5170465e..e87b037cd289 100644 --- a/src/tools/compiletest/src/runtest/ui.rs +++ b/src/tools/compiletest/src/runtest/ui.rs @@ -68,7 +68,7 @@ impl TestCx<'_> { { let mut coverage_file_path = self.config.build_test_suite_root.clone(); coverage_file_path.push("rustfix_missing_coverage.txt"); - debug!("coverage_file_path: {}", coverage_file_path.display()); + debug!("coverage_file_path: {}", coverage_file_path); let mut file = OpenOptions::new() .create(true) @@ -76,8 +76,8 @@ impl TestCx<'_> { .open(coverage_file_path.as_path()) .expect("could not create or open file"); - if let Err(e) = writeln!(file, "{}", self.testpaths.file.display()) { - panic!("couldn't write to {}: {e:?}", coverage_file_path.display()); + if let Err(e) = writeln!(file, "{}", self.testpaths.file) { + panic!("couldn't write to {}: {e:?}", coverage_file_path); } } } else if self.props.run_rustfix { @@ -119,7 +119,7 @@ impl TestCx<'_> { self.testpaths.relative_dir.join(self.testpaths.file.file_name().unwrap()); println!( "To only update this specific test, also pass `--test-args {}`", - relative_path_to_file.display(), + relative_path_to_file, ); self.fatal_proc_rec( &format!("{} errors occurred comparing output.", errors), @@ -211,8 +211,6 @@ impl TestCx<'_> { let crate_name = self.testpaths.file.file_stem().expect("test must have a file stem"); // crate name must be alphanumeric or `_`. - let crate_name = - crate_name.to_str().expect("crate name implies file name must be valid UTF-8"); // replace `a.foo` -> `a__foo` for crate name purposes. // replace `revision-name-with-dashes` -> `revision_name_with_underscore` let crate_name = crate_name.replace('.', "__"); diff --git a/src/tools/compiletest/src/tests.rs b/src/tools/compiletest/src/tests.rs index 43c6dc0a67e8..e3e4a81755d0 100644 --- a/src/tools/compiletest/src/tests.rs +++ b/src/tools/compiletest/src/tests.rs @@ -1,5 +1,3 @@ -use std::ffi::OsString; - use crate::debuggers::{extract_gdb_version, extract_lldb_version}; use crate::is_test; @@ -60,11 +58,11 @@ fn test_extract_lldb_version() { #[test] fn is_test_test() { - assert!(is_test(&OsString::from("a_test.rs"))); - assert!(!is_test(&OsString::from(".a_test.rs"))); - assert!(!is_test(&OsString::from("a_cat.gif"))); - assert!(!is_test(&OsString::from("#a_dog_gif"))); - assert!(!is_test(&OsString::from("~a_temp_file"))); + assert!(is_test("a_test.rs")); + assert!(!is_test(".a_test.rs")); + assert!(!is_test("a_cat.gif")); + assert!(!is_test("#a_dog_gif")); + assert!(!is_test("~a_temp_file")); } #[test] diff --git a/src/tools/compiletest/src/util.rs b/src/tools/compiletest/src/util.rs index bff02f1db9f0..81f5679aead7 100644 --- a/src/tools/compiletest/src/util.rs +++ b/src/tools/compiletest/src/util.rs @@ -1,8 +1,7 @@ use std::env; -use std::ffi::OsStr; -use std::path::{Path, PathBuf}; use std::process::Command; +use camino::{Utf8Path, Utf8PathBuf}; use tracing::*; use crate::common::Config; @@ -34,21 +33,21 @@ pub fn logv(config: &Config, s: String) { } } -pub trait PathBufExt { +pub trait Utf8PathBufExt { /// Append an extension to the path, even if it already has one. - fn with_extra_extension>(&self, extension: S) -> PathBuf; + fn with_extra_extension(&self, extension: &str) -> Utf8PathBuf; } -impl PathBufExt for PathBuf { - fn with_extra_extension>(&self, extension: S) -> PathBuf { - if extension.as_ref().is_empty() { +impl Utf8PathBufExt for Utf8PathBuf { + fn with_extra_extension(&self, extension: &str) -> Utf8PathBuf { + if extension.is_empty() { self.clone() } else { - let mut fname = self.file_name().unwrap().to_os_string(); - if !extension.as_ref().to_str().unwrap().starts_with('.') { - fname.push("."); + let mut fname = self.file_name().unwrap().to_string(); + if !extension.starts_with('.') { + fname.push_str("."); } - fname.push(extension); + fname.push_str(extension); self.with_file_name(fname) } } @@ -71,22 +70,27 @@ pub fn dylib_env_var() -> &'static str { /// Adds a list of lookup paths to `cmd`'s dynamic library lookup path. /// If the dylib_path_var is already set for this cmd, the old value will be overwritten! -pub fn add_dylib_path(cmd: &mut Command, paths: impl Iterator>) { +pub fn add_dylib_path( + cmd: &mut Command, + paths: impl Iterator>, +) { let path_env = env::var_os(dylib_env_var()); let old_paths = path_env.as_ref().map(env::split_paths); let new_paths = paths.map(Into::into).chain(old_paths.into_iter().flatten()); cmd.env(dylib_env_var(), env::join_paths(new_paths).unwrap()); } -pub fn copy_dir_all(src: impl AsRef, dst: impl AsRef) -> std::io::Result<()> { - std::fs::create_dir_all(&dst)?; - for entry in std::fs::read_dir(src)? { +pub fn copy_dir_all(src: &Utf8Path, dst: &Utf8Path) -> std::io::Result<()> { + std::fs::create_dir_all(dst.as_std_path())?; + for entry in std::fs::read_dir(src.as_std_path())? { let entry = entry?; + let path = Utf8PathBuf::try_from(entry.path()).unwrap(); + let file_name = path.file_name().unwrap(); let ty = entry.file_type()?; if ty.is_dir() { - copy_dir_all(entry.path(), dst.as_ref().join(entry.file_name()))?; + copy_dir_all(&path, &dst.join(file_name))?; } else { - std::fs::copy(entry.path(), dst.as_ref().join(entry.file_name()))?; + std::fs::copy(path.as_std_path(), dst.join(file_name).as_std_path())?; } } Ok(()) diff --git a/src/tools/compiletest/src/util/tests.rs b/src/tools/compiletest/src/util/tests.rs index b09a183b14e6..5bcae0dcee14 100644 --- a/src/tools/compiletest/src/util/tests.rs +++ b/src/tools/compiletest/src/util/tests.rs @@ -3,12 +3,12 @@ use super::*; #[test] fn path_buf_with_extra_extension_test() { assert_eq!( - PathBuf::from("foo.rs.stderr"), - PathBuf::from("foo.rs").with_extra_extension("stderr") + Utf8PathBuf::from("foo.rs.stderr"), + Utf8PathBuf::from("foo.rs").with_extra_extension("stderr") ); assert_eq!( - PathBuf::from("foo.rs.stderr"), - PathBuf::from("foo.rs").with_extra_extension(".stderr") + Utf8PathBuf::from("foo.rs.stderr"), + Utf8PathBuf::from("foo.rs").with_extra_extension(".stderr") ); - assert_eq!(PathBuf::from("foo.rs"), PathBuf::from("foo.rs").with_extra_extension("")); + assert_eq!(Utf8PathBuf::from("foo.rs"), Utf8PathBuf::from("foo.rs").with_extra_extension("")); } diff --git a/src/tools/generate-copyright/Cargo.toml b/src/tools/generate-copyright/Cargo.toml index 404101abd41b..ab76d0fc01e7 100644 --- a/src/tools/generate-copyright/Cargo.toml +++ b/src/tools/generate-copyright/Cargo.toml @@ -8,8 +8,8 @@ description = "Produces a manifest of all the copyrighted materials in the Rust [dependencies] anyhow = "1.0.65" +askama = "0.13.0" cargo_metadata = "0.18.1" -rinja = "0.3.0" serde = { version = "1.0.147", features = ["derive"] } serde_json = "1.0.85" thiserror = "1" diff --git a/src/tools/generate-copyright/src/main.rs b/src/tools/generate-copyright/src/main.rs index 79e90d88f444..d6ed7261b7c8 100644 --- a/src/tools/generate-copyright/src/main.rs +++ b/src/tools/generate-copyright/src/main.rs @@ -2,7 +2,7 @@ use std::collections::BTreeMap; use std::path::{Path, PathBuf}; use anyhow::Error; -use rinja::Template; +use askama::Template; mod cargo_metadata; @@ -117,7 +117,7 @@ struct Metadata { } /// Describes one node in our metadata tree -#[derive(serde::Deserialize, rinja::Template, Clone, Debug, PartialEq, Eq)] +#[derive(serde::Deserialize, Template, Clone, Debug, PartialEq, Eq)] #[serde(rename_all = "kebab-case", tag = "type")] #[template(path = "Node.html")] pub(crate) enum Node { diff --git a/src/tools/generate-windows-sys/Cargo.toml b/src/tools/generate-windows-sys/Cargo.toml index f5c0e56bb3c2..152cd504abd1 100644 --- a/src/tools/generate-windows-sys/Cargo.toml +++ b/src/tools/generate-windows-sys/Cargo.toml @@ -4,4 +4,4 @@ version = "0.1.0" edition = "2021" [dependencies.windows-bindgen] -version = "0.59.0" +version = "0.61.0" diff --git a/src/tools/jsondocck/src/main.rs b/src/tools/jsondocck/src/main.rs index 54249fbd9ae7..79e419884c68 100644 --- a/src/tools/jsondocck/src/main.rs +++ b/src/tools/jsondocck/src/main.rs @@ -156,7 +156,7 @@ static LINE_PATTERN: LazyLock = LazyLock::new(|| { r#" //@\s+ (?P!?) - (?P[A-Za-z]+(?:-[A-Za-z]+)*) + (?P[A-Za-z0-9]+(?:-[A-Za-z0-9]+)*) (?P.*)$ "#, ) diff --git a/src/tools/jsondoclint/src/validator/tests.rs b/src/tools/jsondoclint/src/validator/tests.rs index 28deb7e7ceef..dd0b4ac5601a 100644 --- a/src/tools/jsondoclint/src/validator/tests.rs +++ b/src/tools/jsondoclint/src/validator/tests.rs @@ -42,6 +42,7 @@ fn errors_on_missing_links() { )]), paths: FxHashMap::default(), external_crates: FxHashMap::default(), + target: rustdoc_json_types::Target { triple: "".to_string(), target_features: vec![] }, format_version: rustdoc_json_types::FORMAT_VERSION, }; @@ -112,6 +113,7 @@ fn errors_on_local_in_paths_and_not_index() { }, )]), external_crates: FxHashMap::default(), + target: rustdoc_json_types::Target { triple: "".to_string(), target_features: vec![] }, format_version: rustdoc_json_types::FORMAT_VERSION, }; @@ -216,6 +218,7 @@ fn errors_on_missing_path() { ItemSummary { crate_id: 0, path: vec!["foo".to_owned()], kind: ItemKind::Module }, )]), external_crates: FxHashMap::default(), + target: rustdoc_json_types::Target { triple: "".to_string(), target_features: vec![] }, format_version: rustdoc_json_types::FORMAT_VERSION, }; @@ -259,6 +262,7 @@ fn checks_local_crate_id_is_correct() { )]), paths: FxHashMap::default(), external_crates: FxHashMap::default(), + target: rustdoc_json_types::Target { triple: "".to_string(), target_features: vec![] }, format_version: FORMAT_VERSION, }; check(&krate, &[]); diff --git a/src/tools/miri/Cargo.lock b/src/tools/miri/Cargo.lock index b8100d0e7ad9..6f4bd3eab51a 100644 --- a/src/tools/miri/Cargo.lock +++ b/src/tools/miri/Cargo.lock @@ -39,31 +39,31 @@ dependencies = [ [[package]] name = "annotate-snippets" -version = "0.11.4" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24e35ed54e5ea7997c14ed4c70ba043478db1112e98263b3b035907aa197d991" +checksum = "710e8eae58854cdc1790fcb56cca04d712a17be849eeb81da2a724bf4bae2bc4" dependencies = [ "anstyle", - "unicode-width", + "unicode-width 0.2.0", ] [[package]] name = "anstyle" -version = "1.0.8" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" [[package]] name = "anyhow" -version = "1.0.86" +version = "1.0.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" +checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f" [[package]] name = "autocfg" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "backtrace" @@ -82,15 +82,15 @@ dependencies = [ [[package]] name = "bitflags" -version = "2.6.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" [[package]] name = "bstr" -version = "1.10.0" +version = "1.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40723b8fb387abc38f4f4a37c09073622e41dd12327033091ef8950659e6dc0c" +checksum = "531a9155a481e2ee699d4f98f43c0ca4ff8ee1bfd55c31e9e98fb29d2b176fe0" dependencies = [ "memchr", "regex-automata", @@ -98,25 +98,25 @@ dependencies = [ ] [[package]] -name = "byteorder" -version = "1.5.0" +name = "bumpalo" +version = "3.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" +checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" [[package]] name = "camino" -version = "1.1.7" +version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0ec6b951b160caa93cc0c7b209e5a3bff7aae9062213451ac99493cd844c239" +checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3" dependencies = [ "serde", ] [[package]] name = "cargo-platform" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24b1f0365a6c6bb4020cd05806fd0d33c44d38046b8bd7f0e40814b9763cabfc" +checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea" dependencies = [ "serde", ] @@ -132,14 +132,14 @@ dependencies = [ "semver", "serde", "serde_json", - "thiserror", + "thiserror 1.0.69", ] [[package]] name = "cc" -version = "1.1.22" +version = "1.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9540e661f81799159abee814118cc139a2004b3a3aa3ea37724a1b66530b90e0" +checksum = "1fcb57c740ae1daf453ae85f16e37396f672b039e00d9d866e07ddb24e328e3a" dependencies = [ "shlex", ] @@ -152,18 +152,18 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.38" +version = "0.4.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c" dependencies = [ "num-traits", ] [[package]] name = "chrono-tz" -version = "0.10.0" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd6dd8046d00723a59a2f8c5f295c515b9bb9a331ee4f8f3d4dd49e428acd3b6" +checksum = "efdce149c370f133a071ca8ef6ea340b7b88748ab0810097a9e2976eaa34b4f3" dependencies = [ "chrono", "chrono-tz-build", @@ -172,9 +172,9 @@ dependencies = [ [[package]] name = "chrono-tz-build" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94fea34d77a245229e7746bd2beb786cd2a896f306ff491fb8cecb3074b10a7" +checksum = "8f10f8c9340e31fc120ff885fcdb54a0b48e474bbd77cab557f0c30a3e569402" dependencies = [ "parse-zoneinfo", "phf_codegen", @@ -219,12 +219,12 @@ dependencies = [ [[package]] name = "colored" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8" +checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c" dependencies = [ "lazy_static", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -235,40 +235,40 @@ checksum = "55b672471b4e9f9e95499ea597ff64941a309b2cdbffcc46f2cc5e2d971fd335" [[package]] name = "console" -version = "0.15.8" +version = "0.15.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" +checksum = "054ccb5b10f9f2cbf51eb355ca1d05c2d279ce1804688d0db74b4733a5aeafd8" dependencies = [ "encode_unicode", - "lazy_static", "libc", - "unicode-width", - "windows-sys 0.52.0", + "once_cell", + "unicode-width 0.2.0", + "windows-sys", ] [[package]] name = "cpufeatures" -version = "0.2.12" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" dependencies = [ "libc", ] [[package]] name = "crossbeam-channel" -version = "0.5.13" +version = "0.5.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2" +checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.8.20" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crypto-common" @@ -282,39 +282,39 @@ dependencies = [ [[package]] name = "directories" -version = "5.0.1" +version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a49173b84e034382284f27f1af4dcbbd231ffa358c0fe316541a7337f376a35" +checksum = "16f5094c54661b38d03bd7e50df373292118db60b585c08a411c6d840017fe7d" dependencies = [ "dirs-sys", ] [[package]] name = "dirs-sys" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" +checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" dependencies = [ "libc", "option-ext", "redox_users", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] name = "encode_unicode" -version = "0.3.6" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" +checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" [[package]] name = "errno" -version = "0.3.9" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys", ] [[package]] @@ -329,9 +329,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.1.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] name = "generic-array" @@ -356,14 +356,14 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8" +checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0" dependencies = [ "cfg-if", "libc", - "wasi 0.13.3+wasi-0.2.2", - "windows-targets 0.52.6", + "r-efi", + "wasi 0.14.2+wasi-0.2.4", ] [[package]] @@ -380,40 +380,41 @@ checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" [[package]] name = "indicatif" -version = "0.17.8" +version = "0.17.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "763a5a8f45087d6bcea4222e7b72c291a054edf80e4ef6efd2a4979878c7bea3" +checksum = "183b3088984b400f4cfac3620d5e076c84da5364016b4f49473de574b2586235" dependencies = [ "console", - "instant", "number_prefix", "portable-atomic", - "unicode-width", + "unicode-width 0.2.0", + "web-time", ] [[package]] name = "inout" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" dependencies = [ "generic-array", ] [[package]] -name = "instant" -version = "0.1.13" +name = "itoa" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" -dependencies = [ - "cfg-if", -] +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] -name = "itoa" -version = "1.0.11" +name = "js-sys" +version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +dependencies = [ + "once_cell", + "wasm-bindgen", +] [[package]] name = "lazy_static" @@ -429,15 +430,15 @@ checksum = "db13adb97ab515a3691f56e4dbab09283d0b86cb45abd991d8634a9d6f501760" [[package]] name = "libc" -version = "0.2.155" +version = "0.2.171" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" +checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" [[package]] name = "libffi" -version = "3.2.0" +version = "4.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce826c243048e3d5cec441799724de52e2d42f820468431fc3fceee2341871e2" +checksum = "4a9434b6fc77375fb624698d5f8c49d7e80b10d59eb1219afda27d1f824d4074" dependencies = [ "libc", "libffi-sys", @@ -445,21 +446,21 @@ dependencies = [ [[package]] name = "libffi-sys" -version = "2.3.0" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f36115160c57e8529781b4183c2bb51fdc1f6d6d1ed345591d84be7703befb3c" +checksum = "ead36a2496acfc8edd6cc32352110e9478ac5b9b5f5b9856ebd3d28019addb84" dependencies = [ "cc", ] [[package]] name = "libloading" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" +checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" dependencies = [ "cfg-if", - "windows-targets 0.52.6", + "windows-targets", ] [[package]] @@ -474,9 +475,9 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.4.14" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +checksum = "fe7db12097d22ec582439daf8618b8fdd1a7bef6270e9af3b1ebcd30893cf413" [[package]] name = "lock_api" @@ -490,15 +491,15 @@ dependencies = [ [[package]] name = "log" -version = "0.4.22" +version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" [[package]] name = "measureme" -version = "11.0.1" +version = "12.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfa4a40f09af7aa6faef38285402a78847d0d72bf8827006cd2a332e1e6e4a8d" +checksum = "570a507d8948a66a97f42cbbaf8a6bb9516a51017d4ee949502ad7a10a864395" dependencies = [ "log", "memmap2", @@ -537,11 +538,12 @@ name = "miri" version = "0.1.0" dependencies = [ "aes", + "bitflags", "chrono", "chrono-tz", "colored", "directories", - "getrandom 0.3.1", + "getrandom 0.3.2", "libc", "libffi", "libloading", @@ -553,7 +555,7 @@ dependencies = [ "tempfile", "tikv-jemalloc-sys", "ui_test", - "windows-sys 0.52.0", + "windows-sys", ] [[package]] @@ -582,9 +584,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.19.0" +version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "option-ext" @@ -604,7 +606,7 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2ad9b889f1b12e0b9ee24db044b5129150d5eada288edc800f789928dc8c0e3" dependencies = [ - "unicode-width", + "unicode-width 0.1.14", ] [[package]] @@ -627,7 +629,7 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "windows-targets 0.52.6", + "windows-targets", ] [[package]] @@ -650,18 +652,18 @@ dependencies = [ [[package]] name = "phf" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" +checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" dependencies = [ "phf_shared", ] [[package]] name = "phf_codegen" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8d39688d359e6b34654d328e262234662d16cc0f60ec8dcbe5e718709342a5a" +checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a" dependencies = [ "phf_generator", "phf_shared", @@ -669,9 +671,9 @@ dependencies = [ [[package]] name = "phf_generator" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" +checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" dependencies = [ "phf_shared", "rand 0.8.5", @@ -679,32 +681,32 @@ dependencies = [ [[package]] name = "phf_shared" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" +checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" dependencies = [ "siphasher", ] [[package]] name = "pin-project-lite" -version = "0.2.14" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" [[package]] name = "portable-atomic" -version = "1.7.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da544ee218f0d287a911e9c99a39a8c9bc8fcad3cb8db5959940044ecfc67265" +checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e" [[package]] name = "ppv-lite86" -version = "0.2.20" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" dependencies = [ - "zerocopy 0.7.35", + "zerocopy", ] [[package]] @@ -719,22 +721,28 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.86" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.36" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "5.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" + [[package]] name = "rand" version = "0.8.5" @@ -751,8 +759,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" dependencies = [ "rand_chacha", - "rand_core 0.9.0", - "zerocopy 0.8.14", + "rand_core 0.9.3", + "zerocopy", ] [[package]] @@ -762,7 +770,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", - "rand_core 0.9.0", + "rand_core 0.9.3", ] [[package]] @@ -773,39 +781,38 @@ checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" [[package]] name = "rand_core" -version = "0.9.0" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b08f3c9802962f7e1b25113931d94f43ed9725bebc59db9d0c3e9a23b67e15ff" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" dependencies = [ - "getrandom 0.3.1", - "zerocopy 0.8.14", + "getrandom 0.3.2", ] [[package]] name = "redox_syscall" -version = "0.5.3" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" +checksum = "0b8c0c260b63a8219631167be35e6a988e9554dbd323f8bd08439c8ed1302bd1" dependencies = [ "bitflags", ] [[package]] name = "redox_users" -version = "0.4.5" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" +checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b" dependencies = [ "getrandom 0.2.15", "libredox", - "thiserror", + "thiserror 2.0.12", ] [[package]] name = "regex" -version = "1.10.6" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", @@ -815,9 +822,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.7" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", @@ -826,9 +833,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "rustc-demangle" @@ -844,43 +851,43 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustc_version" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" dependencies = [ "semver", ] [[package]] name = "rustfix" -version = "0.8.5" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70f5b7fc8060f4f8373f9381a630304b42e1183535d9beb1d3f596b236c9106a" +checksum = "82fa69b198d894d84e23afde8e9ab2af4400b2cba20d6bf2b428a8b01c222c5a" dependencies = [ "serde", "serde_json", - "thiserror", + "thiserror 1.0.69", "tracing", ] [[package]] name = "rustix" -version = "0.38.34" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +checksum = "d97817398dd4bb2e6da002002db259209759911da105da92bec29ccb12cf58bf" dependencies = [ "bitflags", "errno", "libc", "linux-raw-sys", - "windows-sys 0.52.0", + "windows-sys", ] [[package]] name = "ryu" -version = "1.0.18" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[package]] name = "scopeguard" @@ -890,27 +897,27 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "semver" -version = "1.0.23" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" +checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" dependencies = [ "serde", ] [[package]] name = "serde" -version = "1.0.204" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.204" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", @@ -919,9 +926,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.122" +version = "1.0.140" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784b6203951c57ff748476b126ccb5e8e2959a5c19e5c617ab1956be3dbc68da" +checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" dependencies = [ "itoa", "memchr", @@ -946,15 +953,15 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "siphasher" -version = "0.3.11" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" +checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" [[package]] name = "smallvec" -version = "1.13.2" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd" [[package]] name = "spanned" @@ -968,9 +975,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.72" +version = "2.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af" +checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" dependencies = [ "proc-macro2", "quote", @@ -979,31 +986,51 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.11.0" +version = "3.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8fcd239983515c23a32fb82099f97d0b11b8c72f654ed659363a95c3dad7a53" +checksum = "7437ac7763b9b123ccf33c338a5cc1bac6f69b45a136c19bdd8a65e3916435bf" dependencies = [ - "cfg-if", "fastrand", + "getrandom 0.3.2", "once_cell", "rustix", - "windows-sys 0.52.0", + "windows-sys", ] [[package]] name = "thiserror" -version = "1.0.63" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ - "thiserror-impl", + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +dependencies = [ + "thiserror-impl 2.0.12", ] [[package]] name = "thiserror-impl" -version = "1.0.63" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" dependencies = [ "proc-macro2", "quote", @@ -1032,9 +1059,9 @@ dependencies = [ [[package]] name = "tracing" -version = "0.1.40" +version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" dependencies = [ "pin-project-lite", "tracing-core", @@ -1042,9 +1069,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.32" +version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" dependencies = [ "once_cell", "valuable", @@ -1052,9 +1079,9 @@ dependencies = [ [[package]] name = "tracing-error" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d686ec1c0f384b1277f097b2f279a2ecc11afe8c133c1aabf036a27cb4cd206e" +checksum = "8b1581020d7a273442f5b45074a6a57d5757ad0a47dac0e9f0bd57b81936f3db" dependencies = [ "tracing", "tracing-subscriber", @@ -1062,9 +1089,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.18" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" dependencies = [ "sharded-slab", "thread_local", @@ -1073,15 +1100,15 @@ dependencies = [ [[package]] name = "typenum" -version = "1.17.0" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" [[package]] name = "ui_test" -version = "0.29.1" +version = "0.29.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14bf63f2931a28a04af0bd24c5f850223d29f3a40afae49ed6ce442a65eb8652" +checksum = "1211b1111c752c73b33073d2958072be08825fd97c9ab4d83444da361a06634b" dependencies = [ "annotate-snippets", "anyhow", @@ -1105,21 +1132,27 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" [[package]] name = "unicode-width" -version = "0.1.13" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" + +[[package]] +name = "unicode-width" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" [[package]] name = "valuable" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" [[package]] name = "version_check" @@ -1135,44 +1168,87 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasi" -version = "0.13.3+wasi-0.2.2" +version = "0.14.2+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2" +checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" dependencies = [ "wit-bindgen-rt", ] [[package]] -name = "windows-sys" -version = "0.48.0" +name = "wasm-bindgen" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" dependencies = [ - "windows-targets 0.48.5", + "cfg-if", + "once_cell", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" +dependencies = [ + "bumpalo", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", ] [[package]] name = "windows-sys" -version = "0.52.0" +version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", + "windows-targets", ] [[package]] @@ -1181,46 +1257,28 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", "windows_i686_gnullvm", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - [[package]] name = "windows_i686_gnu" version = "0.52.6" @@ -1233,48 +1291,24 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - [[package]] name = "windows_x86_64_msvc" version = "0.52.6" @@ -1283,48 +1317,27 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "wit-bindgen-rt" -version = "0.33.0" +version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c" +checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" dependencies = [ "bitflags", ] [[package]] name = "zerocopy" -version = "0.7.35" +version = "0.8.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +checksum = "2586fea28e186957ef732a5f8b3be2da217d65c5969d4b1e17f973ebbe876879" dependencies = [ - "byteorder", - "zerocopy-derive 0.7.35", -] - -[[package]] -name = "zerocopy" -version = "0.8.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a367f292d93d4eab890745e75a778da40909cab4d6ff8173693812f79c4a2468" -dependencies = [ - "zerocopy-derive 0.8.14", + "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.35" +version = "0.8.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "zerocopy-derive" -version = "0.8.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3931cb58c62c13adec22e38686b559c86a30565e16ad6e8510a337cedc611e1" +checksum = "a996a8f63c5c4448cd959ac1bab0aaa3306ccfd060472f85943ee0750f0169be" dependencies = [ "proc-macro2", "quote", diff --git a/src/tools/miri/Cargo.toml b/src/tools/miri/Cargo.toml index 5d8c9a866445..bb24e700e738 100644 --- a/src/tools/miri/Cargo.toml +++ b/src/tools/miri/Cargo.toml @@ -22,10 +22,11 @@ getrandom = { version = "0.3", features = ["std"] } rand = "0.9" smallvec = { version = "1.7", features = ["drain_filter"] } aes = { version = "0.8.3", features = ["hazmat"] } -measureme = "11" +measureme = "12" chrono = { version = "0.4.38", default-features = false } chrono-tz = "0.10" -directories = "5" +directories = "6" +bitflags = "2.6" # Copied from `compiler/rustc/Cargo.toml`. # But only for some targets, it fails for others. Rustc configures this in its CI, but we can't @@ -36,11 +37,11 @@ features = ['unprefixed_malloc_on_supported_platforms'] [target.'cfg(unix)'.dependencies] libc = "0.2" -libffi = "3.2.0" +libffi = "4.0.0" libloading = "0.8" [target.'cfg(target_family = "windows")'.dependencies] -windows-sys = { version = "0.52", features = [ +windows-sys = { version = "0.59", features = [ "Win32_Foundation", "Win32_System_IO", "Win32_Storage_FileSystem", diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md index 201aa1f53869..e8ea988558ce 100644 --- a/src/tools/miri/README.md +++ b/src/tools/miri/README.md @@ -565,6 +565,7 @@ Definite bugs found: * [Occasional memory leak in `std::mpsc` channels](https://github.com/rust-lang/rust/issues/121582) (original code in [crossbeam](https://github.com/crossbeam-rs/crossbeam/pull/1084)) * [Weak-memory-induced memory leak in Windows thread-local storage](https://github.com/rust-lang/rust/pull/124281) * [A bug in the new `RwLock::downgrade` implementation](https://rust-lang.zulipchat.com/#narrow/channel/269128-miri/topic/Miri.20error.20library.20test) (caught by Miri before it landed in the Rust repo) +* [Mockall reading unintialized memory when mocking `std::io::Read::read`, even if all expectations are satisfied](https://github.com/asomers/mockall/issues/647) (caught by Miri running Tokio's test suite) Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows is currently just an experiment): diff --git a/src/tools/miri/bench-cargo-miri/big-allocs/src/main.rs b/src/tools/miri/bench-cargo-miri/big-allocs/src/main.rs index a1c1708cf3ba..5b807ac3df1f 100644 --- a/src/tools/miri/bench-cargo-miri/big-allocs/src/main.rs +++ b/src/tools/miri/bench-cargo-miri/big-allocs/src/main.rs @@ -7,7 +7,10 @@ fn main() { // We can't use too big of an allocation or this code will encounter an allocation failure in // CI. Since the allocation can't be huge, we need to do a few iterations so that the effect // we're trying to measure is clearly visible above the interpreter's startup time. - for _ in 0..10 { + // FIXME (https://github.com/rust-lang/miri/issues/4253): On 32bit targets, we can run out of + // usable addresses if we don't reuse, leading to random test failures. + let count = if cfg!(target_pointer_width = "32") { 8 } else { 12 }; + for _ in 0..count { drop(Vec::::with_capacity(512 * 1024 * 1024)); } } diff --git a/src/tools/miri/cargo-miri/Cargo.lock b/src/tools/miri/cargo-miri/Cargo.lock index b8e08d39a861..bd4ca2860f35 100644 --- a/src/tools/miri/cargo-miri/Cargo.lock +++ b/src/tools/miri/cargo-miri/Cargo.lock @@ -4,21 +4,21 @@ version = 4 [[package]] name = "anyhow" -version = "1.0.86" +version = "1.0.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" +checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f" [[package]] name = "bitflags" -version = "2.6.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" [[package]] name = "camino" -version = "1.1.7" +version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0ec6b951b160caa93cc0c7b209e5a3bff7aae9062213451ac99493cd844c239" +checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3" dependencies = [ "serde", ] @@ -38,18 +38,18 @@ dependencies = [ [[package]] name = "cargo-platform" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24b1f0365a6c6bb4020cd05806fd0d33c44d38046b8bd7f0e40814b9763cabfc" +checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea" dependencies = [ "serde", ] [[package]] name = "cargo_metadata" -version = "0.18.1" +version = "0.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d886547e41f740c616ae73108f6eb70afe6d940c7bc697cb30f13daec073037" +checksum = "dd5eb614ed4c27c5d706420e4320fbe3216ab31fa1c33cd8246ac36dae4479ba" dependencies = [ "camino", "cargo-platform", @@ -67,40 +67,40 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "directories" -version = "5.0.1" +version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a49173b84e034382284f27f1af4dcbbd231ffa358c0fe316541a7337f376a35" +checksum = "16f5094c54661b38d03bd7e50df373292118db60b585c08a411c6d840017fe7d" dependencies = [ "dirs-sys", ] [[package]] name = "dirs-sys" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" +checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" dependencies = [ "libc", "option-ext", "redox_users", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] name = "errno" -version = "0.3.9" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys", ] [[package]] name = "fastrand" -version = "2.1.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] name = "getrandom" @@ -110,20 +110,32 @@ checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "libc", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasi 0.14.2+wasi-0.2.4", ] [[package]] name = "itoa" -version = "1.0.11" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "libc" -version = "0.2.155" +version = "0.2.171" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" +checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" [[package]] name = "libredox" @@ -137,9 +149,9 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.4.14" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +checksum = "fe7db12097d22ec582439daf8618b8fdd1a7bef6270e9af3b1ebcd30893cf413" [[package]] name = "memchr" @@ -149,9 +161,9 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "once_cell" -version = "1.19.0" +version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "option-ext" @@ -161,29 +173,35 @@ checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" [[package]] name = "proc-macro2" -version = "1.0.86" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.36" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" dependencies = [ "proc-macro2", ] [[package]] -name = "redox_users" -version = "0.4.5" +name = "r-efi" +version = "5.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" +checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" + +[[package]] +name = "redox_users" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b" dependencies = [ - "getrandom", + "getrandom 0.2.15", "libredox", "thiserror", ] @@ -202,37 +220,37 @@ dependencies = [ [[package]] name = "rustc_tools_util" -version = "0.4.0" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3316159ab19e19d1065ecc49278e87f767a9dae9fae80348d2b4d4fa4ae02d4d" +checksum = "a3b75158011a63889ba12084cf1224baad7bcad50f6ee7c842f772b74aa148ed" [[package]] name = "rustc_version" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" dependencies = [ "semver", ] [[package]] name = "rustix" -version = "0.38.34" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +checksum = "d97817398dd4bb2e6da002002db259209759911da105da92bec29ccb12cf58bf" dependencies = [ "bitflags", "errno", "libc", "linux-raw-sys", - "windows-sys 0.52.0", + "windows-sys", ] [[package]] name = "ryu" -version = "1.0.18" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[package]] name = "same-file" @@ -245,27 +263,27 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.23" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" +checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" dependencies = [ "serde", ] [[package]] name = "serde" -version = "1.0.204" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.204" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", @@ -274,9 +292,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.122" +version = "1.0.140" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784b6203951c57ff748476b126ccb5e8e2959a5c19e5c617ab1956be3dbc68da" +checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" dependencies = [ "itoa", "memchr", @@ -286,9 +304,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.72" +version = "2.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af" +checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" dependencies = [ "proc-macro2", "quote", @@ -297,31 +315,31 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.11.0" +version = "3.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8fcd239983515c23a32fb82099f97d0b11b8c72f654ed659363a95c3dad7a53" +checksum = "7437ac7763b9b123ccf33c338a5cc1bac6f69b45a136c19bdd8a65e3916435bf" dependencies = [ - "cfg-if", "fastrand", + "getrandom 0.3.2", "once_cell", "rustix", - "windows-sys 0.52.0", + "windows-sys", ] [[package]] name = "thiserror" -version = "1.0.63" +version = "2.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" +checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.63" +version = "2.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" +checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" dependencies = [ "proc-macro2", "quote", @@ -330,9 +348,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" [[package]] name = "walkdir" @@ -350,31 +368,22 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasi" +version = "0.14.2+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +dependencies = [ + "wit-bindgen-rt", +] + [[package]] name = "winapi-util" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.59.0", -] - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", -] - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets 0.52.6", + "windows-sys", ] [[package]] @@ -383,22 +392,7 @@ version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", + "windows-targets", ] [[package]] @@ -407,46 +401,28 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", "windows_i686_gnullvm", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - [[package]] name = "windows_i686_gnu" version = "0.52.6" @@ -459,50 +435,35 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - [[package]] name = "windows_x86_64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "wit-bindgen-rt" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" +dependencies = [ + "bitflags", +] diff --git a/src/tools/miri/cargo-miri/Cargo.toml b/src/tools/miri/cargo-miri/Cargo.toml index de0988d6d1cd..ed142b0e2114 100644 --- a/src/tools/miri/cargo-miri/Cargo.toml +++ b/src/tools/miri/cargo-miri/Cargo.toml @@ -14,10 +14,10 @@ test = false # we have no unit tests doctest = false # and no doc tests [dependencies] -directories = "5" +directories = "6" rustc_version = "0.4" serde_json = "1.0.40" -cargo_metadata = "0.18.0" +cargo_metadata = "0.19" rustc-build-sysroot = "0.5.4" # Enable some feature flags that dev-dependencies need but dependencies diff --git a/src/tools/miri/ci/ci.sh b/src/tools/miri/ci/ci.sh index 7155d692ee5c..755e02d02eca 100755 --- a/src/tools/miri/ci/ci.sh +++ b/src/tools/miri/ci/ci.sh @@ -164,9 +164,9 @@ case $HOST_TARGET in # Partially supported targets (tier 2) BASIC="empty_main integer heap_alloc libc-mem vec string btreemap" # ensures we have the basics: pre-main code, system allocator UNIX="hello panic/panic panic/unwind concurrency/simple atomic libc-mem libc-misc libc-random env num_cpus" # the things that are very similar across all Unixes, and hence easily supported there - TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal $BASIC $UNIX time hashmap random threadname pthread fs libc-pipe - TEST_TARGET=i686-unknown-freebsd run_tests_minimal $BASIC $UNIX time hashmap random threadname pthread fs libc-pipe - TEST_TARGET=aarch64-linux-android run_tests_minimal $BASIC $UNIX time hashmap random sync concurrency thread epoll eventfd + TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal $BASIC $UNIX time hashmap random thread sync concurrency fs libc-pipe + TEST_TARGET=i686-unknown-freebsd run_tests_minimal $BASIC $UNIX time hashmap random thread sync concurrency fs libc-pipe + TEST_TARGET=aarch64-linux-android run_tests_minimal $BASIC $UNIX time hashmap random thread sync concurrency epoll eventfd TEST_TARGET=wasm32-wasip2 run_tests_minimal $BASIC wasm TEST_TARGET=wasm32-unknown-unknown run_tests_minimal no_std empty_main wasm # this target doesn't really have std TEST_TARGET=thumbv7em-none-eabihf run_tests_minimal no_std diff --git a/src/tools/miri/miri-script/Cargo.lock b/src/tools/miri/miri-script/Cargo.lock index 25c6f817575e..3494a241ec50 100644 --- a/src/tools/miri/miri-script/Cargo.lock +++ b/src/tools/miri/miri-script/Cargo.lock @@ -38,30 +38,31 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" dependencies = [ - "windows-sys 0.59.0", + "windows-sys", ] [[package]] name = "anstyle-wincon" -version = "3.0.6" +version = "3.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" +checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" dependencies = [ "anstyle", - "windows-sys 0.59.0", + "once_cell", + "windows-sys", ] [[package]] name = "anyhow" -version = "1.0.80" +version = "1.0.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1" +checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f" [[package]] name = "bitflags" -version = "2.4.2" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" +checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" [[package]] name = "cfg-if" @@ -71,9 +72,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clap" -version = "4.5.23" +version = "4.5.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3135e7ec2ef7b10c6ed8950f0f792ed96ee093fa088608f1c76e569722700c84" +checksum = "d8aa86934b44c19c50f87cc2790e19f54f7a67aedb64101c2e1a2e5ecfb73944" dependencies = [ "clap_builder", "clap_derive", @@ -81,9 +82,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.23" +version = "4.5.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30582fc632330df2bd26877bde0c1f4470d57c582bbc070376afcd04d8cb4838" +checksum = "2414dbb2dd0695280da6ea9261e327479e9d37b0630f6b53ba2a11c60c679fd9" dependencies = [ "anstream", "anstyle", @@ -93,9 +94,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.18" +version = "4.5.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" +checksum = "09176aae279615badda0765c0c0b3f6ed53f4709118af73cf4655d85d1530cd7" dependencies = [ "heck", "proc-macro2", @@ -117,62 +118,80 @@ checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" [[package]] name = "directories" -version = "5.0.1" +version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a49173b84e034382284f27f1af4dcbbd231ffa358c0fe316541a7337f376a35" +checksum = "16f5094c54661b38d03bd7e50df373292118db60b585c08a411c6d840017fe7d" dependencies = [ "dirs-sys", ] [[package]] name = "dirs-sys" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" +checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" dependencies = [ "libc", "option-ext", "redox_users", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] name = "dunce" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" [[package]] name = "either" -version = "1.10.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "env_home" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7f84e12ccf0a7ddc17a6c41c93326024c42920d7ee630d04950e6926645c0fe" [[package]] name = "errno" -version = "0.3.9" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys", ] [[package]] name = "fastrand" -version = "2.1.1" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] name = "getrandom" -version = "0.2.12" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "libc", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasi 0.14.2+wasi-0.2.4", ] [[package]] @@ -181,15 +200,6 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" -[[package]] -name = "home" -version = "0.5.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" -dependencies = [ - "windows-sys 0.52.0", -] - [[package]] name = "is_terminal_polyfill" version = "1.70.1" @@ -198,24 +208,24 @@ checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" [[package]] name = "itertools" -version = "0.11.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" dependencies = [ "either", ] [[package]] name = "itoa" -version = "1.0.11" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "libc" -version = "0.2.159" +version = "0.2.171" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" +checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" [[package]] name = "libredox" @@ -229,9 +239,15 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.4.14" +version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" + +[[package]] +name = "linux-raw-sys" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe7db12097d22ec582439daf8618b8fdd1a7bef6270e9af3b1ebcd30893cf413" [[package]] name = "memchr" @@ -262,9 +278,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.20.2" +version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "option-ext" @@ -280,60 +296,79 @@ checksum = "a6e819bbd49d5939f682638fa54826bf1650abddcd65d000923de8ad63cc7d15" [[package]] name = "proc-macro2" -version = "1.0.78" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.35" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" dependencies = [ "proc-macro2", ] [[package]] -name = "redox_users" -version = "0.4.6" +name = "r-efi" +version = "5.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" +checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" + +[[package]] +name = "redox_users" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b" dependencies = [ - "getrandom", + "getrandom 0.2.15", "libredox", "thiserror", ] [[package]] name = "rustc_version" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" dependencies = [ "semver", ] [[package]] name = "rustix" -version = "0.38.37" +version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ "bitflags", "errno", "libc", - "linux-raw-sys", - "windows-sys 0.52.0", + "linux-raw-sys 0.4.15", + "windows-sys", +] + +[[package]] +name = "rustix" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d97817398dd4bb2e6da002002db259209759911da105da92bec29ccb12cf58bf" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys 0.9.3", + "windows-sys", ] [[package]] name = "ryu" -version = "1.0.18" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[package]] name = "same-file" @@ -346,24 +381,24 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.22" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" +checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" [[package]] name = "serde" -version = "1.0.210" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.210" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", @@ -372,9 +407,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.128" +version = "1.0.140" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" +checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" dependencies = [ "itoa", "memchr", @@ -396,9 +431,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" -version = "2.0.50" +version = "2.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74f1bdc9872430ce9b75da68329d1c1746faf50ffac5f19e02b71e37ff881ffb" +checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" dependencies = [ "proc-macro2", "quote", @@ -407,31 +442,31 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.13.0" +version = "3.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b" +checksum = "7437ac7763b9b123ccf33c338a5cc1bac6f69b45a136c19bdd8a65e3916435bf" dependencies = [ - "cfg-if", "fastrand", + "getrandom 0.3.2", "once_cell", - "rustix", - "windows-sys 0.59.0", + "rustix 1.0.5", + "windows-sys", ] [[package]] name = "thiserror" -version = "1.0.57" +version = "2.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b" +checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.57" +version = "2.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81" +checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" dependencies = [ "proc-macro2", "quote", @@ -440,9 +475,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" [[package]] name = "utf8parse" @@ -452,9 +487,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "walkdir" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" dependencies = [ "same-file", "winapi-util", @@ -467,14 +502,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] -name = "which" -version = "6.0.3" +name = "wasi" +version = "0.14.2+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4ee928febd44d98f2f459a4a79bd4d928591333a494a10a868418ac1b39cf1f" +checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +dependencies = [ + "wit-bindgen-rt", +] + +[[package]] +name = "which" +version = "7.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2774c861e1f072b3aadc02f8ba886c26ad6321567ecc294c935434cad06f1283" dependencies = [ "either", - "home", - "rustix", + "env_home", + "rustix 0.38.44", "winsafe", ] @@ -484,25 +528,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.59.0", -] - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", -] - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets 0.52.6", + "windows-sys", ] [[package]] @@ -511,22 +537,7 @@ version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", + "windows-targets", ] [[package]] @@ -535,46 +546,28 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", "windows_i686_gnullvm", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - [[package]] name = "windows_i686_gnu" version = "0.52.6" @@ -587,48 +580,24 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - [[package]] name = "windows_x86_64_msvc" version = "0.52.6" @@ -641,6 +610,15 @@ version = "0.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904" +[[package]] +name = "wit-bindgen-rt" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" +dependencies = [ + "bitflags", +] + [[package]] name = "xshell" version = "0.2.7" diff --git a/src/tools/miri/miri-script/Cargo.toml b/src/tools/miri/miri-script/Cargo.toml index 5879b2717e5d..a04898de6aba 100644 --- a/src/tools/miri/miri-script/Cargo.toml +++ b/src/tools/miri/miri-script/Cargo.toml @@ -13,16 +13,16 @@ edition = "2021" # This is needed to make this package build on stable when the parent package uses unstable cargo features. [dependencies] -which = "6.0" +which = "7" walkdir = "2.3" -itertools = "0.11" +itertools = "0.14" path_macro = "1.0" shell-words = "1.1" anyhow = "1.0" xshell = "0.2.6" rustc_version = "0.4" dunce = "1.0.4" -directories = "5" +directories = "6" serde = "1" serde_json = "1" serde_derive = "1" diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index cf36b6fd0385..d1107e515090 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -4ac032f857b46037b55c1fc0fa702450aad37f43 +1bc56185ee257ed829a0aea7abdc3b03c5fed887 diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs index 56ee96502b3e..4e8fe0ca8adf 100644 --- a/src/tools/miri/src/bin/miri.rs +++ b/src/tools/miri/src/bin/miri.rs @@ -185,7 +185,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { let num_failed = sync::IntoDynSyncSend(AtomicU32::new(0)); sync::par_for_each_in(many_seeds.seeds.clone(), |seed| { let mut config = config.clone(); - config.seed = Some(seed.into()); + config.seed = Some((*seed).into()); eprintln!("Trying seed: {seed}"); let return_code = miri::eval_entry(tcx, entry_def_id, entry_type, config) .unwrap_or(rustc_driver::EXIT_FAILURE); diff --git a/src/tools/miri/src/clock.rs b/src/tools/miri/src/clock.rs index c9bffc449f7f..34465e9cac60 100644 --- a/src/tools/miri/src/clock.rs +++ b/src/tools/miri/src/clock.rs @@ -62,12 +62,12 @@ impl Instant { /// A monotone clock used for `Instant` simulation. #[derive(Debug)] -pub struct Clock { - kind: ClockKind, +pub struct MonotonicClock { + kind: MonotonicClockKind, } #[derive(Debug)] -enum ClockKind { +enum MonotonicClockKind { Host { /// The "epoch" for this machine's monotone clock: /// the moment we consider to be time = 0. @@ -79,13 +79,13 @@ enum ClockKind { }, } -impl Clock { +impl MonotonicClock { /// Create a new clock based on the availability of communication with the host. pub fn new(communicate: bool) -> Self { let kind = if communicate { - ClockKind::Host { epoch: StdInstant::now() } + MonotonicClockKind::Host { epoch: StdInstant::now() } } else { - ClockKind::Virtual { nanoseconds: 0.into() } + MonotonicClockKind::Virtual { nanoseconds: 0.into() } }; Self { kind } @@ -94,10 +94,10 @@ impl Clock { /// Let the time pass for a small interval. pub fn tick(&self) { match &self.kind { - ClockKind::Host { .. } => { + MonotonicClockKind::Host { .. } => { // Time will pass without us doing anything. } - ClockKind::Virtual { nanoseconds } => { + MonotonicClockKind::Virtual { nanoseconds } => { nanoseconds.update(|x| x + NANOSECONDS_PER_BASIC_BLOCK); } } @@ -106,8 +106,8 @@ impl Clock { /// Sleep for the desired duration. pub fn sleep(&self, duration: Duration) { match &self.kind { - ClockKind::Host { .. } => std::thread::sleep(duration), - ClockKind::Virtual { nanoseconds } => { + MonotonicClockKind::Host { .. } => std::thread::sleep(duration), + MonotonicClockKind::Virtual { nanoseconds } => { // Just pretend that we have slept for some time. let nanos: u128 = duration.as_nanos(); nanoseconds.update(|x| { @@ -121,15 +121,17 @@ impl Clock { /// Return the `epoch` instant (time = 0), to convert between monotone instants and absolute durations. pub fn epoch(&self) -> Instant { match &self.kind { - ClockKind::Host { epoch } => Instant { kind: InstantKind::Host(*epoch) }, - ClockKind::Virtual { .. } => Instant { kind: InstantKind::Virtual { nanoseconds: 0 } }, + MonotonicClockKind::Host { epoch } => Instant { kind: InstantKind::Host(*epoch) }, + MonotonicClockKind::Virtual { .. } => + Instant { kind: InstantKind::Virtual { nanoseconds: 0 } }, } } pub fn now(&self) -> Instant { match &self.kind { - ClockKind::Host { .. } => Instant { kind: InstantKind::Host(StdInstant::now()) }, - ClockKind::Virtual { nanoseconds } => + MonotonicClockKind::Host { .. } => + Instant { kind: InstantKind::Host(StdInstant::now()) }, + MonotonicClockKind::Virtual { nanoseconds } => Instant { kind: InstantKind::Virtual { nanoseconds: nanoseconds.get() } }, } } diff --git a/src/tools/miri/src/concurrency/thread.rs b/src/tools/miri/src/concurrency/thread.rs index 94629964ea60..72fa918e8e51 100644 --- a/src/tools/miri/src/concurrency/thread.rs +++ b/src/tools/miri/src/concurrency/thread.rs @@ -347,7 +347,7 @@ enum Timeout { impl Timeout { /// How long do we have to wait from now until the specified time? - fn get_wait_time(&self, clock: &Clock) -> Duration { + fn get_wait_time(&self, clock: &MonotonicClock) -> Duration { match self { Timeout::Monotonic(instant) => instant.duration_since(clock.now()), Timeout::RealTime(time) => @@ -683,7 +683,7 @@ impl<'tcx> ThreadManager<'tcx> { } /// Get the wait time for the next timeout, or `None` if no timeout is pending. - fn next_callback_wait_time(&self, clock: &Clock) -> Option { + fn next_callback_wait_time(&self, clock: &MonotonicClock) -> Option { self.threads .iter() .filter_map(|t| { @@ -702,7 +702,7 @@ impl<'tcx> ThreadManager<'tcx> { /// used in stateless model checkers such as Loom: run the active thread as /// long as we can and switch only when we have to (the active thread was /// blocked, terminated, or has explicitly asked to be preempted). - fn schedule(&mut self, clock: &Clock) -> InterpResult<'tcx, SchedulingAction> { + fn schedule(&mut self, clock: &MonotonicClock) -> InterpResult<'tcx, SchedulingAction> { // This thread and the program can keep going. if self.threads[self.active_thread].state.is_enabled() && !self.yield_active_thread { // The currently active thread is still enabled, just continue with it. @@ -772,7 +772,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { for (id, thread) in this.machine.threads.threads.iter_enumerated_mut() { match &thread.state { ThreadState::Blocked { timeout: Some(timeout), .. } - if timeout.get_wait_time(&this.machine.clock) == Duration::ZERO => + if timeout.get_wait_time(&this.machine.monotonic_clock) == Duration::ZERO => { let old_state = mem::replace(&mut thread.state, ThreadState::Enabled); let ThreadState::Blocked { callback, .. } = old_state else { unreachable!() }; @@ -1006,8 +1006,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } TimeoutClock::Monotonic => Timeout::Monotonic(match anchor { - TimeoutAnchor::Absolute => this.machine.clock.epoch(), - TimeoutAnchor::Relative => this.machine.clock.now(), + TimeoutAnchor::Absolute => this.machine.monotonic_clock.epoch(), + TimeoutAnchor::Relative => this.machine.monotonic_clock.now(), }), }; anchor.add_lossy(duration) @@ -1152,7 +1152,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.machine.handle_abnormal_termination(); throw_machine_stop!(TerminationInfo::Interrupted); } - match this.machine.threads.schedule(&this.machine.clock)? { + match this.machine.threads.schedule(&this.machine.monotonic_clock)? { SchedulingAction::ExecuteStep => { if !this.step()? { // See if this thread can do something else. @@ -1167,7 +1167,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.run_timeout_callback()?; } SchedulingAction::Sleep(duration) => { - this.machine.clock.sleep(duration); + this.machine.monotonic_clock.sleep(duration); } } } diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs index ed13f670a90e..7586b5efd4b2 100644 --- a/src/tools/miri/src/eval.rs +++ b/src/tools/miri/src/eval.rs @@ -459,8 +459,13 @@ pub fn eval_entry<'tcx>( ecx.handle_ice(); panic::resume_unwind(panic_payload) }); - // `Ok` can never happen. + // `Ok` can never happen; the interpreter loop always exits with an "error" + // (but that "error" might be just "regular program termination"). let Err(err) = res.report_err(); + // Show diagnostic, if any. + let (return_code, leak_check) = report_error(&ecx, err)?; + + // If we get here there was no fatal error. // Machine cleanup. Only do this if all threads have terminated; threads that are still running // might cause Stacked Borrows errors (https://github.com/rust-lang/miri/issues/2396). @@ -472,8 +477,7 @@ pub fn eval_entry<'tcx>( EnvVars::cleanup(&mut ecx).expect("error during env var cleanup"); } - // Process the result. - let (return_code, leak_check) = report_error(&ecx, err)?; + // Possibly check for memory leaks. if leak_check && !ignore_leaks { // Check for thread leaks. if !ecx.have_all_terminated() { diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index 29ed94a2e4a2..b4098ca0750c 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -602,6 +602,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // We want to not actually read from memory for this visit. So, before // walking this value, we have to make sure it is not a // `Variants::Multiple`. + // FIXME: the current logic here is layout-dependent, so enums with + // multiple variants where all but 1 are uninhabited will be recursed into. + // Is that truly what we want? match v.layout.variants { Variants::Multiple { .. } => { // A multi-variant enum, or coroutine, or so. diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs index 03f76cfa6524..5921ba866390 100644 --- a/src/tools/miri/src/lib.rs +++ b/src/tools/miri/src/lib.rs @@ -121,7 +121,7 @@ pub use crate::borrow_tracker::stacked_borrows::{ }; pub use crate::borrow_tracker::tree_borrows::{EvalContextExt as _, Tree}; pub use crate::borrow_tracker::{BorTag, BorrowTrackerMethod, EvalContextExt as _, RetagFields}; -pub use crate::clock::{Clock, Instant}; +pub use crate::clock::{Instant, MonotonicClock}; pub use crate::concurrency::cpu_affinity::MAX_CPUS; pub use crate::concurrency::data_race::{ AtomicFenceOrd, AtomicReadOrd, AtomicRwOrd, AtomicWriteOrd, EvalContextExt as _, diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index fb99bdc51764..ea59d327be84 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -486,7 +486,7 @@ pub struct MiriMachine<'tcx> { pub(crate) epoll_interests: shims::EpollInterestTable, /// This machine's monotone clock. - pub(crate) clock: Clock, + pub(crate) monotonic_clock: MonotonicClock, /// The set of threads. pub(crate) threads: ThreadManager<'tcx>, @@ -713,7 +713,7 @@ impl<'tcx> MiriMachine<'tcx> { preemption_rate: config.preemption_rate, report_progress: config.report_progress, basic_block_count: 0, - clock: Clock::new(config.isolated_op == IsolatedOp::Allow), + monotonic_clock: MonotonicClock::new(config.isolated_op == IsolatedOp::Allow), #[cfg(unix)] native_lib: config.native_lib.as_ref().map(|lib_file_path| { let host_triple = rustc_session::config::host_tuple(); @@ -896,7 +896,7 @@ impl VisitProvenance for MiriMachine<'_> { tcx: _, isolated_op: _, validation: _, - clock: _, + monotonic_clock: _, layouts: _, static_roots: _, profiler: _, @@ -1568,7 +1568,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { ecx.maybe_preempt_active_thread(); // Make sure some time passes. - ecx.machine.clock.tick(); + ecx.machine.monotonic_clock.tick(); interp_ok(()) } diff --git a/src/tools/miri/src/shims/files.rs b/src/tools/miri/src/shims/files.rs index 6b4f4cdc922a..42603e784bbd 100644 --- a/src/tools/miri/src/shims/files.rs +++ b/src/tools/miri/src/shims/files.rs @@ -1,6 +1,7 @@ use std::any::Any; use std::collections::BTreeMap; -use std::io::{IsTerminal, SeekFrom, Write}; +use std::fs::{File, Metadata}; +use std::io::{IsTerminal, Seek, SeekFrom, Write}; use std::marker::CoercePointee; use std::ops::Deref; use std::rc::{Rc, Weak}; @@ -192,7 +193,7 @@ pub trait FileDescription: std::fmt::Debug + FileDescriptionExt { false } - fn as_unix(&self) -> &dyn UnixFileDescription { + fn as_unix<'tcx>(&self, _ecx: &MiriInterpCx<'tcx>) -> &dyn UnixFileDescription { panic!("Not a unix file descriptor: {}", self.name()); } } @@ -278,6 +279,97 @@ impl FileDescription for io::Stderr { } } +#[derive(Debug)] +pub struct FileHandle { + pub(crate) file: File, + pub(crate) writable: bool, +} + +impl FileDescription for FileHandle { + fn name(&self) -> &'static str { + "file" + } + + fn read<'tcx>( + self: FileDescriptionRef, + communicate_allowed: bool, + ptr: Pointer, + len: usize, + ecx: &mut MiriInterpCx<'tcx>, + finish: DynMachineCallback<'tcx, Result>, + ) -> InterpResult<'tcx> { + assert!(communicate_allowed, "isolation should have prevented even opening a file"); + + let result = ecx.read_from_host(&self.file, len, ptr)?; + finish.call(ecx, result) + } + + fn write<'tcx>( + self: FileDescriptionRef, + communicate_allowed: bool, + ptr: Pointer, + len: usize, + ecx: &mut MiriInterpCx<'tcx>, + finish: DynMachineCallback<'tcx, Result>, + ) -> InterpResult<'tcx> { + assert!(communicate_allowed, "isolation should have prevented even opening a file"); + + let result = ecx.write_to_host(&self.file, len, ptr)?; + finish.call(ecx, result) + } + + fn seek<'tcx>( + &self, + communicate_allowed: bool, + offset: SeekFrom, + ) -> InterpResult<'tcx, io::Result> { + assert!(communicate_allowed, "isolation should have prevented even opening a file"); + interp_ok((&mut &self.file).seek(offset)) + } + + fn close<'tcx>( + self, + communicate_allowed: bool, + _ecx: &mut MiriInterpCx<'tcx>, + ) -> InterpResult<'tcx, io::Result<()>> { + assert!(communicate_allowed, "isolation should have prevented even opening a file"); + // We sync the file if it was opened in a mode different than read-only. + if self.writable { + // `File::sync_all` does the checks that are done when closing a file. We do this to + // to handle possible errors correctly. + let result = self.file.sync_all(); + // Now we actually close the file and return the result. + drop(self.file); + interp_ok(result) + } else { + // We drop the file, this closes it but ignores any errors + // produced when closing it. This is done because + // `File::sync_all` cannot be done over files like + // `/dev/urandom` which are read-only. Check + // https://github.com/rust-lang/miri/issues/999#issuecomment-568920439 + // for a deeper discussion. + drop(self.file); + interp_ok(Ok(())) + } + } + + fn metadata<'tcx>(&self) -> InterpResult<'tcx, io::Result> { + interp_ok(self.file.metadata()) + } + + fn is_tty(&self, communicate_allowed: bool) -> bool { + communicate_allowed && self.file.is_terminal() + } + + fn as_unix<'tcx>(&self, ecx: &MiriInterpCx<'tcx>) -> &dyn UnixFileDescription { + assert!( + ecx.target_os_is_unix(), + "unix file operations are only available for unix targets" + ); + self + } +} + /// Like /dev/null #[derive(Debug)] pub struct NullOutput; @@ -300,10 +392,13 @@ impl FileDescription for NullOutput { } } +/// Internal type of a file-descriptor - this is what [`FdTable`] expects +pub type FdNum = i32; + /// The file descriptor table #[derive(Debug)] pub struct FdTable { - pub fds: BTreeMap, + pub fds: BTreeMap, /// Unique identifier for file description, used to differentiate between various file description. next_file_description_id: FdId, } @@ -339,12 +434,12 @@ impl FdTable { } /// Insert a new file description to the FdTable. - pub fn insert_new(&mut self, fd: impl FileDescription) -> i32 { + pub fn insert_new(&mut self, fd: impl FileDescription) -> FdNum { let fd_ref = self.new_ref(fd); self.insert(fd_ref) } - pub fn insert(&mut self, fd_ref: DynFileDescriptionRef) -> i32 { + pub fn insert(&mut self, fd_ref: DynFileDescriptionRef) -> FdNum { self.insert_with_min_num(fd_ref, 0) } @@ -352,8 +447,8 @@ impl FdTable { pub fn insert_with_min_num( &mut self, file_handle: DynFileDescriptionRef, - min_fd_num: i32, - ) -> i32 { + min_fd_num: FdNum, + ) -> FdNum { // Find the lowest unused FD, starting from min_fd. If the first such unused FD is in // between used FDs, the find_map combinator will return it. If the first such unused FD // is after all other used FDs, the find_map combinator will return None, and we will use @@ -379,16 +474,16 @@ impl FdTable { new_fd_num } - pub fn get(&self, fd_num: i32) -> Option { + pub fn get(&self, fd_num: FdNum) -> Option { let fd = self.fds.get(&fd_num)?; Some(fd.clone()) } - pub fn remove(&mut self, fd_num: i32) -> Option { + pub fn remove(&mut self, fd_num: FdNum) -> Option { self.fds.remove(&fd_num) } - pub fn is_fd_num(&self, fd_num: i32) -> bool { + pub fn is_fd_num(&self, fd_num: FdNum) -> bool { self.fds.contains_key(&fd_num) } } diff --git a/src/tools/miri/src/shims/time.rs b/src/tools/miri/src/shims/time.rs index 64b3ce6b4e49..fb80a36af9fc 100644 --- a/src/tools/miri/src/shims/time.rs +++ b/src/tools/miri/src/shims/time.rs @@ -79,7 +79,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.check_no_isolation("`clock_gettime` with `REALTIME` clocks")?; system_time_to_duration(&SystemTime::now())? } else if relative_clocks.contains(&clk_id) { - this.machine.clock.now().duration_since(this.machine.clock.epoch()) + this.machine.monotonic_clock.now().duration_since(this.machine.monotonic_clock.epoch()) } else { return this.set_last_error_and_return_i32(LibcError("EINVAL")); }; @@ -219,16 +219,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let filetime = this.deref_pointer_as(LPFILETIME_op, this.windows_ty_layout("FILETIME"))?; - let NANOS_PER_SEC = this.eval_windows_u64("time", "NANOS_PER_SEC"); - let INTERVALS_PER_SEC = this.eval_windows_u64("time", "INTERVALS_PER_SEC"); - let INTERVALS_TO_UNIX_EPOCH = this.eval_windows_u64("time", "INTERVALS_TO_UNIX_EPOCH"); - let NANOS_PER_INTERVAL = NANOS_PER_SEC / INTERVALS_PER_SEC; - let SECONDS_TO_UNIX_EPOCH = INTERVALS_TO_UNIX_EPOCH / INTERVALS_PER_SEC; - - let duration = system_time_to_duration(&SystemTime::now())? - + Duration::from_secs(SECONDS_TO_UNIX_EPOCH); - let duration_ticks = u64::try_from(duration.as_nanos() / u128::from(NANOS_PER_INTERVAL)) - .map_err(|_| err_unsup_format!("programs running more than 2^64 Windows ticks after the Windows epoch are not supported"))?; + let duration = this.system_time_since_windows_epoch(&SystemTime::now())?; + let duration_ticks = this.windows_ticks_for(duration)?; let dwLowDateTime = u32::try_from(duration_ticks & 0x00000000FFFFFFFF).unwrap(); let dwHighDateTime = u32::try_from((duration_ticks & 0xFFFFFFFF00000000) >> 32).unwrap(); @@ -248,7 +240,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // QueryPerformanceCounter uses a hardware counter as its basis. // Miri will emulate a counter with a resolution of 1 nanosecond. - let duration = this.machine.clock.now().duration_since(this.machine.clock.epoch()); + let duration = + this.machine.monotonic_clock.now().duration_since(this.machine.monotonic_clock.epoch()); let qpc = i64::try_from(duration.as_nanos()).map_err(|_| { err_unsup_format!("programs running longer than 2^63 nanoseconds are not supported") })?; @@ -280,6 +273,30 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { interp_ok(Scalar::from_i32(-1)) // Return non-zero on success } + #[allow(non_snake_case, clippy::arithmetic_side_effects)] + fn system_time_since_windows_epoch(&self, time: &SystemTime) -> InterpResult<'tcx, Duration> { + let this = self.eval_context_ref(); + + let INTERVALS_PER_SEC = this.eval_windows_u64("time", "INTERVALS_PER_SEC"); + let INTERVALS_TO_UNIX_EPOCH = this.eval_windows_u64("time", "INTERVALS_TO_UNIX_EPOCH"); + let SECONDS_TO_UNIX_EPOCH = INTERVALS_TO_UNIX_EPOCH / INTERVALS_PER_SEC; + + interp_ok(system_time_to_duration(time)? + Duration::from_secs(SECONDS_TO_UNIX_EPOCH)) + } + + #[allow(non_snake_case, clippy::arithmetic_side_effects)] + fn windows_ticks_for(&self, duration: Duration) -> InterpResult<'tcx, u64> { + let this = self.eval_context_ref(); + + let NANOS_PER_SEC = this.eval_windows_u64("time", "NANOS_PER_SEC"); + let INTERVALS_PER_SEC = this.eval_windows_u64("time", "INTERVALS_PER_SEC"); + let NANOS_PER_INTERVAL = NANOS_PER_SEC / INTERVALS_PER_SEC; + + let ticks = u64::try_from(duration.as_nanos() / u128::from(NANOS_PER_INTERVAL)) + .map_err(|_| err_unsup_format!("programs running more than 2^64 Windows ticks after the Windows epoch are not supported"))?; + interp_ok(ticks) + } + fn mach_absolute_time(&self) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_ref(); @@ -287,7 +304,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // This returns a u64, with time units determined dynamically by `mach_timebase_info`. // We return plain nanoseconds. - let duration = this.machine.clock.now().duration_since(this.machine.clock.epoch()); + let duration = + this.machine.monotonic_clock.now().duration_since(this.machine.monotonic_clock.epoch()); let res = u64::try_from(duration.as_nanos()).map_err(|_| { err_unsup_format!("programs running longer than 2^64 nanoseconds are not supported") })?; diff --git a/src/tools/miri/src/shims/unix/fd.rs b/src/tools/miri/src/shims/unix/fd.rs index 3f85b9ae9bd9..41be9df7e2da 100644 --- a/src/tools/miri/src/shims/unix/fd.rs +++ b/src/tools/miri/src/shims/unix/fd.rs @@ -121,7 +121,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { throw_unsup_format!("unsupported flags {:#x}", op); }; - let result = fd.as_unix().flock(this.machine.communicate(), parsed_op)?; + let result = fd.as_unix(this).flock(this.machine.communicate(), parsed_op)?; // return `0` if flock is successful let result = result.map(|()| 0i32); interp_ok(Scalar::from_i32(this.try_unwrap_io_result(result)?)) @@ -273,7 +273,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let Ok(offset) = u64::try_from(offset) else { return this.set_last_error_and_return(LibcError("EINVAL"), dest); }; - fd.as_unix().pread(communicate, offset, buf, count, this, finish)? + fd.as_unix(this).pread(communicate, offset, buf, count, this, finish)? } }; interp_ok(()) @@ -333,7 +333,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let Ok(offset) = u64::try_from(offset) else { return this.set_last_error_and_return(LibcError("EINVAL"), dest); }; - fd.as_unix().pwrite(communicate, buf, count, offset, this, finish)? + fd.as_unix(this).pwrite(communicate, buf, count, offset, this, finish)? } }; interp_ok(()) diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs index 1770b99c0a22..5e6259c35744 100644 --- a/src/tools/miri/src/shims/unix/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/foreign_items.rs @@ -231,6 +231,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(result, dest)?; } "flock" => { + // Currently this function does not exist on all Unixes, e.g. on Solaris. + this.check_target_os(&["linux", "freebsd", "macos", "illumos"], link_name)?; let [fd, op] = this.check_shim(abi, Conv::C, link_name, args)?; let fd = this.read_scalar(fd)?.to_i32()?; let op = this.read_scalar(op)?.to_i32()?; diff --git a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs index 08d06fe5d4c6..21a386b29272 100644 --- a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs @@ -2,6 +2,7 @@ use rustc_middle::ty::Ty; use rustc_span::Symbol; use rustc_target::callconv::{Conv, FnAbi}; +use super::sync::EvalContextExt as _; use crate::shims::unix::*; use crate::*; @@ -55,6 +56,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(res, dest)?; } + // Synchronization primitives + "_umtx_op" => { + let [obj, op, val, uaddr, uaddr2] = + this.check_shim(abi, Conv::C, link_name, args)?; + this._umtx_op(obj, op, val, uaddr, uaddr2, dest)?; + } + // File related shims // For those, we both intercept `func` and `call@FBSD_1.0` symbols cases // since freebsd 12 the former form can be expected. diff --git a/src/tools/miri/src/shims/unix/freebsd/mod.rs b/src/tools/miri/src/shims/unix/freebsd/mod.rs index 09c6507b24f8..50fb2b9d3287 100644 --- a/src/tools/miri/src/shims/unix/freebsd/mod.rs +++ b/src/tools/miri/src/shims/unix/freebsd/mod.rs @@ -1 +1,2 @@ pub mod foreign_items; +pub mod sync; diff --git a/src/tools/miri/src/shims/unix/freebsd/sync.rs b/src/tools/miri/src/shims/unix/freebsd/sync.rs new file mode 100644 index 000000000000..54650f35b2cb --- /dev/null +++ b/src/tools/miri/src/shims/unix/freebsd/sync.rs @@ -0,0 +1,251 @@ +//! Contains FreeBSD-specific synchronization functions + +use core::time::Duration; + +use crate::concurrency::sync::FutexRef; +use crate::*; + +pub struct FreeBsdFutex { + futex: FutexRef, +} + +/// Extended variant of the `timespec` struct. +pub struct UmtxTime { + timeout: Duration, + abs_time: bool, + timeout_clock: TimeoutClock, +} + +impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} +pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { + /// Implementation of the FreeBSD [`_umtx_op`](https://man.freebsd.org/cgi/man.cgi?query=_umtx_op&sektion=2&manpath=FreeBSD+14.2-RELEASE+and+Ports) syscall. + /// This is used for futex operations on FreeBSD. + /// + /// `obj`: a pointer to the futex object (can be a lot of things, mostly *AtomicU32) + /// `op`: the futex operation to run + /// `val`: the current value of the object as a `c_long` (for wait/wake) + /// `uaddr`: `op`-specific optional parameter, pointer-sized integer or pointer to an `op`-specific struct + /// `uaddr2`: `op`-specific optional parameter, pointer-sized integer or pointer to an `op`-specific struct + /// `dest`: the place this syscall returns to, 0 for success, -1 for failure + /// + /// # Note + /// Curently only the WAIT and WAKE operations are implemented. + fn _umtx_op( + &mut self, + obj: &OpTy<'tcx>, + op: &OpTy<'tcx>, + val: &OpTy<'tcx>, + uaddr: &OpTy<'tcx>, + uaddr2: &OpTy<'tcx>, + dest: &MPlaceTy<'tcx>, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + + let obj = this.read_pointer(obj)?; + let op = this.read_scalar(op)?.to_i32()?; + let val = this.read_target_usize(val)?; + let uaddr = this.read_target_usize(uaddr)?; + let uaddr2 = this.read_pointer(uaddr2)?; + + let wait = this.eval_libc_i32("UMTX_OP_WAIT"); + let wait_uint = this.eval_libc_i32("UMTX_OP_WAIT_UINT"); + let wait_uint_private = this.eval_libc_i32("UMTX_OP_WAIT_UINT_PRIVATE"); + + let wake = this.eval_libc_i32("UMTX_OP_WAKE"); + let wake_private = this.eval_libc_i32("UMTX_OP_WAKE_PRIVATE"); + + let timespec_layout = this.libc_ty_layout("timespec"); + let umtx_time_layout = this.libc_ty_layout("_umtx_time"); + assert!( + timespec_layout.size != umtx_time_layout.size, + "`struct timespec` and `struct _umtx_time` should have different sizes." + ); + + match op { + // UMTX_OP_WAIT_UINT and UMTX_OP_WAIT_UINT_PRIVATE only differ in whether they work across + // processes or not. For Miri, we can treat them the same. + op if op == wait || op == wait_uint || op == wait_uint_private => { + let obj_layout = + if op == wait { this.machine.layouts.isize } else { this.machine.layouts.u32 }; + let obj = this.ptr_to_mplace(obj, obj_layout); + + // Read the Linux futex wait implementation in Miri to understand why this fence is needed. + this.atomic_fence(AtomicFenceOrd::SeqCst)?; + let obj_val = this + .read_scalar_atomic(&obj, AtomicReadOrd::Acquire)? + .to_bits(obj_layout.size)?; // isize and u32 can have different sizes + + if obj_val == u128::from(val) { + // This cannot fail since we already did an atomic acquire read on that pointer. + // Acquire reads are only allowed on mutable memory. + let futex_ref = this + .get_sync_or_init(obj.ptr(), |_| FreeBsdFutex { futex: Default::default() }) + .unwrap() + .futex + .clone(); + + // From the manual: + // The timeout is specified by passing either the address of `struct timespec`, or its + // extended variant, `struct _umtx_time`, as the `uaddr2` argument of _umtx_op(). + // They are distinguished by the `uaddr` value, which must be equal + // to the size of the structure pointed to by `uaddr2`, casted to uintptr_t. + let timeout = if this.ptr_is_null(uaddr2)? { + // no timeout parameter + None + } else { + if uaddr == umtx_time_layout.size.bytes() { + // `uaddr2` points to a `struct _umtx_time`. + let umtx_time_place = this.ptr_to_mplace(uaddr2, umtx_time_layout); + + let umtx_time = match this.read_umtx_time(&umtx_time_place)? { + Some(ut) => ut, + None => { + return this + .set_last_error_and_return(LibcError("EINVAL"), dest); + } + }; + + let anchor = if umtx_time.abs_time { + TimeoutAnchor::Absolute + } else { + TimeoutAnchor::Relative + }; + + Some((umtx_time.timeout_clock, anchor, umtx_time.timeout)) + } else if uaddr == timespec_layout.size.bytes() { + // RealTime clock can't be used in isolation mode. + this.check_no_isolation("`_umtx_op` with `timespec` timeout")?; + + // `uaddr2` points to a `struct timespec`. + let timespec = this.ptr_to_mplace(uaddr2, timespec_layout); + let duration = match this.read_timespec(×pec)? { + Some(duration) => duration, + None => { + return this + .set_last_error_and_return(LibcError("EINVAL"), dest); + } + }; + + // FreeBSD does not seem to document which clock is used when the timeout + // is passed as a `struct timespec*`. Based on discussions online and the source + // code (umtx_copyin_umtx_time() in kern_umtx.c), it seems to default to CLOCK_REALTIME, + // so that's what we also do. + // Discussion in golang: https://github.com/golang/go/issues/17168#issuecomment-250235271 + Some((TimeoutClock::RealTime, TimeoutAnchor::Relative, duration)) + } else { + return this.set_last_error_and_return(LibcError("EINVAL"), dest); + } + }; + + let dest = dest.clone(); + this.futex_wait( + futex_ref, + u32::MAX, // we set the bitset to include all bits + timeout, + callback!( + @capture<'tcx> { + dest: MPlaceTy<'tcx>, + } + |ecx, unblock: UnblockKind| match unblock { + UnblockKind::Ready => { + // From the manual: + // If successful, all requests, except UMTX_SHM_CREAT and UMTX_SHM_LOOKUP + // sub-requests of the UMTX_OP_SHM request, will return zero. + ecx.write_int(0, &dest) + } + UnblockKind::TimedOut => { + ecx.set_last_error_and_return(LibcError("ETIMEDOUT"), &dest) + } + } + ), + ); + interp_ok(()) + } else { + // The manual doesn’t specify what should happen if the futex value doesn’t match the expected one. + // On FreeBSD 14.2, testing shows that WAIT operations return 0 even when the value is incorrect. + this.write_int(0, dest)?; + interp_ok(()) + } + } + // UMTX_OP_WAKE and UMTX_OP_WAKE_PRIVATE only differ in whether they work across + // processes or not. For Miri, we can treat them the same. + op if op == wake || op == wake_private => { + let Some(futex_ref) = + this.get_sync_or_init(obj, |_| FreeBsdFutex { futex: Default::default() }) + else { + // From Linux implemenation: + // No AllocId, or no live allocation at that AllocId. + // Return an error code. (That seems nicer than silently doing something non-intuitive.) + // This means that if an address gets reused by a new allocation, + // we'll use an independent futex queue for this... that seems acceptable. + return this.set_last_error_and_return(LibcError("EFAULT"), dest); + }; + let futex_ref = futex_ref.futex.clone(); + + // Saturating cast for when usize is smaller than u64. + let count = usize::try_from(val).unwrap_or(usize::MAX); + + // Read the Linux futex wake implementation in Miri to understand why this fence is needed. + this.atomic_fence(AtomicFenceOrd::SeqCst)?; + + // `_umtx_op` doesn't return the amount of woken threads. + let _woken = this.futex_wake( + &futex_ref, + u32::MAX, // we set the bitset to include all bits + count, + )?; + + // From the manual: + // If successful, all requests, except UMTX_SHM_CREAT and UMTX_SHM_LOOKUP + // sub-requests of the UMTX_OP_SHM request, will return zero. + this.write_int(0, dest)?; + interp_ok(()) + } + op => { + throw_unsup_format!("Miri does not support `_umtx_op` syscall with op={}", op) + } + } + } + + /// Parses a `_umtx_time` struct. + /// Returns `None` if the underlying `timespec` struct is invalid. + fn read_umtx_time(&mut self, ut: &MPlaceTy<'tcx>) -> InterpResult<'tcx, Option> { + let this = self.eval_context_mut(); + // Only flag allowed is UMTX_ABSTIME. + let abs_time = this.eval_libc_u32("UMTX_ABSTIME"); + + let timespec_place = this.project_field(ut, 0)?; + // Inner `timespec` must still be valid. + let duration = match this.read_timespec(×pec_place)? { + Some(dur) => dur, + None => return interp_ok(None), + }; + + let flags_place = this.project_field(ut, 1)?; + let flags = this.read_scalar(&flags_place)?.to_u32()?; + let abs_time_flag = flags == abs_time; + + let clock_id_place = this.project_field(ut, 2)?; + let clock_id = this.read_scalar(&clock_id_place)?.to_i32()?; + let timeout_clock = this.translate_umtx_time_clock_id(clock_id)?; + + interp_ok(Some(UmtxTime { timeout: duration, abs_time: abs_time_flag, timeout_clock })) + } + + /// Translate raw FreeBSD clockid to a Miri TimeoutClock. + /// FIXME: share this code with the pthread and clock_gettime shims. + fn translate_umtx_time_clock_id(&mut self, raw_id: i32) -> InterpResult<'tcx, TimeoutClock> { + let this = self.eval_context_mut(); + + let timeout = if raw_id == this.eval_libc_i32("CLOCK_REALTIME") { + // RealTime clock can't be used in isolation mode. + this.check_no_isolation("`_umtx_op` with `CLOCK_REALTIME` timeout")?; + TimeoutClock::RealTime + } else if raw_id == this.eval_libc_i32("CLOCK_MONOTONIC") { + TimeoutClock::Monotonic + } else { + throw_unsup_format!("unsupported clock id {raw_id}"); + }; + interp_ok(timeout) + } +} diff --git a/src/tools/miri/src/shims/unix/fs.rs b/src/tools/miri/src/shims/unix/fs.rs index f8e0c638c90d..fc0f57694a71 100644 --- a/src/tools/miri/src/shims/unix/fs.rs +++ b/src/tools/miri/src/shims/unix/fs.rs @@ -2,10 +2,9 @@ use std::borrow::Cow; use std::fs::{ - DirBuilder, File, FileType, Metadata, OpenOptions, ReadDir, read_dir, remove_dir, remove_file, - rename, + DirBuilder, File, FileType, OpenOptions, ReadDir, read_dir, remove_dir, remove_file, rename, }; -use std::io::{self, ErrorKind, IsTerminal, Read, Seek, SeekFrom, Write}; +use std::io::{self, ErrorKind, Read, Seek, SeekFrom, Write}; use std::path::{Path, PathBuf}; use std::time::SystemTime; @@ -14,98 +13,11 @@ use rustc_data_structures::fx::FxHashMap; use self::shims::time::system_time_to_duration; use crate::helpers::check_min_vararg_count; -use crate::shims::files::{EvalContextExt as _, FileDescription, FileDescriptionRef}; +use crate::shims::files::FileHandle; use crate::shims::os_str::bytes_to_os_str; use crate::shims::unix::fd::{FlockOp, UnixFileDescription}; use crate::*; -#[derive(Debug)] -struct FileHandle { - file: File, - writable: bool, -} - -impl FileDescription for FileHandle { - fn name(&self) -> &'static str { - "file" - } - - fn read<'tcx>( - self: FileDescriptionRef, - communicate_allowed: bool, - ptr: Pointer, - len: usize, - ecx: &mut MiriInterpCx<'tcx>, - finish: DynMachineCallback<'tcx, Result>, - ) -> InterpResult<'tcx> { - assert!(communicate_allowed, "isolation should have prevented even opening a file"); - - let result = ecx.read_from_host(&self.file, len, ptr)?; - finish.call(ecx, result) - } - - fn write<'tcx>( - self: FileDescriptionRef, - communicate_allowed: bool, - ptr: Pointer, - len: usize, - ecx: &mut MiriInterpCx<'tcx>, - finish: DynMachineCallback<'tcx, Result>, - ) -> InterpResult<'tcx> { - assert!(communicate_allowed, "isolation should have prevented even opening a file"); - - let result = ecx.write_to_host(&self.file, len, ptr)?; - finish.call(ecx, result) - } - - fn seek<'tcx>( - &self, - communicate_allowed: bool, - offset: SeekFrom, - ) -> InterpResult<'tcx, io::Result> { - assert!(communicate_allowed, "isolation should have prevented even opening a file"); - interp_ok((&mut &self.file).seek(offset)) - } - - fn close<'tcx>( - self, - communicate_allowed: bool, - _ecx: &mut MiriInterpCx<'tcx>, - ) -> InterpResult<'tcx, io::Result<()>> { - assert!(communicate_allowed, "isolation should have prevented even opening a file"); - // We sync the file if it was opened in a mode different than read-only. - if self.writable { - // `File::sync_all` does the checks that are done when closing a file. We do this to - // to handle possible errors correctly. - let result = self.file.sync_all(); - // Now we actually close the file and return the result. - drop(self.file); - interp_ok(result) - } else { - // We drop the file, this closes it but ignores any errors - // produced when closing it. This is done because - // `File::sync_all` cannot be done over files like - // `/dev/urandom` which are read-only. Check - // https://github.com/rust-lang/miri/issues/999#issuecomment-568920439 - // for a deeper discussion. - drop(self.file); - interp_ok(Ok(())) - } - } - - fn metadata<'tcx>(&self) -> InterpResult<'tcx, io::Result> { - interp_ok(self.file.metadata()) - } - - fn is_tty(&self, communicate_allowed: bool) -> bool { - communicate_allowed && self.file.is_terminal() - } - - fn as_unix(&self) -> &dyn UnixFileDescription { - self - } -} - impl UnixFileDescription for FileHandle { fn pread<'tcx>( &self, diff --git a/src/tools/miri/src/shims/unix/linux_like/epoll.rs b/src/tools/miri/src/shims/unix/linux_like/epoll.rs index de8bcb54aef5..b489595b4cd0 100644 --- a/src/tools/miri/src/shims/unix/linux_like/epoll.rs +++ b/src/tools/miri/src/shims/unix/linux_like/epoll.rs @@ -153,7 +153,7 @@ impl FileDescription for Epoll { interp_ok(Ok(())) } - fn as_unix(&self) -> &dyn UnixFileDescription { + fn as_unix<'tcx>(&self, _ecx: &MiriInterpCx<'tcx>) -> &dyn UnixFileDescription { self } } @@ -590,7 +590,7 @@ fn check_and_update_one_event_interest<'tcx>( ecx: &MiriInterpCx<'tcx>, ) -> InterpResult<'tcx, bool> { // Get the bitmask of ready events for a file description. - let ready_events_bitmask = fd_ref.as_unix().get_epoll_ready_events()?.get_event_bitmask(ecx); + let ready_events_bitmask = fd_ref.as_unix(ecx).get_epoll_ready_events()?.get_event_bitmask(ecx); let epoll_event_interest = interest.borrow(); let epfd = epoll_event_interest.weak_epfd.upgrade().unwrap(); // This checks if any of the events specified in epoll_event_interest.events diff --git a/src/tools/miri/src/shims/unix/linux_like/eventfd.rs b/src/tools/miri/src/shims/unix/linux_like/eventfd.rs index 936d436bd82d..ee7deb8d3830 100644 --- a/src/tools/miri/src/shims/unix/linux_like/eventfd.rs +++ b/src/tools/miri/src/shims/unix/linux_like/eventfd.rs @@ -100,7 +100,7 @@ impl FileDescription for EventFd { eventfd_write(buf_place, self, ecx, finish) } - fn as_unix(&self) -> &dyn UnixFileDescription { + fn as_unix<'tcx>(&self, _ecx: &MiriInterpCx<'tcx>) -> &dyn UnixFileDescription { self } } diff --git a/src/tools/miri/src/shims/unix/macos/foreign_items.rs b/src/tools/miri/src/shims/unix/macos/foreign_items.rs index 918fd8dd52df..5046e9650822 100644 --- a/src/tools/miri/src/shims/unix/macos/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/macos/foreign_items.rs @@ -222,7 +222,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(res, dest)?; } - // Futex primitives + // Synchronization primitives "os_sync_wait_on_address" => { let [addr_op, value_op, size_op, flags_op] = this.check_shim(abi, Conv::C, link_name, args)?; @@ -273,7 +273,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { addr_op, size_op, flags_op, /* all */ true, dest, )?; } - "os_unfair_lock_lock" => { let [lock_op] = this.check_shim(abi, Conv::C, link_name, args)?; this.os_unfair_lock_lock(lock_op)?; diff --git a/src/tools/miri/src/shims/unix/unnamed_socket.rs b/src/tools/miri/src/shims/unix/unnamed_socket.rs index e183bfdf0e13..135d8f6bee7e 100644 --- a/src/tools/miri/src/shims/unix/unnamed_socket.rs +++ b/src/tools/miri/src/shims/unix/unnamed_socket.rs @@ -107,7 +107,7 @@ impl FileDescription for AnonSocket { anonsocket_write(self, ptr, len, ecx, finish) } - fn as_unix(&self) -> &dyn UnixFileDescription { + fn as_unix<'tcx>(&self, _ecx: &MiriInterpCx<'tcx>) -> &dyn UnixFileDescription { self } } diff --git a/src/tools/miri/src/shims/windows/foreign_items.rs b/src/tools/miri/src/shims/windows/foreign_items.rs index fae6170a9e72..8dcadbed130c 100644 --- a/src/tools/miri/src/shims/windows/foreign_items.rs +++ b/src/tools/miri/src/shims/windows/foreign_items.rs @@ -9,14 +9,9 @@ use rustc_target::callconv::{Conv, FnAbi}; use self::shims::windows::handle::{Handle, PseudoHandle}; use crate::shims::os_str::bytes_to_os_str; -use crate::shims::windows::handle::HandleError; use crate::shims::windows::*; use crate::*; -// The NTSTATUS STATUS_INVALID_HANDLE (0xC0000008) encoded as a HRESULT by setting the N bit. -// (https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/0642cb2f-2075-4469-918c-4441e69c548a) -const STATUS_INVALID_HANDLE: u32 = 0xD0000008; - pub fn is_dyn_sym(name: &str) -> bool { // std does dynamic detection for these symbols matches!( @@ -26,57 +21,107 @@ pub fn is_dyn_sym(name: &str) -> bool { } #[cfg(windows)] -fn win_absolute<'tcx>(path: &Path) -> InterpResult<'tcx, io::Result> { +fn win_get_full_path_name<'tcx>(path: &Path) -> InterpResult<'tcx, io::Result> { // We are on Windows so we can simply let the host do this. interp_ok(path::absolute(path)) } #[cfg(unix)] #[expect(clippy::get_first, clippy::arithmetic_side_effects)] -fn win_absolute<'tcx>(path: &Path) -> InterpResult<'tcx, io::Result> { - // We are on Unix, so we need to implement parts of the logic ourselves. +fn win_get_full_path_name<'tcx>(path: &Path) -> InterpResult<'tcx, io::Result> { + use std::sync::LazyLock; + + use rustc_data_structures::fx::FxHashSet; + + // We are on Unix, so we need to implement parts of the logic ourselves. `path` will use `/` + // separators, and the result should also use `/`. + // See for more + // information about Windows paths. + // This does not handle all corner cases correctly, see + // for more cursed + // examples. let bytes = path.as_os_str().as_encoded_bytes(); - // If it starts with `//` (these were backslashes but are already converted) - // then this is a magic special path, we just leave it unchanged. - if bytes.get(0).copied() == Some(b'/') && bytes.get(1).copied() == Some(b'/') { + // If it starts with `//./` or `//?/` then this is a magic special path, we just leave it + // unchanged. + if bytes.get(0).copied() == Some(b'/') + && bytes.get(1).copied() == Some(b'/') + && matches!(bytes.get(2), Some(b'.' | b'?')) + && bytes.get(3).copied() == Some(b'/') + { return interp_ok(Ok(path.into())); }; - // Special treatment for Windows' magic filenames: they are treated as being relative to `\\.\`. - let magic_filenames = &[ - "CON", "PRN", "AUX", "NUL", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", - "COM9", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9", - ]; - if magic_filenames.iter().any(|m| m.as_bytes() == bytes) { - let mut result: Vec = br"//./".into(); + let is_unc = bytes.starts_with(b"//"); + // Special treatment for Windows' magic filenames: they are treated as being relative to `//./`. + static MAGIC_FILENAMES: LazyLock> = LazyLock::new(|| { + FxHashSet::from_iter([ + "CON", "PRN", "AUX", "NUL", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", + "COM8", "COM9", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9", + ]) + }); + if str::from_utf8(bytes).is_ok_and(|s| MAGIC_FILENAMES.contains(&*s.to_ascii_uppercase())) { + let mut result: Vec = b"//./".into(); result.extend(bytes); return interp_ok(Ok(bytes_to_os_str(&result)?.into())); } // Otherwise we try to do something kind of close to what Windows does, but this is probably not - // right in all cases. We iterate over the components between `/`, and remove trailing `.`, - // except that trailing `..` remain unchanged. - let mut result = vec![]; + // right in all cases. + let mut result: Vec<&[u8]> = vec![]; // will be a vector of components, joined by `/`. let mut bytes = bytes; // the remaining bytes to process - loop { - let len = bytes.iter().position(|&b| b == b'/').unwrap_or(bytes.len()); - let mut component = &bytes[..len]; - if len >= 2 && component[len - 1] == b'.' && component[len - 2] != b'.' { - // Strip trailing `.` + let mut stop = false; + while !stop { + // Find next component, and advance `bytes`. + let mut component = match bytes.iter().position(|&b| b == b'/') { + Some(pos) => { + let (component, tail) = bytes.split_at(pos); + bytes = &tail[1..]; // remove the `/`. + component + } + None => { + // There's no more `/`. + stop = true; + let component = bytes; + bytes = &[]; + component + } + }; + // `NUL` and only `NUL` also gets changed to be relative to `//./` later in the path. + // (This changed with Windows 11; previously, all magic filenames behaved like this.) + // Also, this does not apply to UNC paths. + if !is_unc && component.eq_ignore_ascii_case(b"NUL") { + let mut result: Vec = b"//./".into(); + result.extend(component); + return interp_ok(Ok(bytes_to_os_str(&result)?.into())); + } + // Deal with `..` -- Windows handles this entirely syntactically. + if component == b".." { + // Remove previous component, unless we are at the "root" already, then just ignore the `..`. + let is_root = { + // Paths like `/C:`. + result.len() == 2 && matches!(result[0], []) && matches!(result[1], [_, b':']) + } || { + // Paths like `//server/share` + result.len() == 4 && matches!(result[0], []) && matches!(result[1], []) + }; + if !is_root { + result.pop(); + } + continue; + } + // Preserve this component. + // Strip trailing `.`, but preserve trailing `..`. But not for UNC paths! + let len = component.len(); + if !is_unc && len >= 2 && component[len - 1] == b'.' && component[len - 2] != b'.' { component = &component[..len - 1]; } // Add this component to output. - result.extend(component); - // Prepare next iteration. - if len < bytes.len() { - // There's a component after this; add `/` and process remaining bytes. - result.push(b'/'); - bytes = &bytes[len + 1..]; - continue; - } else { - // This was the last component and it did not have a trailing `/`. - break; - } + result.push(component); } - // Let the host `absolute` function do working-dir handling + // Drive letters must be followed by a `/`. + if result.len() == 2 && matches!(result[0], []) && matches!(result[1], [_, b':']) { + result.push(&[]); + } + // Let the host `absolute` function do working-dir handling. + let result = result.join(&b'/'); interp_ok(path::absolute(bytes_to_os_str(&result)?)) } @@ -231,7 +276,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } let filename = this.read_path_from_wide_str(filename)?; - let result = match win_absolute(&filename)? { + let result = match win_get_full_path_name(&filename)? { Err(err) => { this.set_last_error(err)?; Scalar::from_u32(0) // return zero upon failure @@ -246,6 +291,32 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { }; this.write_scalar(result, dest)?; } + "CreateFileW" => { + let [ + file_name, + desired_access, + share_mode, + security_attributes, + creation_disposition, + flags_and_attributes, + template_file, + ] = this.check_shim(abi, sys_conv, link_name, args)?; + let handle = this.CreateFileW( + file_name, + desired_access, + share_mode, + security_attributes, + creation_disposition, + flags_and_attributes, + template_file, + )?; + this.write_scalar(handle.to_scalar(this), dest)?; + } + "GetFileInformationByHandle" => { + let [handle, info] = this.check_shim(abi, sys_conv, link_name, args)?; + let res = this.GetFileInformationByHandle(handle, info)?; + this.write_scalar(res, dest)?; + } // Allocation "HeapAlloc" => { @@ -325,6 +396,25 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let last_error = this.get_last_error()?; this.write_scalar(last_error, dest)?; } + "RtlNtStatusToDosError" => { + let [status] = this.check_shim(abi, sys_conv, link_name, args)?; + let status = this.read_scalar(status)?.to_u32()?; + let err = match status { + // STATUS_MEDIA_WRITE_PROTECTED => ERROR_WRITE_PROTECT + 0xC00000A2 => 19, + // STATUS_FILE_INVALID => ERROR_FILE_INVALID + 0xC0000098 => 1006, + // STATUS_DISK_FULL => ERROR_DISK_FULL + 0xC000007F => 112, + // STATUS_IO_DEVICE_ERROR => ERROR_IO_DEVICE + 0xC0000185 => 1117, + // STATUS_ACCESS_DENIED => ERROR_ACCESS_DENIED + 0xC0000022 => 5, + // Anything without an error code => ERROR_MR_MID_NOT_FOUND + _ => 317, + }; + this.write_scalar(Scalar::from_i32(err), dest)?; + } // Querying system information "GetSystemInfo" => { @@ -498,52 +588,37 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "SetThreadDescription" => { let [handle, name] = this.check_shim(abi, sys_conv, link_name, args)?; - let handle = this.read_scalar(handle)?; + let handle = this.read_handle(handle, "SetThreadDescription")?; let name = this.read_wide_str(this.read_pointer(name)?)?; - let thread = match Handle::try_from_scalar(handle, this)? { - Ok(Handle::Thread(thread)) => Ok(thread), - Ok(Handle::Pseudo(PseudoHandle::CurrentThread)) => Ok(this.active_thread()), - Ok(_) | Err(HandleError::InvalidHandle) => - this.invalid_handle("SetThreadDescription")?, - Err(HandleError::ThreadNotFound(e)) => Err(e), + let thread = match handle { + Handle::Thread(thread) => thread, + Handle::Pseudo(PseudoHandle::CurrentThread) => this.active_thread(), + _ => this.invalid_handle("SetThreadDescription")?, }; - let res = match thread { - Ok(thread) => { - // FIXME: use non-lossy conversion - this.set_thread_name(thread, String::from_utf16_lossy(&name).into_bytes()); - Scalar::from_u32(0) - } - Err(_) => Scalar::from_u32(STATUS_INVALID_HANDLE), - }; - - this.write_scalar(res, dest)?; + // FIXME: use non-lossy conversion + this.set_thread_name(thread, String::from_utf16_lossy(&name).into_bytes()); + this.write_scalar(Scalar::from_u32(0), dest)?; } "GetThreadDescription" => { let [handle, name_ptr] = this.check_shim(abi, sys_conv, link_name, args)?; - let handle = this.read_scalar(handle)?; + let handle = this.read_handle(handle, "GetThreadDescription")?; let name_ptr = this.deref_pointer_as(name_ptr, this.machine.layouts.mut_raw_ptr)?; // the pointer where we should store the ptr to the name - let thread = match Handle::try_from_scalar(handle, this)? { - Ok(Handle::Thread(thread)) => Ok(thread), - Ok(Handle::Pseudo(PseudoHandle::CurrentThread)) => Ok(this.active_thread()), - Ok(_) | Err(HandleError::InvalidHandle) => - this.invalid_handle("GetThreadDescription")?, - Err(HandleError::ThreadNotFound(e)) => Err(e), - }; - let (name, res) = match thread { - Ok(thread) => { - // Looks like the default thread name is empty. - let name = this.get_thread_name(thread).unwrap_or(b"").to_owned(); - let name = this.alloc_os_str_as_wide_str( - bytes_to_os_str(&name)?, - MiriMemoryKind::WinLocal.into(), - )?; - (Scalar::from_maybe_pointer(name, this), Scalar::from_u32(0)) - } - Err(_) => (Scalar::null_ptr(this), Scalar::from_u32(STATUS_INVALID_HANDLE)), + let thread = match handle { + Handle::Thread(thread) => thread, + Handle::Pseudo(PseudoHandle::CurrentThread) => this.active_thread(), + _ => this.invalid_handle("GetThreadDescription")?, }; + // Looks like the default thread name is empty. + let name = this.get_thread_name(thread).unwrap_or(b"").to_owned(); + let name = this.alloc_os_str_as_wide_str( + bytes_to_os_str(&name)?, + MiriMemoryKind::WinLocal.into(), + )?; + let name = Scalar::from_maybe_pointer(name, this); + let res = Scalar::from_u32(0); this.write_scalar(name, &name_ptr)?; this.write_scalar(res, dest)?; @@ -638,11 +713,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let [handle, filename, size] = this.check_shim(abi, sys_conv, link_name, args)?; this.check_no_isolation("`GetModuleFileNameW`")?; - let handle = this.read_target_usize(handle)?; + let handle = this.read_handle(handle, "GetModuleFileNameW")?; let filename = this.read_pointer(filename)?; let size = this.read_scalar(size)?.to_u32()?; - if handle != 0 { + if handle != Handle::Null { throw_unsup_format!("`GetModuleFileNameW` only supports the NULL handle"); } diff --git a/src/tools/miri/src/shims/windows/fs.rs b/src/tools/miri/src/shims/windows/fs.rs new file mode 100644 index 000000000000..32bab5489693 --- /dev/null +++ b/src/tools/miri/src/shims/windows/fs.rs @@ -0,0 +1,402 @@ +use std::fs::{Metadata, OpenOptions}; +use std::io; +use std::path::PathBuf; +use std::time::SystemTime; + +use bitflags::bitflags; + +use crate::shims::files::{FileDescription, FileHandle}; +use crate::shims::windows::handle::{EvalContextExt as _, Handle}; +use crate::*; + +#[derive(Debug)] +pub struct DirHandle { + pub(crate) path: PathBuf, +} + +impl FileDescription for DirHandle { + fn name(&self) -> &'static str { + "directory" + } + + fn metadata<'tcx>(&self) -> InterpResult<'tcx, io::Result> { + interp_ok(self.path.metadata()) + } + + fn close<'tcx>( + self, + _communicate_allowed: bool, + _ecx: &mut MiriInterpCx<'tcx>, + ) -> InterpResult<'tcx, io::Result<()>> { + interp_ok(Ok(())) + } +} + +/// Windows supports handles without any read/write/delete permissions - these handles can get +/// metadata, but little else. We represent that by storing the metadata from the time the handle +/// was opened. +#[derive(Debug)] +pub struct MetadataHandle { + pub(crate) meta: Metadata, +} + +impl FileDescription for MetadataHandle { + fn name(&self) -> &'static str { + "metadata-only" + } + + fn metadata<'tcx>(&self) -> InterpResult<'tcx, io::Result> { + interp_ok(Ok(self.meta.clone())) + } + + fn close<'tcx>( + self, + _communicate_allowed: bool, + _ecx: &mut MiriInterpCx<'tcx>, + ) -> InterpResult<'tcx, io::Result<()>> { + interp_ok(Ok(())) + } +} + +#[derive(Copy, Clone, Debug, PartialEq)] +enum CreationDisposition { + CreateAlways, + CreateNew, + OpenAlways, + OpenExisting, + TruncateExisting, +} + +impl CreationDisposition { + fn new<'tcx>( + value: u32, + ecx: &mut MiriInterpCx<'tcx>, + ) -> InterpResult<'tcx, CreationDisposition> { + let create_always = ecx.eval_windows_u32("c", "CREATE_ALWAYS"); + let create_new = ecx.eval_windows_u32("c", "CREATE_NEW"); + let open_always = ecx.eval_windows_u32("c", "OPEN_ALWAYS"); + let open_existing = ecx.eval_windows_u32("c", "OPEN_EXISTING"); + let truncate_existing = ecx.eval_windows_u32("c", "TRUNCATE_EXISTING"); + + let out = if value == create_always { + CreationDisposition::CreateAlways + } else if value == create_new { + CreationDisposition::CreateNew + } else if value == open_always { + CreationDisposition::OpenAlways + } else if value == open_existing { + CreationDisposition::OpenExisting + } else if value == truncate_existing { + CreationDisposition::TruncateExisting + } else { + throw_unsup_format!("CreateFileW: Unsupported creation disposition: {value}"); + }; + interp_ok(out) + } +} + +bitflags! { + #[derive(PartialEq)] + struct FileAttributes: u32 { + const ZERO = 0; + const NORMAL = 1 << 0; + /// This must be passed to allow getting directory handles. If not passed, we error on trying + /// to open directories + const BACKUP_SEMANTICS = 1 << 1; + /// Open a reparse point as a regular file - this is basically similar to 'readlink' in Unix + /// terminology. A reparse point is a file with custom logic when navigated to, of which + /// a symlink is one specific example. + const OPEN_REPARSE = 1 << 2; + } +} + +impl FileAttributes { + fn new<'tcx>( + mut value: u32, + ecx: &mut MiriInterpCx<'tcx>, + ) -> InterpResult<'tcx, FileAttributes> { + let file_attribute_normal = ecx.eval_windows_u32("c", "FILE_ATTRIBUTE_NORMAL"); + let file_flag_backup_semantics = ecx.eval_windows_u32("c", "FILE_FLAG_BACKUP_SEMANTICS"); + let file_flag_open_reparse_point = + ecx.eval_windows_u32("c", "FILE_FLAG_OPEN_REPARSE_POINT"); + + let mut out = FileAttributes::ZERO; + if value & file_flag_backup_semantics != 0 { + value &= !file_flag_backup_semantics; + out |= FileAttributes::BACKUP_SEMANTICS; + } + if value & file_flag_open_reparse_point != 0 { + value &= !file_flag_open_reparse_point; + out |= FileAttributes::OPEN_REPARSE; + } + if value & file_attribute_normal != 0 { + value &= !file_attribute_normal; + out |= FileAttributes::NORMAL; + } + + if value != 0 { + throw_unsup_format!("CreateFileW: Unsupported flags_and_attributes: {value}"); + } + + if out == FileAttributes::ZERO { + // NORMAL is equivalent to 0. Avoid needing to check both cases by unifying the two. + out = FileAttributes::NORMAL; + } + interp_ok(out) + } +} + +impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} +#[allow(non_snake_case)] +pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { + fn CreateFileW( + &mut self, + file_name: &OpTy<'tcx>, // LPCWSTR + desired_access: &OpTy<'tcx>, // DWORD + share_mode: &OpTy<'tcx>, // DWORD + security_attributes: &OpTy<'tcx>, // LPSECURITY_ATTRIBUTES + creation_disposition: &OpTy<'tcx>, // DWORD + flags_and_attributes: &OpTy<'tcx>, // DWORD + template_file: &OpTy<'tcx>, // HANDLE + ) -> InterpResult<'tcx, Handle> { + // ^ Returns HANDLE + use CreationDisposition::*; + + let this = self.eval_context_mut(); + this.assert_target_os("windows", "CreateFileW"); + this.check_no_isolation("`CreateFileW`")?; + + // This function appears to always set the error to 0. This is important for some flag + // combinations, which may set error code on success. + this.set_last_error(IoError::Raw(Scalar::from_i32(0)))?; + + let file_name = this.read_path_from_wide_str(this.read_pointer(file_name)?)?; + let mut desired_access = this.read_scalar(desired_access)?.to_u32()?; + let share_mode = this.read_scalar(share_mode)?.to_u32()?; + let security_attributes = this.read_pointer(security_attributes)?; + let creation_disposition = this.read_scalar(creation_disposition)?.to_u32()?; + let flags_and_attributes = this.read_scalar(flags_and_attributes)?.to_u32()?; + let template_file = this.read_target_usize(template_file)?; + + let generic_read = this.eval_windows_u32("c", "GENERIC_READ"); + let generic_write = this.eval_windows_u32("c", "GENERIC_WRITE"); + + let file_share_delete = this.eval_windows_u32("c", "FILE_SHARE_DELETE"); + let file_share_read = this.eval_windows_u32("c", "FILE_SHARE_READ"); + let file_share_write = this.eval_windows_u32("c", "FILE_SHARE_WRITE"); + + let creation_disposition = CreationDisposition::new(creation_disposition, this)?; + let attributes = FileAttributes::new(flags_and_attributes, this)?; + + if share_mode != (file_share_delete | file_share_read | file_share_write) { + throw_unsup_format!("CreateFileW: Unsupported share mode: {share_mode}"); + } + if !this.ptr_is_null(security_attributes)? { + throw_unsup_format!("CreateFileW: Security attributes are not supported"); + } + + if attributes.contains(FileAttributes::OPEN_REPARSE) && creation_disposition == CreateAlways + { + throw_machine_stop!(TerminationInfo::Abort("Invalid CreateFileW argument combination: FILE_FLAG_OPEN_REPARSE_POINT with CREATE_ALWAYS".to_string())); + } + + if template_file != 0 { + throw_unsup_format!("CreateFileW: Template files are not supported"); + } + + // We need to know if the file is a directory to correctly open directory handles. + // This is racy, but currently the stdlib doesn't appear to offer a better solution. + let is_dir = file_name.is_dir(); + + // BACKUP_SEMANTICS is how Windows calls the act of opening a directory handle. + if !attributes.contains(FileAttributes::BACKUP_SEMANTICS) && is_dir { + this.set_last_error(IoError::WindowsError("ERROR_ACCESS_DENIED"))?; + return interp_ok(Handle::Invalid); + } + + let desired_read = desired_access & generic_read != 0; + let desired_write = desired_access & generic_write != 0; + + let mut options = OpenOptions::new(); + if desired_read { + desired_access &= !generic_read; + options.read(true); + } + if desired_write { + desired_access &= !generic_write; + options.write(true); + } + + if desired_access != 0 { + throw_unsup_format!( + "CreateFileW: Unsupported bits set for access mode: {desired_access:#x}" + ); + } + + // Per the documentation: + // If the specified file exists and is writable, the function truncates the file, + // the function succeeds, and last-error code is set to ERROR_ALREADY_EXISTS. + // If the specified file does not exist and is a valid path, a new file is created, + // the function succeeds, and the last-error code is set to zero. + // https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew + // + // This is racy, but there doesn't appear to be an std API that both succeeds if a + // file exists but tells us it isn't new. Either we accept racing one way or another, + // or we use an iffy heuristic like file creation time. This implementation prefers + // to fail in the direction of erroring more often. + if let CreateAlways | OpenAlways = creation_disposition + && file_name.exists() + { + this.set_last_error(IoError::WindowsError("ERROR_ALREADY_EXISTS"))?; + } + + let handle = if is_dir { + // Open this as a directory. + let fd_num = this.machine.fds.insert_new(DirHandle { path: file_name }); + Ok(Handle::File(fd_num)) + } else if creation_disposition == OpenExisting && !(desired_read || desired_write) { + // Windows supports handles with no permissions. These allow things such as reading + // metadata, but not file content. + file_name.metadata().map(|meta| { + let fd_num = this.machine.fds.insert_new(MetadataHandle { meta }); + Handle::File(fd_num) + }) + } else { + // Open this as a standard file. + match creation_disposition { + CreateAlways | OpenAlways => { + options.create(true); + if creation_disposition == CreateAlways { + options.truncate(true); + } + } + CreateNew => { + options.create_new(true); + // Per `create_new` documentation: + // The file must be opened with write or append access in order to create a new file. + // https://doc.rust-lang.org/std/fs/struct.OpenOptions.html#method.create_new + if !desired_write { + options.append(true); + } + } + OpenExisting => {} // Default options + TruncateExisting => { + options.truncate(true); + } + } + + options.open(file_name).map(|file| { + let fd_num = + this.machine.fds.insert_new(FileHandle { file, writable: desired_write }); + Handle::File(fd_num) + }) + }; + + match handle { + Ok(handle) => interp_ok(handle), + Err(e) => { + this.set_last_error(e)?; + interp_ok(Handle::Invalid) + } + } + } + + fn GetFileInformationByHandle( + &mut self, + file: &OpTy<'tcx>, // HANDLE + file_information: &OpTy<'tcx>, // LPBY_HANDLE_FILE_INFORMATION + ) -> InterpResult<'tcx, Scalar> { + // ^ Returns BOOL (i32 on Windows) + let this = self.eval_context_mut(); + this.assert_target_os("windows", "GetFileInformationByHandle"); + this.check_no_isolation("`GetFileInformationByHandle`")?; + + let file = this.read_handle(file, "GetFileInformationByHandle")?; + let file_information = this.deref_pointer_as( + file_information, + this.windows_ty_layout("BY_HANDLE_FILE_INFORMATION"), + )?; + + let fd_num = if let Handle::File(fd_num) = file { + fd_num + } else { + this.invalid_handle("GetFileInformationByHandle")? + }; + + let Some(desc) = this.machine.fds.get(fd_num) else { + this.invalid_handle("GetFileInformationByHandle")? + }; + + let metadata = match desc.metadata()? { + Ok(meta) => meta, + Err(e) => { + this.set_last_error(e)?; + return interp_ok(this.eval_windows("c", "FALSE")); + } + }; + + let size = metadata.len(); + + let file_type = metadata.file_type(); + let attributes = if file_type.is_dir() { + this.eval_windows_u32("c", "FILE_ATTRIBUTE_DIRECTORY") + } else if file_type.is_file() { + this.eval_windows_u32("c", "FILE_ATTRIBUTE_NORMAL") + } else { + this.eval_windows_u32("c", "FILE_ATTRIBUTE_DEVICE") + }; + + // Per the Windows documentation: + // "If the underlying file system does not support the [...] time, this member is zero (0)." + // https://learn.microsoft.com/en-us/windows/win32/api/fileapi/ns-fileapi-by_handle_file_information + let created = extract_windows_epoch(this, metadata.created())?.unwrap_or((0, 0)); + let accessed = extract_windows_epoch(this, metadata.accessed())?.unwrap_or((0, 0)); + let written = extract_windows_epoch(this, metadata.modified())?.unwrap_or((0, 0)); + + this.write_int_fields_named(&[("dwFileAttributes", attributes.into())], &file_information)?; + write_filetime_field(this, &file_information, "ftCreationTime", created)?; + write_filetime_field(this, &file_information, "ftLastAccessTime", accessed)?; + write_filetime_field(this, &file_information, "ftLastWriteTime", written)?; + this.write_int_fields_named( + &[ + ("dwVolumeSerialNumber", 0), + ("nFileSizeHigh", (size >> 32).into()), + ("nFileSizeLow", (size & 0xFFFFFFFF).into()), + ("nNumberOfLinks", 1), + ("nFileIndexHigh", 0), + ("nFileIndexLow", 0), + ], + &file_information, + )?; + + interp_ok(this.eval_windows("c", "TRUE")) + } +} + +/// Windows FILETIME is measured in 100-nanosecs since 1601 +fn extract_windows_epoch<'tcx>( + ecx: &MiriInterpCx<'tcx>, + time: io::Result, +) -> InterpResult<'tcx, Option<(u32, u32)>> { + match time.ok() { + Some(time) => { + let duration = ecx.system_time_since_windows_epoch(&time)?; + let duration_ticks = ecx.windows_ticks_for(duration)?; + #[allow(clippy::cast_possible_truncation)] + interp_ok(Some((duration_ticks as u32, (duration_ticks >> 32) as u32))) + } + None => interp_ok(None), + } +} + +fn write_filetime_field<'tcx>( + cx: &mut MiriInterpCx<'tcx>, + val: &MPlaceTy<'tcx>, + name: &str, + (low, high): (u32, u32), +) -> InterpResult<'tcx> { + cx.write_int_fields_named( + &[("dwLowDateTime", low.into()), ("dwHighDateTime", high.into())], + &cx.project_field_named(val, name)?, + ) +} diff --git a/src/tools/miri/src/shims/windows/handle.rs b/src/tools/miri/src/shims/windows/handle.rs index c4eb11fbd3f9..eec6c62bebc7 100644 --- a/src/tools/miri/src/shims/windows/handle.rs +++ b/src/tools/miri/src/shims/windows/handle.rs @@ -3,6 +3,7 @@ use std::mem::variant_count; use rustc_abi::HasDataLayout; use crate::concurrency::thread::ThreadNotFound; +use crate::shims::files::FdNum; use crate::*; #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] @@ -16,6 +17,8 @@ pub enum Handle { Null, Pseudo(PseudoHandle), Thread(ThreadId), + File(FdNum), + Invalid, } impl PseudoHandle { @@ -47,12 +50,18 @@ impl Handle { const NULL_DISCRIMINANT: u32 = 0; const PSEUDO_DISCRIMINANT: u32 = 1; const THREAD_DISCRIMINANT: u32 = 2; + const FILE_DISCRIMINANT: u32 = 3; + // Chosen to ensure Handle::Invalid encodes to -1. Update this value if there are ever more than + // 8 discriminants. + const INVALID_DISCRIMINANT: u32 = 7; fn discriminant(self) -> u32 { match self { Self::Null => Self::NULL_DISCRIMINANT, Self::Pseudo(_) => Self::PSEUDO_DISCRIMINANT, Self::Thread(_) => Self::THREAD_DISCRIMINANT, + Self::File(_) => Self::FILE_DISCRIMINANT, + Self::Invalid => Self::INVALID_DISCRIMINANT, } } @@ -61,17 +70,27 @@ impl Handle { Self::Null => 0, Self::Pseudo(pseudo_handle) => pseudo_handle.value(), Self::Thread(thread) => thread.to_u32(), + #[expect(clippy::cast_sign_loss)] + Self::File(fd) => fd as u32, + // INVALID_HANDLE_VALUE is -1. This fact is explicitly declared or implied in several + // pages of Windows documentation. + // 1: https://learn.microsoft.com/en-us/dotnet/api/microsoft.win32.safehandles.safefilehandle?view=net-9.0 + // 2: https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/get-osfhandle?view=msvc-170 + Self::Invalid => 0x1FFFFFFF, } } fn packed_disc_size() -> u32 { - // ceil(log2(x)) is how many bits it takes to store x numbers + // ceil(log2(x)) is how many bits it takes to store x numbers. + // We ensure that INVALID_HANDLE_VALUE (0xFFFFFFFF) decodes to Handle::Invalid. + // see https://devblogs.microsoft.com/oldnewthing/20230914-00/?p=108766 for more detail on + // INVALID_HANDLE_VALUE. let variant_count = variant_count::(); - // however, std's ilog2 is floor(log2(x)) + // However, std's ilog2 is floor(log2(x)). let floor_log2 = variant_count.ilog2(); - // we need to add one for non powers of two to compensate for the difference + // We need to add one for non powers of two to compensate for the difference. #[expect(clippy::arithmetic_side_effects)] // cannot overflow if variant_count.is_power_of_two() { floor_log2 } else { floor_log2 + 1 } } @@ -105,6 +124,13 @@ impl Handle { Self::NULL_DISCRIMINANT if data == 0 => Some(Self::Null), Self::PSEUDO_DISCRIMINANT => Some(Self::Pseudo(PseudoHandle::from_value(data)?)), Self::THREAD_DISCRIMINANT => Some(Self::Thread(ThreadId::new_unchecked(data))), + #[expect(clippy::cast_possible_wrap)] + Self::FILE_DISCRIMINANT => { + // This cast preserves all bits. + assert_eq!(size_of_val(&data), size_of::()); + Some(Self::File(data as FdNum)) + } + Self::INVALID_DISCRIMINANT => Some(Self::Invalid), _ => None, } } @@ -139,7 +165,7 @@ impl Handle { /// Structurally invalid handles return [`HandleError::InvalidHandle`]. /// If the handle is structurally valid but semantically invalid, e.g. a for non-existent thread /// ID, returns [`HandleError::ThreadNotFound`]. - pub fn try_from_scalar<'tcx>( + fn try_from_scalar<'tcx>( handle: Scalar, cx: &MiriInterpCx<'tcx>, ) -> InterpResult<'tcx, Result> { @@ -171,6 +197,27 @@ impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} #[allow(non_snake_case)] pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { + /// Convert a scalar into a structured `Handle`. + /// If the handle is invalid, or references a non-existent item, execution is aborted. + #[track_caller] + fn read_handle(&self, handle: &OpTy<'tcx>, function_name: &str) -> InterpResult<'tcx, Handle> { + let this = self.eval_context_ref(); + let handle = this.read_scalar(handle)?; + match Handle::try_from_scalar(handle, this)? { + Ok(handle) => interp_ok(handle), + Err(HandleError::InvalidHandle) => + throw_machine_stop!(TerminationInfo::Abort(format!( + "invalid handle {} passed to {function_name}", + handle.to_target_isize(this)?, + ))), + Err(HandleError::ThreadNotFound(_)) => + throw_machine_stop!(TerminationInfo::Abort(format!( + "invalid thread ID {} passed to {function_name}", + handle.to_target_isize(this)?, + ))), + } + } + fn invalid_handle(&mut self, function_name: &str) -> InterpResult<'tcx, !> { throw_machine_stop!(TerminationInfo::Abort(format!( "invalid handle passed to `{function_name}`" @@ -180,15 +227,38 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn CloseHandle(&mut self, handle_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); - let handle = this.read_scalar(handle_op)?; - let ret = match Handle::try_from_scalar(handle, this)? { - Ok(Handle::Thread(thread)) => { + let handle = this.read_handle(handle_op, "CloseHandle")?; + let ret = match handle { + Handle::Thread(thread) => { this.detach_thread(thread, /*allow_terminated_joined*/ true)?; this.eval_windows("c", "TRUE") } + Handle::File(fd_num) => + if let Some(fd) = this.machine.fds.remove(fd_num) { + let err = fd.close_ref(this.machine.communicate(), this)?; + if let Err(e) = err { + this.set_last_error(e)?; + this.eval_windows("c", "FALSE") + } else { + this.eval_windows("c", "TRUE") + } + } else { + this.invalid_handle("CloseHandle")? + }, _ => this.invalid_handle("CloseHandle")?, }; interp_ok(ret) } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_invalid_encoding() { + // Ensure the invalid handle encodes to `u32::MAX`/`INVALID_HANDLE_VALUE`. + assert_eq!(Handle::Invalid.to_packed(), u32::MAX) + } +} diff --git a/src/tools/miri/src/shims/windows/mod.rs b/src/tools/miri/src/shims/windows/mod.rs index 892bd6924fc9..442c5a0dd11f 100644 --- a/src/tools/miri/src/shims/windows/mod.rs +++ b/src/tools/miri/src/shims/windows/mod.rs @@ -1,12 +1,14 @@ pub mod foreign_items; mod env; +mod fs; mod handle; mod sync; mod thread; // All the Windows-specific extension traits pub use self::env::{EvalContextExt as _, WindowsEnvVars}; +pub use self::fs::EvalContextExt as _; pub use self::handle::EvalContextExt as _; pub use self::sync::EvalContextExt as _; pub use self::thread::EvalContextExt as _; diff --git a/src/tools/miri/src/shims/windows/thread.rs b/src/tools/miri/src/shims/windows/thread.rs index 5db554044227..d5f9ed4e968e 100644 --- a/src/tools/miri/src/shims/windows/thread.rs +++ b/src/tools/miri/src/shims/windows/thread.rs @@ -62,14 +62,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); - let handle = this.read_scalar(handle_op)?; + let handle = this.read_handle(handle_op, "WaitForSingleObject")?; let timeout = this.read_scalar(timeout_op)?.to_u32()?; - let thread = match Handle::try_from_scalar(handle, this)? { - Ok(Handle::Thread(thread)) => thread, + let thread = match handle { + Handle::Thread(thread) => thread, // Unlike on posix, the outcome of joining the current thread is not documented. // On current Windows, it just deadlocks. - Ok(Handle::Pseudo(PseudoHandle::CurrentThread)) => this.active_thread(), + Handle::Pseudo(PseudoHandle::CurrentThread) => this.active_thread(), _ => this.invalid_handle("WaitForSingleObject")?, }; diff --git a/src/tools/miri/test-cargo-miri/Cargo.lock b/src/tools/miri/test-cargo-miri/Cargo.lock index 8f618e7ffb38..32119426184d 100644 --- a/src/tools/miri/test-cargo-miri/Cargo.lock +++ b/src/tools/miri/test-cargo-miri/Cargo.lock @@ -1,12 +1,12 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "autocfg" -version = "1.2.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "byteorder" @@ -96,15 +96,15 @@ version = "0.1.0" [[package]] name = "once_cell" -version = "1.19.0" +version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "proc-macro2" -version = "1.0.79" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" +checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" dependencies = [ "unicode-ident", ] @@ -129,6 +129,6 @@ version = "0.1.0" [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" diff --git a/src/tools/miri/test-cargo-miri/Cargo.toml b/src/tools/miri/test-cargo-miri/Cargo.toml index 574f1d05a6fa..f5092a4748f3 100644 --- a/src/tools/miri/test-cargo-miri/Cargo.toml +++ b/src/tools/miri/test-cargo-miri/Cargo.toml @@ -6,7 +6,7 @@ exclude = ["no-std-smoke"] # it wants to be panic="abort" name = "cargo-miri-test" version = "0.1.0" authors = ["Miri Team"] -edition = "2018" +edition = "2024" [dependencies] byteorder = "1.0" diff --git a/src/tools/miri/test-cargo-miri/run-test.py b/src/tools/miri/test-cargo-miri/run-test.py index 5b77092979d3..a9d09ac7a9d6 100755 --- a/src/tools/miri/test-cargo-miri/run-test.py +++ b/src/tools/miri/test-cargo-miri/run-test.py @@ -136,7 +136,7 @@ def test_cargo_miri_run(): cargo_miri("run") + ["--target-dir=custom-run", "--", "--target-dir=target/custom-run"], "run.args.stdout.ref", "run.custom-target-dir.stderr.ref", ) - test("`cargo miri run --package=test-local-crate-detection` (test local crate detection)", + test("`cargo miri run` (test local crate detection)", cargo_miri("run") + ["--package=test-local-crate-detection"], "run.local_crate.stdout.ref", "run.local_crate.stderr.ref", ) @@ -147,49 +147,46 @@ def test_cargo_miri_test(): default_ref = "test.cross-target.stdout.ref" if is_foreign else "test.default.stdout.ref" filter_ref = "test.filter.cross-target.stdout.ref" if is_foreign else "test.filter.stdout.ref" - # macOS needs permissive provenance inside getrandom_1. test("`cargo miri test`", cargo_miri("test"), - default_ref, "test.stderr-empty.ref", - env={'MIRIFLAGS': "-Zmiri-permissive-provenance -Zmiri-seed=4242"}, + default_ref, "test.empty.ref", + env={'MIRIFLAGS': "-Zmiri-seed=4242"}, ) test("`cargo miri test` (no isolation, no doctests)", cargo_miri("test") + ["--bins", "--tests"], # no `--lib`, we disabled that in `Cargo.toml` - "test.cross-target.stdout.ref", "test.stderr-empty.ref", - env={'MIRIFLAGS': "-Zmiri-permissive-provenance -Zmiri-disable-isolation"}, + "test.cross-target.stdout.ref", "test.empty.ref", + env={'MIRIFLAGS': "-Zmiri-disable-isolation"}, ) test("`cargo miri test` (with filter)", cargo_miri("test") + ["--", "--format=pretty", "pl"], - filter_ref, "test.stderr-empty.ref", + filter_ref, "test.empty.ref", ) test("`cargo miri test` (test target)", cargo_miri("test") + ["--test", "test", "--", "--format=pretty"], - "test.test-target.stdout.ref", "test.stderr-empty.ref", - env={'MIRIFLAGS': "-Zmiri-permissive-provenance"}, + "test.test-target.stdout.ref", "test.empty.ref", ) test("`cargo miri test` (bin target)", cargo_miri("test") + ["--bin", "cargo-miri-test", "--", "--format=pretty"], - "test.bin-target.stdout.ref", "test.stderr-empty.ref", + "test.bin-target.stdout.ref", "test.empty.ref", ) test("`cargo miri t` (subcrate, no isolation)", cargo_miri("t") + ["-p", "subcrate"], - "test.subcrate.stdout.ref", "test.stderr-proc-macro.ref", + "test.subcrate.cross-target.stdout.ref" if is_foreign else "test.subcrate.stdout.ref", + "test.empty.ref", env={'MIRIFLAGS': "-Zmiri-disable-isolation"}, ) - test("`cargo miri test` (subcrate, doctests)", - cargo_miri("test") + ["-p", "subcrate", "--doc"], - "test.stdout-empty.ref", "test.stderr-proc-macro-doctest.ref", + test("`cargo miri test` (proc-macro crate)", + cargo_miri("test") + ["-p", "proc_macro_crate"], + "test.empty.ref", "test.proc-macro.stderr.ref", ) test("`cargo miri test` (custom target dir)", cargo_miri("test") + ["--target-dir=custom-test"], - default_ref, "test.stderr-empty.ref", - env={'MIRIFLAGS': "-Zmiri-permissive-provenance"}, + default_ref, "test.empty.ref", ) del os.environ["CARGO_TARGET_DIR"] # this overrides `build.target-dir` passed by `--config`, so unset it test("`cargo miri test` (config-cli)", cargo_miri("test") + ["--config=build.target-dir=\"config-cli\""], - default_ref, "test.stderr-empty.ref", - env={'MIRIFLAGS': "-Zmiri-permissive-provenance"}, + default_ref, "test.empty.ref", ) if ARGS.multi_target: test_cargo_miri_multi_target() @@ -198,8 +195,7 @@ def test_cargo_miri_test(): def test_cargo_miri_multi_target(): test("`cargo miri test` (multiple targets)", cargo_miri("test", targets = ["aarch64-unknown-linux-gnu", "s390x-unknown-linux-gnu"]), - "test.multiple_targets.stdout.ref", "test.stderr-empty.ref", - env={'MIRIFLAGS': "-Zmiri-permissive-provenance"}, + "test.multiple_targets.stdout.ref", "test.empty.ref", ) args_parser = argparse.ArgumentParser(description='`cargo miri` testing') diff --git a/src/tools/miri/test-cargo-miri/src/lib.rs b/src/tools/miri/test-cargo-miri/src/lib.rs index 003341d0974c..3b63f8afc902 100644 --- a/src/tools/miri/test-cargo-miri/src/lib.rs +++ b/src/tools/miri/test-cargo-miri/src/lib.rs @@ -26,7 +26,8 @@ /// /// let _val = Fail::::C; /// ``` -#[no_mangle] +// This is imported in `main.rs`. +#[unsafe(no_mangle)] pub fn make_true() -> bool { proc_macro_crate::use_the_dependency!(); issue_1567::use_the_dependency(); diff --git a/src/tools/miri/test-cargo-miri/src/main.rs b/src/tools/miri/test-cargo-miri/src/main.rs index efe95bf3abab..00a239a9161a 100644 --- a/src/tools/miri/test-cargo-miri/src/main.rs +++ b/src/tools/miri/test-cargo-miri/src/main.rs @@ -30,7 +30,7 @@ fn main() { let mut out = Vec::with_capacity(1024); unsafe { - extern "Rust" { + unsafe extern "Rust" { fn miri_host_to_target_path( path: *const c_char, out: *mut c_char, @@ -81,7 +81,7 @@ mod test { // Test calling exported symbols in (transitive) dependencies. // Repeat calls to make sure the `Instance` cache is not broken. for _ in 0..3 { - extern "Rust" { + unsafe extern "Rust" { fn exported_symbol() -> i32; fn assoc_fn_as_exported_symbol() -> i32; fn make_true() -> bool; diff --git a/src/tools/miri/test-cargo-miri/subcrate/Cargo.toml b/src/tools/miri/test-cargo-miri/subcrate/Cargo.toml index 06b1ce1cba4b..f2f6360f2d21 100644 --- a/src/tools/miri/test-cargo-miri/subcrate/Cargo.toml +++ b/src/tools/miri/test-cargo-miri/subcrate/Cargo.toml @@ -2,11 +2,11 @@ name = "subcrate" version = "0.1.0" authors = ["Miri Team"] +# This is deliberately *not* on the 2024 edition to ensure doctests keep working +# on old editions. edition = "2018" [lib] -proc-macro = true -doctest = false [[bin]] name = "subcrate" diff --git a/src/tools/miri/test-cargo-miri/subcrate/src/lib.rs b/src/tools/miri/test-cargo-miri/subcrate/src/lib.rs index 98c22fef0766..b9278c54dbed 100644 --- a/src/tools/miri/test-cargo-miri/subcrate/src/lib.rs +++ b/src/tools/miri/test-cargo-miri/subcrate/src/lib.rs @@ -1,16 +1,8 @@ -// This is a proc-macro crate. - -extern crate proc_macro; // make sure proc_macro is in the sysroot - -#[cfg(doctest)] -compile_error!("rustdoc should not touch me"); - -#[cfg(miri)] -compile_error!("Miri should not touch me"); - -use proc_macro::TokenStream; - -#[proc_macro] -pub fn make_answer(_item: TokenStream) -> TokenStream { - "fn answer() -> u32 { 42 }".parse().unwrap() +/// Doc-test test +/// +/// ```rust +/// assert!(subcrate::make_true()); +/// ``` +pub fn make_true() -> bool { + true } diff --git a/src/tools/miri/test-cargo-miri/test.stderr-empty.ref b/src/tools/miri/test-cargo-miri/test.empty.ref similarity index 100% rename from src/tools/miri/test-cargo-miri/test.stderr-empty.ref rename to src/tools/miri/test-cargo-miri/test.empty.ref diff --git a/src/tools/miri/test-cargo-miri/test.stderr-proc-macro.ref b/src/tools/miri/test-cargo-miri/test.proc-macro.stderr.ref similarity index 50% rename from src/tools/miri/test-cargo-miri/test.stderr-proc-macro.ref rename to src/tools/miri/test-cargo-miri/test.proc-macro.stderr.ref index 4983250917b5..b95474208b27 100644 --- a/src/tools/miri/test-cargo-miri/test.stderr-proc-macro.ref +++ b/src/tools/miri/test-cargo-miri/test.proc-macro.stderr.ref @@ -1 +1,2 @@ Running unit tests of `proc-macro` crates is not currently supported by Miri. +Running doctests of `proc-macro` crates is not currently supported by Miri. diff --git a/src/tools/miri/test-cargo-miri/test.stderr-proc-macro-doctest.ref b/src/tools/miri/test-cargo-miri/test.stderr-proc-macro-doctest.ref deleted file mode 100644 index ca5e3a2392db..000000000000 --- a/src/tools/miri/test-cargo-miri/test.stderr-proc-macro-doctest.ref +++ /dev/null @@ -1 +0,0 @@ -Running doctests of `proc-macro` crates is not currently supported by Miri. diff --git a/src/tools/miri/test-cargo-miri/test.subcrate.cross-target.stdout.ref b/src/tools/miri/test-cargo-miri/test.subcrate.cross-target.stdout.ref new file mode 100644 index 000000000000..436e6e4fbbbc --- /dev/null +++ b/src/tools/miri/test-cargo-miri/test.subcrate.cross-target.stdout.ref @@ -0,0 +1,11 @@ + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + +subcrate testing diff --git a/src/tools/miri/test-cargo-miri/test.subcrate.stdout.ref b/src/tools/miri/test-cargo-miri/test.subcrate.stdout.ref index e50838ebc838..c7c7bc8351b2 100644 --- a/src/tools/miri/test-cargo-miri/test.subcrate.stdout.ref +++ b/src/tools/miri/test-cargo-miri/test.subcrate.stdout.ref @@ -1,6 +1,16 @@ +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + + running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME subcrate testing + +running 1 test +. +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/src/tools/miri/test_dependencies/Cargo.lock b/src/tools/miri/test_dependencies/Cargo.lock index af92f9d0dec4..276c518e74f3 100644 --- a/src/tools/miri/test_dependencies/Cargo.lock +++ b/src/tools/miri/test_dependencies/Cargo.lock @@ -4,60 +4,51 @@ version = 4 [[package]] name = "addr2line" -version = "0.22.0" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" dependencies = [ "gimli", ] [[package]] -name = "adler" -version = "1.0.2" +name = "adler2" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" [[package]] name = "backtrace" -version = "0.3.73" +version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" dependencies = [ "addr2line", - "cc", "cfg-if", "libc", "miniz_oxide", "object", "rustc-demangle", + "windows-targets", ] [[package]] name = "bitflags" -version = "2.6.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" [[package]] name = "bumpalo" -version = "3.16.0" +version = "3.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" [[package]] name = "bytes" -version = "1.7.1" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" - -[[package]] -name = "cc" -version = "1.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9540e661f81799159abee814118cc139a2004b3a3aa3ea37724a1b66530b90e0" -dependencies = [ - "shlex", -] +checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" [[package]] name = "cfg-if" @@ -67,19 +58,19 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "errno" -version = "0.3.9" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e" dependencies = [ "libc", - "windows-sys", + "windows-sys 0.59.0", ] [[package]] name = "fastrand" -version = "2.1.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] name = "getrandom" @@ -107,21 +98,21 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8" +checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0" dependencies = [ "cfg-if", "libc", - "wasi 0.13.3+wasi-0.2.2", - "windows-targets", + "r-efi", + "wasi 0.14.2+wasi-0.2.4", ] [[package]] name = "gimli" -version = "0.29.0" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" [[package]] name = "hermit-abi" @@ -131,30 +122,31 @@ checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" [[package]] name = "js-sys" -version = "0.3.69" +version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" dependencies = [ + "once_cell", "wasm-bindgen", ] [[package]] name = "libc" -version = "0.2.161" +version = "0.2.171" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" +checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" [[package]] name = "linux-raw-sys" -version = "0.4.14" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +checksum = "fe7db12097d22ec582439daf8618b8fdd1a7bef6270e9af3b1ebcd30893cf413" [[package]] name = "log" -version = "0.4.22" +version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" [[package]] name = "memchr" @@ -164,23 +156,22 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "miniz_oxide" -version = "0.7.4" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" +checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" dependencies = [ - "adler", + "adler2", ] [[package]] name = "mio" -version = "1.0.1" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4569e456d394deccd22ce1c1913e6ea0e54519f577285001215d33557431afe4" +checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" dependencies = [ - "hermit-abi", "libc", "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -190,13 +181,13 @@ dependencies = [ "cfg-if", "getrandom 0.1.16", "getrandom 0.2.15", - "getrandom 0.3.1", + "getrandom 0.3.2", "libc", "num_cpus", "page_size", "tempfile", "tokio", - "windows-sys", + "windows-sys 0.59.0", ] [[package]] @@ -211,18 +202,18 @@ dependencies = [ [[package]] name = "object" -version = "0.36.2" +version = "0.36.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f203fa8daa7bb185f760ae12bd8e097f63d17041dcdcaf675ac54cdf863170e" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.19.0" +version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "page_size" @@ -236,28 +227,34 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.14" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" [[package]] name = "proc-macro2" -version = "1.0.86" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.36" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "5.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" + [[package]] name = "rustc-demangle" version = "0.1.24" @@ -266,23 +263,17 @@ checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "rustix" -version = "0.38.34" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +checksum = "d97817398dd4bb2e6da002002db259209759911da105da92bec29ccb12cf58bf" dependencies = [ "bitflags", "errno", "libc", "linux-raw-sys", - "windows-sys", + "windows-sys 0.59.0", ] -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - [[package]] name = "signal-hook-registry" version = "1.4.2" @@ -294,19 +285,19 @@ dependencies = [ [[package]] name = "socket2" -version = "0.5.7" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +checksum = "4f5fd57c80058a56cf5c777ab8a126398ece8e442983605d280a44ce79d0edef" dependencies = [ "libc", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] name = "syn" -version = "2.0.72" +version = "2.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af" +checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" dependencies = [ "proc-macro2", "quote", @@ -315,22 +306,22 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.11.0" +version = "3.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8fcd239983515c23a32fb82099f97d0b11b8c72f654ed659363a95c3dad7a53" +checksum = "7437ac7763b9b123ccf33c338a5cc1bac6f69b45a136c19bdd8a65e3916435bf" dependencies = [ - "cfg-if", "fastrand", + "getrandom 0.3.2", "once_cell", "rustix", - "windows-sys", + "windows-sys 0.59.0", ] [[package]] name = "tokio" -version = "1.39.2" +version = "1.44.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daa4fb1bc778bd6f04cbfc4bb2d06a7396a8f299dc33ea1900cedaa316f467b1" +checksum = "e6b88822cbe49de4185e3a4cbf8321dd487cf5fe0c5c65695fef6346371e9c48" dependencies = [ "backtrace", "bytes", @@ -340,14 +331,14 @@ dependencies = [ "signal-hook-registry", "socket2", "tokio-macros", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] name = "tokio-macros" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" +checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" dependencies = [ "proc-macro2", "quote", @@ -356,9 +347,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" [[package]] name = "wasi" @@ -374,32 +365,32 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasi" -version = "0.13.3+wasi-0.2.2" +version = "0.14.2+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2" +checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" dependencies = [ "wit-bindgen-rt", ] [[package]] name = "wasm-bindgen" -version = "0.2.92" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" dependencies = [ "cfg-if", + "once_cell", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.92" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" dependencies = [ "bumpalo", "log", - "once_cell", "proc-macro2", "quote", "syn", @@ -408,9 +399,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.92" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -418,9 +409,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.92" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", @@ -431,9 +422,12 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.92" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] [[package]] name = "winapi" @@ -466,6 +460,15 @@ dependencies = [ "windows-targets", ] +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + [[package]] name = "windows-targets" version = "0.52.6" @@ -532,9 +535,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "wit-bindgen-rt" -version = "0.33.0" +version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c" +checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" dependencies = [ "bitflags", ] diff --git a/src/tools/miri/test_dependencies/Cargo.toml b/src/tools/miri/test_dependencies/Cargo.toml index 78dddaf11dff..653228a5e3db 100644 --- a/src/tools/miri/test_dependencies/Cargo.toml +++ b/src/tools/miri/test_dependencies/Cargo.toml @@ -22,9 +22,9 @@ tempfile = "3" page_size = "0.6" # Avoid pulling in all of tokio's dependencies. # However, without `net` and `signal`, tokio uses fewer relevant system APIs. -tokio = { version = "1.24", features = ["macros", "rt-multi-thread", "time", "net", "fs", "sync", "signal", "io-util"] } +tokio = { version = "1", features = ["macros", "rt-multi-thread", "time", "net", "fs", "sync", "signal", "io-util"] } [target.'cfg(windows)'.dependencies] -windows-sys = { version = "0.52", features = [ "Win32_Foundation", "Win32_System_Threading" ] } +windows-sys = { version = "0.59", features = ["Win32_Foundation", "Win32_System_Threading", "Win32_Storage_FileSystem", "Win32_Security"] } [workspace] diff --git a/src/tools/miri/tests/fail-dep/concurrency/windows_join_main.rs b/src/tools/miri/tests/fail-dep/concurrency/windows_join_main.rs index 279201df867c..3ee2bf14f9fe 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/windows_join_main.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/windows_join_main.rs @@ -13,7 +13,7 @@ use windows_sys::Win32::System::Threading::{INFINITE, WaitForSingleObject}; // XXX HACK: This is how miri represents the handle for thread 0. // This value can be "legitimately" obtained by using `GetCurrentThread` with `DuplicateHandle` // but miri does not implement `DuplicateHandle` yet. -const MAIN_THREAD: HANDLE = (2i32 << 30) as HANDLE; +const MAIN_THREAD: HANDLE = (2i32 << 29) as HANDLE; fn main() { thread::spawn(|| { diff --git a/src/tools/miri/tests/pass-dep/concurrency/freebsd-futex.rs b/src/tools/miri/tests/pass-dep/concurrency/freebsd-futex.rs new file mode 100644 index 000000000000..38a0bf58148e --- /dev/null +++ b/src/tools/miri/tests/pass-dep/concurrency/freebsd-futex.rs @@ -0,0 +1,260 @@ +//@only-target: freebsd +//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-isolation + +use std::mem::{self, MaybeUninit}; +use std::ptr::{self, addr_of}; +use std::sync::atomic::AtomicU32; +use std::time::Instant; +use std::{io, thread}; + +fn wait_wake() { + fn wake_nobody() { + // Current thread waits on futex. + // New thread wakes up 0 threads waiting on that futex. + // Current thread should time out. + static mut FUTEX: u32 = 0; + + let waker = thread::spawn(|| { + unsafe { + assert_eq!( + libc::_umtx_op( + addr_of!(FUTEX) as *mut _, + libc::UMTX_OP_WAKE_PRIVATE, + 0, // wake up 0 waiters + ptr::null_mut::(), + ptr::null_mut::(), + ), + 0 + ); + } + }); + + // 10ms should be enough. + let mut timeout = libc::timespec { tv_sec: 0, tv_nsec: 10_000_000 }; + let timeout_size_arg = + ptr::without_provenance_mut::(mem::size_of::()); + unsafe { + assert_eq!( + libc::_umtx_op( + addr_of!(FUTEX) as *mut _, + libc::UMTX_OP_WAIT_UINT_PRIVATE, + 0, + timeout_size_arg, + &mut timeout as *mut _ as _, + ), + -1 + ); + // Main thread did not get woken up, so it timed out. + assert_eq!(io::Error::last_os_error().raw_os_error().unwrap(), libc::ETIMEDOUT); + } + + waker.join().unwrap(); + } + + fn wake_two_of_three() { + // We create 2 threads that wait on a futex with a 100ms timeout. + // The main thread wakes up 2 threads waiting on this futex and after this + // checks that only those threads woke up and the other one timed out. + static mut FUTEX: u32 = 0; + + fn waiter() -> bool { + let mut timeout = libc::timespec { tv_sec: 0, tv_nsec: 100_000_000 }; + let timeout_size_arg = + ptr::without_provenance_mut::(mem::size_of::()); + unsafe { + libc::_umtx_op( + addr_of!(FUTEX) as *mut _, + libc::UMTX_OP_WAIT_UINT_PRIVATE, + 0, // FUTEX is 0 + timeout_size_arg, + &mut timeout as *mut _ as _, + ); + // Return true if this thread woke up. + io::Error::last_os_error().raw_os_error().unwrap() != libc::ETIMEDOUT + } + } + + let t1 = thread::spawn(waiter); + let t2 = thread::spawn(waiter); + let t3 = thread::spawn(waiter); + + // Run all the waiters, so they can go to sleep. + thread::yield_now(); + + // Wake up 2 thread and make sure 1 is still waiting. + unsafe { + assert_eq!( + libc::_umtx_op( + addr_of!(FUTEX) as *mut _, + libc::UMTX_OP_WAKE_PRIVATE, + 2, + ptr::null_mut::(), + ptr::null_mut::(), + ), + 0 + ); + } + + // Treat the booleans as numbers to simplify checking how many threads were woken up. + let t1 = t1.join().unwrap() as usize; + let t2 = t2.join().unwrap() as usize; + let t3 = t3.join().unwrap() as usize; + let woken_up_count = t1 + t2 + t3; + assert!(woken_up_count == 2, "Expected 2 threads to wake up got: {woken_up_count}"); + } + + wake_nobody(); + wake_two_of_three(); +} + +fn wake_dangling() { + let futex = Box::new(0); + let ptr: *const u32 = &*futex; + drop(futex); + + // Expect error since this is now "unmapped" memory. + unsafe { + assert_eq!( + libc::_umtx_op( + ptr as *const AtomicU32 as *mut _, + libc::UMTX_OP_WAKE_PRIVATE, + 0, + ptr::null_mut::(), + ptr::null_mut::(), + ), + -1 + ); + assert_eq!(io::Error::last_os_error().raw_os_error().unwrap(), libc::EFAULT); + } +} + +fn wait_wrong_val() { + let futex: u32 = 123; + + // Wait with a wrong value just returns 0 + unsafe { + assert_eq!( + libc::_umtx_op( + ptr::from_ref(&futex).cast_mut().cast(), + libc::UMTX_OP_WAIT_UINT_PRIVATE, + 456, + ptr::null_mut::(), + ptr::null_mut::(), + ), + 0 + ); + } +} + +fn wait_relative_timeout() { + fn without_timespec() { + let start = Instant::now(); + + let futex: u32 = 123; + + let mut timeout = libc::timespec { tv_sec: 0, tv_nsec: 200_000_000 }; + let timeout_size_arg = + ptr::without_provenance_mut::(mem::size_of::()); + // Wait for 200ms, with nobody waking us up early + unsafe { + assert_eq!( + libc::_umtx_op( + ptr::from_ref(&futex).cast_mut().cast(), + libc::UMTX_OP_WAIT_UINT_PRIVATE, + 123, + timeout_size_arg, + &mut timeout as *mut _ as _, + ), + -1 + ); + assert_eq!(io::Error::last_os_error().raw_os_error().unwrap(), libc::ETIMEDOUT); + } + + assert!((200..1000).contains(&start.elapsed().as_millis())); + } + + fn with_timespec() { + let futex: u32 = 123; + let mut timeout = libc::_umtx_time { + _timeout: libc::timespec { tv_sec: 0, tv_nsec: 200_000_000 }, + _flags: 0, + _clockid: libc::CLOCK_MONOTONIC as u32, + }; + let timeout_size_arg = + ptr::without_provenance_mut::(mem::size_of::()); + + let start = Instant::now(); + + // Wait for 200ms, with nobody waking us up early + unsafe { + assert_eq!( + libc::_umtx_op( + ptr::from_ref(&futex).cast_mut().cast(), + libc::UMTX_OP_WAIT_UINT_PRIVATE, + 123, + timeout_size_arg, + &mut timeout as *mut _ as _, + ), + -1 + ); + assert_eq!(io::Error::last_os_error().raw_os_error().unwrap(), libc::ETIMEDOUT); + } + assert!((200..1000).contains(&start.elapsed().as_millis())); + } + + without_timespec(); + with_timespec(); +} + +fn wait_absolute_timeout() { + let start = Instant::now(); + + // Get the current monotonic timestamp as timespec. + let mut timeout = unsafe { + let mut now: MaybeUninit = MaybeUninit::uninit(); + assert_eq!(libc::clock_gettime(libc::CLOCK_MONOTONIC, now.as_mut_ptr()), 0); + now.assume_init() + }; + + // Add 200ms. + timeout.tv_nsec += 200_000_000; + if timeout.tv_nsec > 1_000_000_000 { + timeout.tv_nsec -= 1_000_000_000; + timeout.tv_sec += 1; + } + + // Create umtx_timeout struct with that absolute timeout. + let umtx_timeout = libc::_umtx_time { + _timeout: timeout, + _flags: libc::UMTX_ABSTIME, + _clockid: libc::CLOCK_MONOTONIC as u32, + }; + let umtx_timeout_ptr = &umtx_timeout as *const _; + let umtx_timeout_size = ptr::without_provenance_mut(mem::size_of_val(&umtx_timeout)); + + let futex: u32 = 123; + + // Wait for 200ms from now, with nobody waking us up early. + unsafe { + assert_eq!( + libc::_umtx_op( + ptr::from_ref(&futex).cast_mut().cast(), + libc::UMTX_OP_WAIT_UINT_PRIVATE, + 123, + umtx_timeout_size, + umtx_timeout_ptr as *mut _, + ), + -1 + ); + assert_eq!(io::Error::last_os_error().raw_os_error().unwrap(), libc::ETIMEDOUT); + } + assert!((200..1000).contains(&start.elapsed().as_millis())); +} + +fn main() { + wait_wake(); + wake_dangling(); + wait_wrong_val(); + wait_relative_timeout(); + wait_absolute_timeout(); +} diff --git a/src/tools/miri/tests/pass-dep/concurrency/windows_join_multiple.rs b/src/tools/miri/tests/pass-dep/concurrency/windows_join_multiple.rs index ce829eee2270..2796541a3d72 100644 --- a/src/tools/miri/tests/pass-dep/concurrency/windows_join_multiple.rs +++ b/src/tools/miri/tests/pass-dep/concurrency/windows_join_multiple.rs @@ -9,6 +9,10 @@ use std::thread; use windows_sys::Win32::Foundation::{HANDLE, WAIT_OBJECT_0}; use windows_sys::Win32::System::Threading::{INFINITE, WaitForSingleObject}; +#[derive(Copy, Clone)] +struct UnsafeSendWrapper(T); +unsafe impl Send for UnsafeSendWrapper {} + fn main() { static FLAG: AtomicBool = AtomicBool::new(false); @@ -17,10 +21,12 @@ fn main() { thread::yield_now(); } }) - .into_raw_handle() as HANDLE; + .into_raw_handle(); + let blocker = UnsafeSendWrapper(blocker as HANDLE); let waiter = move || unsafe { - assert_eq!(WaitForSingleObject(blocker, INFINITE), WAIT_OBJECT_0); + let blocker = blocker; // circumvent per-field capturing + assert_eq!(WaitForSingleObject(blocker.0, INFINITE), WAIT_OBJECT_0); }; let waiter1 = thread::spawn(waiter); diff --git a/src/tools/miri/tests/pass-dep/libc/libc-fs-flock.rs b/src/tools/miri/tests/pass-dep/libc/libc-fs-flock.rs index 99d6d2b38f8d..116cde4b425c 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-fs-flock.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-fs-flock.rs @@ -1,4 +1,5 @@ //@ignore-target: windows # File handling is not implemented yet +//@ignore-target: solaris # Does not have flock //@compile-flags: -Zmiri-disable-isolation use std::fs::File; diff --git a/src/tools/miri/tests/pass-dep/shims/windows-fs.rs b/src/tools/miri/tests/pass-dep/shims/windows-fs.rs new file mode 100644 index 000000000000..a015464dbde3 --- /dev/null +++ b/src/tools/miri/tests/pass-dep/shims/windows-fs.rs @@ -0,0 +1,207 @@ +//@only-target: windows # this directly tests windows-only functions +//@compile-flags: -Zmiri-disable-isolation +#![allow(nonstandard_style)] + +use std::os::windows::ffi::OsStrExt; +use std::path::Path; +use std::ptr; + +#[path = "../../utils/mod.rs"] +mod utils; + +use windows_sys::Win32::Foundation::{ + CloseHandle, ERROR_ACCESS_DENIED, ERROR_ALREADY_EXISTS, ERROR_IO_DEVICE, GENERIC_READ, + GENERIC_WRITE, GetLastError, RtlNtStatusToDosError, STATUS_ACCESS_DENIED, + STATUS_IO_DEVICE_ERROR, +}; +use windows_sys::Win32::Storage::FileSystem::{ + BY_HANDLE_FILE_INFORMATION, CREATE_ALWAYS, CREATE_NEW, CreateFileW, FILE_ATTRIBUTE_DIRECTORY, + FILE_ATTRIBUTE_NORMAL, FILE_FLAG_BACKUP_SEMANTICS, FILE_FLAG_OPEN_REPARSE_POINT, + FILE_SHARE_DELETE, FILE_SHARE_READ, FILE_SHARE_WRITE, GetFileInformationByHandle, OPEN_ALWAYS, + OPEN_EXISTING, +}; + +fn main() { + unsafe { + test_create_dir_file(); + test_create_normal_file(); + test_create_always_twice(); + test_open_always_twice(); + test_open_dir_reparse(); + test_ntstatus_to_dos(); + } +} + +unsafe fn test_create_dir_file() { + let temp = utils::tmp(); + let raw_path = to_wide_cstr(&temp); + // Open the `temp` directory. + let handle = CreateFileW( + raw_path.as_ptr(), + GENERIC_READ, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + ptr::null_mut(), + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, + ptr::null_mut(), + ); + assert_ne!(handle.addr(), usize::MAX, "CreateFileW Failed: {}", GetLastError()); + let mut info = std::mem::zeroed::(); + if GetFileInformationByHandle(handle, &mut info) == 0 { + panic!("Failed to get file information") + }; + assert!(info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY != 0); + if CloseHandle(handle) == 0 { + panic!("Failed to close file") + }; +} + +unsafe fn test_create_normal_file() { + let temp = utils::tmp().join("test.txt"); + let raw_path = to_wide_cstr(&temp); + let handle = CreateFileW( + raw_path.as_ptr(), + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + ptr::null_mut(), + CREATE_NEW, + 0, + ptr::null_mut(), + ); + assert_ne!(handle.addr(), usize::MAX, "CreateFileW Failed: {}", GetLastError()); + let mut info = std::mem::zeroed::(); + if GetFileInformationByHandle(handle, &mut info) == 0 { + panic!("Failed to get file information: {}", GetLastError()) + }; + assert!(info.dwFileAttributes & FILE_ATTRIBUTE_NORMAL != 0); + if CloseHandle(handle) == 0 { + panic!("Failed to close file") + }; + + // Test metadata-only handle + let handle = CreateFileW( + raw_path.as_ptr(), + 0, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + ptr::null_mut(), + OPEN_EXISTING, + 0, + ptr::null_mut(), + ); + assert_ne!(handle.addr(), usize::MAX, "CreateFileW Failed: {}", GetLastError()); + let mut info = std::mem::zeroed::(); + if GetFileInformationByHandle(handle, &mut info) == 0 { + panic!("Failed to get file information: {}", GetLastError()) + }; + assert!(info.dwFileAttributes & FILE_ATTRIBUTE_NORMAL != 0); + if CloseHandle(handle) == 0 { + panic!("Failed to close file") + }; +} + +/// Tests that CREATE_ALWAYS sets the error value correctly based on whether the file already exists +unsafe fn test_create_always_twice() { + let temp = utils::tmp().join("test_create_always.txt"); + let raw_path = to_wide_cstr(&temp); + let handle = CreateFileW( + raw_path.as_ptr(), + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + ptr::null_mut(), + CREATE_ALWAYS, + 0, + ptr::null_mut(), + ); + assert_ne!(handle.addr(), usize::MAX, "CreateFileW Failed: {}", GetLastError()); + assert_eq!(GetLastError(), 0); + if CloseHandle(handle) == 0 { + panic!("Failed to close file") + }; + + let handle = CreateFileW( + raw_path.as_ptr(), + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + ptr::null_mut(), + CREATE_ALWAYS, + 0, + ptr::null_mut(), + ); + assert_ne!(handle.addr(), usize::MAX, "CreateFileW Failed: {}", GetLastError()); + assert_eq!(GetLastError(), ERROR_ALREADY_EXISTS); + if CloseHandle(handle) == 0 { + panic!("Failed to close file") + }; +} + +/// Tests that OPEN_ALWAYS sets the error value correctly based on whether the file already exists +unsafe fn test_open_always_twice() { + let temp = utils::tmp().join("test_open_always.txt"); + let raw_path = to_wide_cstr(&temp); + let handle = CreateFileW( + raw_path.as_ptr(), + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + ptr::null_mut(), + OPEN_ALWAYS, + 0, + ptr::null_mut(), + ); + assert_ne!(handle.addr(), usize::MAX, "CreateFileW Failed: {}", GetLastError()); + assert_eq!(GetLastError(), 0); + if CloseHandle(handle) == 0 { + panic!("Failed to close file") + }; + + let handle = CreateFileW( + raw_path.as_ptr(), + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + ptr::null_mut(), + OPEN_ALWAYS, + 0, + ptr::null_mut(), + ); + assert_ne!(handle.addr(), usize::MAX, "CreateFileW Failed: {}", GetLastError()); + assert_eq!(GetLastError(), ERROR_ALREADY_EXISTS); + if CloseHandle(handle) == 0 { + panic!("Failed to close file") + }; +} + +// TODO: Once we support more of the std API, it would be nice to test against an actual symlink +unsafe fn test_open_dir_reparse() { + let temp = utils::tmp(); + let raw_path = to_wide_cstr(&temp); + // Open the `temp` directory. + let handle = CreateFileW( + raw_path.as_ptr(), + GENERIC_READ, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + ptr::null_mut(), + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, + ptr::null_mut(), + ); + assert_ne!(handle.addr(), usize::MAX, "CreateFileW Failed: {}", GetLastError()); + let mut info = std::mem::zeroed::(); + if GetFileInformationByHandle(handle, &mut info) == 0 { + panic!("Failed to get file information") + }; + assert!(info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY != 0); + if CloseHandle(handle) == 0 { + panic!("Failed to close file") + }; +} + +unsafe fn test_ntstatus_to_dos() { + // We won't test all combinations, just a couple common ones + assert_eq!(RtlNtStatusToDosError(STATUS_IO_DEVICE_ERROR), ERROR_IO_DEVICE); + assert_eq!(RtlNtStatusToDosError(STATUS_ACCESS_DENIED), ERROR_ACCESS_DENIED); +} + +fn to_wide_cstr(path: &Path) -> Vec { + let mut raw_path = path.as_os_str().encode_wide().collect::>(); + raw_path.extend([0, 0]); + raw_path +} diff --git a/src/tools/miri/tests/pass/float.rs b/src/tools/miri/tests/pass/float.rs index 05ac5e82b564..cd60b6bd563d 100644 --- a/src/tools/miri/tests/pass/float.rs +++ b/src/tools/miri/tests/pass/float.rs @@ -38,8 +38,9 @@ macro_rules! assert_approx_eq { }}; ($a:expr, $b: expr) => { - // accept up to 64ULP (16ULP for host floats and 16ULP for miri artificial error and 32 for any rounding errors) - assert_approx_eq!($a, $b, 64); + // accept up to 12ULP (4ULP for host floats and 4ULP for miri artificial error and 4 for any additional effects + // due to having multiple error sources. + assert_approx_eq!($a, $b, 12); }; } diff --git a/src/tools/miri/tests/pass/issues/issue-134713-swap_nonoverlapping_untyped.rs b/src/tools/miri/tests/pass/issues/issue-134713-swap_nonoverlapping_untyped.rs new file mode 100644 index 000000000000..27ea12398d88 --- /dev/null +++ b/src/tools/miri/tests/pass/issues/issue-134713-swap_nonoverlapping_untyped.rs @@ -0,0 +1,30 @@ +use std::mem::{align_of, size_of}; + +// See + +#[repr(C)] +struct Foo(usize, u8); + +fn main() { + let buf1: [usize; 2] = [1000, 2000]; + let buf2: [usize; 2] = [3000, 4000]; + + // Foo and [usize; 2] have the same size and alignment, + // so swap_nonoverlapping should treat them the same + assert_eq!(size_of::(), size_of::<[usize; 2]>()); + assert_eq!(align_of::(), align_of::<[usize; 2]>()); + + let mut b1 = buf1; + let mut b2 = buf2; + // Safety: b1 and b2 are distinct local variables, + // with the same size and alignment as Foo. + unsafe { + std::ptr::swap_nonoverlapping( + b1.as_mut_ptr().cast::(), + b2.as_mut_ptr().cast::(), + 1, + ); + } + assert_eq!(b1, buf2); + assert_eq!(b2, buf1); +} diff --git a/src/tools/miri/tests/pass/issues/issue-139553.rs b/src/tools/miri/tests/pass/issues/issue-139553.rs new file mode 100644 index 000000000000..119d589d1ead --- /dev/null +++ b/src/tools/miri/tests/pass/issues/issue-139553.rs @@ -0,0 +1,45 @@ +//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-compare-exchange-weak-failure-rate=0 +use std::sync::mpsc::channel; +use std::thread; + +/// This test aims to trigger a race condition that causes a double free in the unbounded channel +/// implementation. The test relies on a particular thread scheduling to happen as annotated by the +/// comments below. +fn main() { + let (s1, r) = channel::(); + let s2 = s1.clone(); + + let t1 = thread::spawn(move || { + // 1. The first action executed is an attempt to send the first value in the channel. This + // will begin to initialize the channel but will stop at a critical momement as + // indicated by the `yield_now()` call in the `start_send` method of the implementation. + let _ = s1.send(42); + // 4. The sender is re-scheduled and it finishes the initialization of the channel by + // setting head.block to the same value as tail.block. It then proceeds to publish its + // value but observes that the channel has already disconnected (due to the concurrent + // call of `discard_all_messages`) and aborts the send. + }); + std::thread::yield_now(); + + // 2. A second sender attempts to send a value while the channel is in a half-initialized + // state. Here, half-initialized means that the `tail.block` pointer points to a valid block + // but `head.block` is still null. This condition is ensured by the yield of step 1. When + // this call returns the channel state has tail.index != head.index, tail.block != NULL, and + // head.block = NULL. + s2.send(42).unwrap(); + // 3. This thread continues with dropping the one and only receiver. When all receivers are + // gone `discard_all_messages` will attempt to drop all currently sent values and + // de-allocate all the blocks. If `tail.block != NULL` but `head.block = NULL` the + // implementation waits for the initializing sender to finish by spinning/yielding. + drop(r); + // 5. This thread is rescheduled and `discard_all_messages` observes the head.block pointer set + // by step 4 and proceeds with deallocation. In the problematic version of the code + // `head.block` is simply read via an `Acquire` load and not swapped with NULL. After this + // call returns the channel state has tail.index = head.index, tail.block = NULL, and + // head.block != NULL. + t1.join().unwrap(); + // 6. The last sender (s2) is dropped here which also attempts to cleanup any data in the + // channel. It observes `tail.index = head.index` and so it doesn't attempt to cleanup any + // messages but it also observes that `head.block != NULL` and attempts to deallocate it. + // This is however already deallocated by `discard_all_messages`, leading to a double free. +} diff --git a/src/tools/miri/tests/pass/path.rs b/src/tools/miri/tests/pass/path.rs index 299ee6cfe9dd..7428d0afcc67 100644 --- a/src/tools/miri/tests/pass/path.rs +++ b/src/tools/miri/tests/pass/path.rs @@ -6,7 +6,11 @@ mod utils; #[track_caller] fn assert_absolute_eq(in_: &str, out: &str) { - assert_eq!(absolute(in_).unwrap().as_os_str(), Path::new(out).as_os_str()); + assert_eq!( + absolute(in_).unwrap().as_os_str(), + Path::new(out).as_os_str(), + "incorrect absolute path for {in_:?}" + ); } fn test_absolute() { @@ -29,11 +33,28 @@ fn test_absolute() { assert_absolute_eq(r"\\?\C:\path\to\file", r"\\?\C:\path\to\file"); assert_absolute_eq(r"\\?\UNC\server\share\to\file", r"\\?\UNC\server\share\to\file"); assert_absolute_eq(r"\\?\PIPE\name", r"\\?\PIPE\name"); + assert_absolute_eq(r"\\server\share\NUL", r"\\server\share\NUL"); + // This fails on Windows 10 hosts. FIXME: enable this once GHA runners are on Windows 11. + //assert_absolute_eq(r"C:\path\to\COM1", r"C:\path\to\COM1"); // Verbatim paths are always unchanged, no matter what. assert_absolute_eq(r"\\?\path.\to/file..", r"\\?\path.\to/file.."); - + // Trailing dot is removed here. assert_absolute_eq(r"C:\path..\to.\file.", r"C:\path..\to\file"); + // `..` is resolved here. + assert_absolute_eq(r"C:\path\to\..\file", r"C:\path\file"); + assert_absolute_eq(r"C:\path\to\..\..\file", r"C:\file"); + assert_absolute_eq(r"C:\path\to\..\..\..\..\..\..\file", r"C:\file"); + assert_absolute_eq(r"C:\..", r"C:\"); + assert_absolute_eq(r"\\server\share\to\path\with\..\file", r"\\server\share\to\path\file"); + assert_absolute_eq(r"\\server\share\to\..\..\..\..\file", r"\\server\share\file"); + assert_absolute_eq(r"\\server\share\..", r"\\server\share"); + // Magic filenames. + assert_absolute_eq(r"NUL", r"\\.\NUL"); + assert_absolute_eq(r"nul", r"\\.\nul"); assert_absolute_eq(r"COM1", r"\\.\COM1"); + assert_absolute_eq(r"com1", r"\\.\com1"); + assert_absolute_eq(r"C:\path\to\NUL", r"\\.\NUL"); + assert_absolute_eq(r"C:\path\to\nul", r"\\.\nul"); } else { panic!("unsupported OS"); } diff --git a/src/tools/miri/tests/pass/shims/fs.rs b/src/tools/miri/tests/pass/shims/fs.rs index 289c6aa2fcec..6ad23055f30e 100644 --- a/src/tools/miri/tests/pass/shims/fs.rs +++ b/src/tools/miri/tests/pass/shims/fs.rs @@ -1,4 +1,3 @@ -//@ignore-target: windows # File handling is not implemented yet //@compile-flags: -Zmiri-disable-isolation #![feature(io_error_more)] @@ -18,20 +17,23 @@ mod utils; fn main() { test_path_conversion(); - test_file(); - test_file_clone(); - test_file_create_new(); - test_seek(); - test_metadata(); - test_file_set_len(); - test_file_sync(); - test_errors(); - test_rename(); - test_directory(); - test_canonicalize(); - test_from_raw_os_error(); - #[cfg(unix)] - test_pread_pwrite(); + // Windows file handling is very incomplete. + if cfg!(not(windows)) { + test_file(); + test_file_create_new(); + test_seek(); + test_file_clone(); + test_metadata(); + test_file_set_len(); + test_file_sync(); + test_errors(); + test_rename(); + test_directory(); + test_canonicalize(); + test_from_raw_os_error(); + #[cfg(unix)] + test_pread_pwrite(); + } } fn test_path_conversion() { @@ -144,10 +146,10 @@ fn test_metadata() { let path = utils::prepare_with_content("miri_test_fs_metadata.txt", bytes); // Test that metadata of an absolute path is correct. - check_metadata(bytes, &path).unwrap(); + check_metadata(bytes, &path).expect("absolute path metadata"); // Test that metadata of a relative path is correct. std::env::set_current_dir(path.parent().unwrap()).unwrap(); - check_metadata(bytes, Path::new(path.file_name().unwrap())).unwrap(); + check_metadata(bytes, Path::new(path.file_name().unwrap())).expect("relative path metadata"); // Removing file should succeed. remove_file(&path).unwrap(); diff --git a/src/tools/miri/tests/pass/tls/tls_leak_main_thread_allowed.rs b/src/tools/miri/tests/pass/tls/tls_leak_main_thread_allowed.rs index 341b2280e010..abc0968f7c4c 100644 --- a/src/tools/miri/tests/pass/tls/tls_leak_main_thread_allowed.rs +++ b/src/tools/miri/tests/pass/tls/tls_leak_main_thread_allowed.rs @@ -13,7 +13,7 @@ pub fn main() { TLS.set(Some(Box::leak(Box::new(123)))); // We can only ignore leaks on targets that use `#[thread_local]` statics to implement - // `thread_local!`. Ignore the test on targest that don't. + // `thread_local!`. Ignore the test on targets that don't. if cfg!(target_thread_local) { thread_local! { static TLS_KEY: Cell> = Cell::new(None); diff --git a/src/tools/miri/triagebot.toml b/src/tools/miri/triagebot.toml index 4e013764d871..60e80c3f6733 100644 --- a/src/tools/miri/triagebot.toml +++ b/src/tools/miri/triagebot.toml @@ -40,3 +40,9 @@ unless = ["S-blocked", "S-waiting-on-team", "S-waiting-on-review"] # Automatically close and reopen PRs made by bots to run CI on them [bot-pull-requests] + +# Canonicalize issue numbers to avoid closing the wrong issue when upstreaming this subtree +[canonicalize-issue-links] + +# Prevents mentions in commits to avoid users being spammed +[no-mentions] diff --git a/src/tools/opt-dist/src/environment.rs b/src/tools/opt-dist/src/environment.rs index 90d0ca717b25..9342d164be41 100644 --- a/src/tools/opt-dist/src/environment.rs +++ b/src/tools/opt-dist/src/environment.rs @@ -25,6 +25,7 @@ pub struct Environment { prebuilt_rustc_perf: Option, use_bolt: bool, shared_llvm: bool, + run_tests: bool, } impl Environment { @@ -101,6 +102,10 @@ impl Environment { pub fn benchmark_cargo_config(&self) -> &[String] { &self.benchmark_cargo_config } + + pub fn run_tests(&self) -> bool { + self.run_tests + } } /// What is the extension of binary executables on this platform? diff --git a/src/tools/opt-dist/src/main.rs b/src/tools/opt-dist/src/main.rs index ac5d294f07ed..d5e6640fb430 100644 --- a/src/tools/opt-dist/src/main.rs +++ b/src/tools/opt-dist/src/main.rs @@ -76,7 +76,7 @@ enum EnvironmentCmd { rustc_perf_checkout_dir: Option, /// Is LLVM for `rustc` built in shared library mode? - #[arg(long, default_value_t = true)] + #[arg(long, default_value_t = true, action(clap::ArgAction::Set))] llvm_shared: bool, /// Should BOLT optimization be used? If yes, host LLVM must have BOLT binaries @@ -94,6 +94,10 @@ enum EnvironmentCmd { /// Arguments passed to `rustc-perf --cargo-config ` when running benchmarks. #[arg(long)] benchmark_cargo_config: Vec, + + /// Perform tests after final build if it's not a try build + #[arg(long)] + run_tests: bool, }, /// Perform an optimized build on Linux CI, from inside Docker. LinuxCi { @@ -125,6 +129,7 @@ fn create_environment(args: Args) -> anyhow::Result<(Environment, Vec)> skipped_tests, benchmark_cargo_config, shared, + run_tests, } => { let env = EnvironmentBuilder::default() .host_tuple(target_triple) @@ -138,6 +143,7 @@ fn create_environment(args: Args) -> anyhow::Result<(Environment, Vec)> .use_bolt(use_bolt) .skipped_tests(skipped_tests) .benchmark_cargo_config(benchmark_cargo_config) + .run_tests(run_tests) .build()?; (env, shared.build_args) @@ -160,6 +166,7 @@ fn create_environment(args: Args) -> anyhow::Result<(Environment, Vec)> // FIXME: Enable bolt for aarch64 once it's fixed upstream. Broken as of December 2024. .use_bolt(!is_aarch64) .skipped_tests(vec![]) + .run_tests(true) .build()?; (env, shared.build_args) @@ -179,6 +186,7 @@ fn create_environment(args: Args) -> anyhow::Result<(Environment, Vec)> .shared_llvm(false) .use_bolt(false) .skipped_tests(vec![]) + .run_tests(true) .build()?; (env, shared.build_args) @@ -344,7 +352,7 @@ fn execute_pipeline( // possible regressions. // The tests are not executed for try builds, which can be in various broken states, so we don't // want to gatekeep them with tests. - if !is_try_build() { + if !is_try_build() && env.run_tests() { timer.section("Run tests", |_| run_tests(env))?; } diff --git a/src/tools/opt-dist/src/training.rs b/src/tools/opt-dist/src/training.rs index 30c79f959474..47159a43140f 100644 --- a/src/tools/opt-dist/src/training.rs +++ b/src/tools/opt-dist/src/training.rs @@ -70,7 +70,9 @@ fn merge_llvm_profiles( profdata: LlvmProfdata, ) -> anyhow::Result<()> { let llvm_profdata = match profdata { - LlvmProfdata::Host => env.host_llvm_dir().join("bin/llvm-profdata"), + LlvmProfdata::Host => { + env.host_llvm_dir().join(format!("bin/llvm-profdata{}", executable_extension())) + } LlvmProfdata::Target => env .build_artifacts() .join("llvm") diff --git a/src/tools/opt-dist/src/utils/mod.rs b/src/tools/opt-dist/src/utils/mod.rs index 32d88a59af92..fb4f14ea41ae 100644 --- a/src/tools/opt-dist/src/utils/mod.rs +++ b/src/tools/opt-dist/src/utils/mod.rs @@ -36,7 +36,9 @@ pub fn clear_llvm_files(env: &Environment) -> anyhow::Result<()> { // directories ourselves. log::info!("Clearing LLVM build files"); delete_directory(&env.build_artifacts().join("llvm"))?; - delete_directory(&env.build_artifacts().join("lld"))?; + if env.build_artifacts().join("lld").is_dir() { + delete_directory(&env.build_artifacts().join("lld"))?; + } Ok(()) } diff --git a/src/tools/run-make-support/Cargo.toml b/src/tools/run-make-support/Cargo.toml index f9beffec7508..15ed03ad5c23 100644 --- a/src/tools/run-make-support/Cargo.toml +++ b/src/tools/run-make-support/Cargo.toml @@ -14,9 +14,5 @@ build_helper = { path = "../../build_helper" } serde_json = "1.0" libc = "0.2" -# FIXME(#137532): replace `os_pipe` with `anonymous_pipe` once it stabilizes and -# reaches beta. -os_pipe = "1.2.1" - [lib] crate-type = ["lib", "dylib"] diff --git a/src/tools/run-make-support/src/artifact_names.rs b/src/tools/run-make-support/src/artifact_names.rs index 8968f831542e..b0d588d3550a 100644 --- a/src/tools/run-make-support/src/artifact_names.rs +++ b/src/tools/run-make-support/src/artifact_names.rs @@ -1,11 +1,11 @@ //! A collection of helpers to construct artifact names, such as names of dynamic or static -//! librarys which are target-dependent. - -// FIXME(jieyouxu): convert these to return `PathBuf`s instead of strings! +//! libraries which are target-dependent. +use crate::target; use crate::targets::is_msvc; /// Construct the static library name based on the target. +#[track_caller] #[must_use] pub fn static_lib_name(name: &str) -> String { assert!(!name.contains(char::is_whitespace), "static library name cannot contain whitespace"); @@ -14,15 +14,34 @@ pub fn static_lib_name(name: &str) -> String { } /// Construct the dynamic library name based on the target. +#[track_caller] #[must_use] pub fn dynamic_lib_name(name: &str) -> String { assert!(!name.contains(char::is_whitespace), "dynamic library name cannot contain whitespace"); - format!("{}{name}.{}", std::env::consts::DLL_PREFIX, std::env::consts::DLL_EXTENSION) + format!("{}{name}.{}", dynamic_lib_prefix(), dynamic_lib_extension()) } -/// Construct the name of the import library for the dynamic library, exclusive to MSVC and -/// accepted by link.exe. +fn dynamic_lib_prefix() -> &'static str { + if target().contains("windows") { "" } else { "lib" } +} + +/// Construct the dynamic library extension based on the target. +#[must_use] +pub fn dynamic_lib_extension() -> &'static str { + let target = target(); + + if target.contains("apple") { + "dylib" + } else if target.contains("windows") { + "dll" + } else { + "so" + } +} + +/// Construct the name of the import library for the dynamic library, exclusive to MSVC and accepted +/// by link.exe. #[track_caller] #[must_use] pub fn msvc_import_dynamic_lib_name(name: &str) -> String { @@ -32,20 +51,28 @@ pub fn msvc_import_dynamic_lib_name(name: &str) -> String { format!("{name}.dll.lib") } -/// Construct the dynamic library extension based on the target. -#[must_use] -pub fn dynamic_lib_extension() -> &'static str { - std::env::consts::DLL_EXTENSION -} - /// Construct the name of a rust library (rlib). +#[track_caller] #[must_use] pub fn rust_lib_name(name: &str) -> String { format!("lib{name}.rlib") } /// Construct the binary (executable) name based on the target. +#[track_caller] #[must_use] pub fn bin_name(name: &str) -> String { - format!("{name}{}", std::env::consts::EXE_SUFFIX) + let target = target(); + + if target.contains("windows") { + format!("{name}.exe") + } else if target.contains("uefi") { + format!("{name}.efi") + } else if target.contains("wasm") { + format!("{name}.wasm") + } else if target.contains("nvptx") { + format!("{name}.ptx") + } else { + name.to_string() + } } diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index c75d500d2f06..f37b38ac0b15 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -41,8 +41,6 @@ pub use bstr; pub use gimli; pub use libc; pub use object; -// FIXME(#137532): replace with std `anonymous_pipe` once it stabilizes and reaches beta. -pub use os_pipe; pub use regex; pub use serde_json; pub use similar; diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index 745a8097c8a5..2dbb3f5d69ca 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -902,9 +902,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.169" +version = "0.2.172" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" +checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" [[package]] name = "libloading" diff --git a/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs b/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs index 0a7a7d1fb241..706d04484f6f 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs @@ -3789,35 +3789,6 @@ The tracking issue for this feature is: [#64797] [#64797]: https://github.com/rust-lang/rust/issues/64797 ------------------------ -"##, - default_severity: Severity::Allow, - warn_since: None, - deny_since: None, - }, - Lint { - label: "cfg_boolean_literals", - description: r##"# `cfg_boolean_literals` - -The tracking issue for this feature is: [#131204] - -[#131204]: https://github.com/rust-lang/rust/issues/131204 - ------------------------- - -The `cfg_boolean_literals` feature makes it possible to use the `true`/`false` -literal as cfg predicate. They always evaluate to true/false respectively. - -## Examples - -```rust -#![feature(cfg_boolean_literals)] - -#[cfg(true)] -const A: i32 = 5; - -#[cfg(all(false))] -const A: i32 = 58 * 89; -``` "##, default_severity: Severity::Allow, warn_since: None, diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs index 6b470d921f7a..80a2d4690d4a 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs @@ -6882,109 +6882,14 @@ pub fn foo() {} #[test] fn hover_feature() { - check( - r#"#![feature(intrinsics$0)]"#, - expect![[r#" - *intrinsics* - ``` - intrinsics - ``` - ___ - - # `intrinsics` - - The tracking issue for this feature is: None. - - Intrinsics are rarely intended to be stable directly, but are usually - exported in some sort of stable manner. Prefer using the stable interfaces to - the intrinsic directly when you can. - - ------------------------ - - - ## Intrinsics with fallback logic - - Many intrinsics can be written in pure rust, albeit inefficiently or without supporting - some features that only exist on some backends. Backends can simply not implement those - intrinsics without causing any code miscompilations or failures to compile. - All intrinsic fallback bodies are automatically made cross-crate inlineable (like `#[inline]`) - by the codegen backend, but not the MIR inliner. - - ```rust - #![feature(intrinsics)] - #![allow(internal_features)] - - #[rustc_intrinsic] - const unsafe fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) {} - ``` - - Since these are just regular functions, it is perfectly ok to create the intrinsic twice: - - ```rust - #![feature(intrinsics)] - #![allow(internal_features)] - - #[rustc_intrinsic] - const unsafe fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) {} - - mod foo { - #[rustc_intrinsic] - const unsafe fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) { - panic!("noisy const dealloc") - } - } - - ``` - - The behaviour on backends that override the intrinsic is exactly the same. On other - backends, the intrinsic behaviour depends on which implementation is called, just like - with any regular function. - - ## Intrinsics lowered to MIR instructions - - Various intrinsics have native MIR operations that they correspond to. Instead of requiring - backends to implement both the intrinsic and the MIR operation, the `lower_intrinsics` pass - will convert the calls to the MIR operation. Backends do not need to know about these intrinsics - at all. These intrinsics only make sense without a body, and can either be declared as a "rust-intrinsic" - or as a `#[rustc_intrinsic]`. The body is never used, as calls to the intrinsic do not exist - anymore after MIR analyses. - - ## Intrinsics without fallback logic - - These must be implemented by all backends. - - ### `#[rustc_intrinsic]` declarations - - These are written like intrinsics with fallback bodies, but the body is irrelevant. - Use `loop {}` for the body or call the intrinsic recursively and add - `#[rustc_intrinsic_must_be_overridden]` to the function to ensure that backends don't - invoke the body. - - ### Legacy extern ABI based intrinsics - - These are imported as if they were FFI functions, with the special - `rust-intrinsic` ABI. For example, if one was in a freestanding - context, but wished to be able to `transmute` between types, and - perform efficient pointer arithmetic, one would import those functions - via a declaration like - - ```rust - #![feature(intrinsics)] - #![allow(internal_features)] - # fn main() {} - - extern "rust-intrinsic" { - fn transmute(x: T) -> U; - - fn arith_offset(dst: *const T, offset: isize) -> *const T; - } - ``` - - As with any other FFI functions, these are by default always `unsafe` to call. - You can add `#[rustc_safe_intrinsic]` to the intrinsic to make it safe to call. - - "#]], - ) + let (analysis, position) = fixture::position(r#"#![feature(intrinsics$0)]"#); + analysis + .hover( + &HoverConfig { links_in_hover: true, ..HOVER_BASE_CONFIG }, + FileRange { file_id: position.file_id, range: TextRange::empty(position.offset) }, + ) + .unwrap() + .unwrap(); } #[test] diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs index 59293ee3f965..80f6d85a3d05 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs @@ -11,7 +11,7 @@ use std::{ use intern::Symbol; use proc_macro::bridge::{self, server}; -use span::{FileId, Span, FIXUP_ERASED_FILE_AST_ID_MARKER}; +use span::{Span, FIXUP_ERASED_FILE_AST_ID_MARKER}; use tt::{TextRange, TextSize}; use crate::server_impl::{literal_kind_to_internal, token_stream::TokenStreamBuilder, TopSubtree}; @@ -27,10 +27,6 @@ mod tt { type TokenStream = crate::server_impl::TokenStream; -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub struct SourceFile { - file_id: FileId, -} pub struct FreeFunctions; pub struct RaSpanServer { @@ -46,7 +42,6 @@ pub struct RaSpanServer { impl server::Types for RaSpanServer { type FreeFunctions = FreeFunctions; type TokenStream = TokenStream; - type SourceFile = SourceFile; type Span = Span; type Symbol = Symbol; } @@ -245,25 +240,17 @@ impl server::TokenStream for RaSpanServer { } } -impl server::SourceFile for RaSpanServer { - fn eq(&mut self, file1: &Self::SourceFile, file2: &Self::SourceFile) -> bool { - file1 == file2 - } - fn path(&mut self, _file: &Self::SourceFile) -> String { - // FIXME - String::new() - } - fn is_real(&mut self, _file: &Self::SourceFile) -> bool { - true - } -} - impl server::Span for RaSpanServer { fn debug(&mut self, span: Self::Span) -> String { format!("{:?}", span) } - fn source_file(&mut self, span: Self::Span) -> Self::SourceFile { - SourceFile { file_id: span.anchor.file_id.file_id() } + fn file(&mut self, _: Self::Span) -> String { + // FIXME + String::new() + } + fn local_file(&mut self, _: Self::Span) -> Option { + // FIXME + None } fn save_span(&mut self, _span: Self::Span) -> usize { // FIXME, quote is incompatible with third-party tools diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs index 409cf3cc7813..4d7c7c46766b 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs @@ -24,8 +24,6 @@ type Literal = tt::Literal; type Span = tt::TokenId; type TokenStream = crate::server_impl::TokenStream; -#[derive(Clone)] -pub struct SourceFile; pub struct FreeFunctions; pub struct TokenIdServer { @@ -37,7 +35,6 @@ pub struct TokenIdServer { impl server::Types for TokenIdServer { type FreeFunctions = FreeFunctions; type TokenStream = TokenStream; - type SourceFile = SourceFile; type Span = Span; type Symbol = Symbol; } @@ -223,24 +220,15 @@ impl server::TokenStream for TokenIdServer { } } -impl server::SourceFile for TokenIdServer { - fn eq(&mut self, _file1: &Self::SourceFile, _file2: &Self::SourceFile) -> bool { - true - } - fn path(&mut self, _file: &Self::SourceFile) -> String { - String::new() - } - fn is_real(&mut self, _file: &Self::SourceFile) -> bool { - true - } -} - impl server::Span for TokenIdServer { fn debug(&mut self, span: Self::Span) -> String { format!("{:?}", span.0) } - fn source_file(&mut self, _span: Self::Span) -> Self::SourceFile { - SourceFile {} + fn file(&mut self, _span: Self::Span) -> String { + String::new() + } + fn local_file(&mut self, _span: Self::Span) -> Option { + None } fn save_span(&mut self, _span: Self::Span) -> usize { 0 diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs index 15de88ea656d..4bd365be7ca8 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs @@ -97,6 +97,7 @@ fn test_fn_like_macro_clone_raw_ident() { } #[test] +#[cfg(not(bootstrap))] fn test_fn_like_fn_like_span_join() { assert_expand( "fn_like_span_join", @@ -111,6 +112,7 @@ fn test_fn_like_fn_like_span_join() { } #[test] +#[cfg(not(bootstrap))] fn test_fn_like_fn_like_span_ops() { assert_expand( "fn_like_span_ops", diff --git a/src/tools/rustbook/Cargo.lock b/src/tools/rustbook/Cargo.lock index 09bbbd61de50..c14372dd6aec 100644 --- a/src/tools/rustbook/Cargo.lock +++ b/src/tools/rustbook/Cargo.lock @@ -951,6 +951,7 @@ dependencies = [ "once_cell", "pathdiff", "pulldown-cmark 0.10.3", + "railroad", "regex", "semver", "serde_json", @@ -981,9 +982,9 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "miniz_oxide" -version = "0.8.7" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff70ce3e48ae43fa075863cef62e8b43b71a4f2382229920e0df362592919430" +checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" dependencies = [ "adler2", ] @@ -1300,6 +1301,15 @@ version = "5.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" +[[package]] +name = "railroad" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ecedffc46c1b2cb04f4b80e094eae6b3f3f470a9635f1f396dd5206428f6b58" +dependencies = [ + "unicode-width", +] + [[package]] name = "rand" version = "0.8.5" diff --git a/src/tools/rustc-perf b/src/tools/rustc-perf index e22e08623a34..c0f3b53c8e5d 160000 --- a/src/tools/rustc-perf +++ b/src/tools/rustc-perf @@ -1 +1 @@ -Subproject commit e22e08623a349b13a3296971a05394d44f769744 +Subproject commit c0f3b53c8e5de87714d18a5f42998859302ae03a diff --git a/src/tools/rustdoc-gui-test/Cargo.toml b/src/tools/rustdoc-gui-test/Cargo.toml index f7384a98f856..8d958ac94f30 100644 --- a/src/tools/rustdoc-gui-test/Cargo.toml +++ b/src/tools/rustdoc-gui-test/Cargo.toml @@ -5,6 +5,7 @@ edition = "2021" [dependencies] build_helper = { path = "../../build_helper" } +camino = "1" compiletest = { path = "../compiletest" } getopts = "0.2" walkdir = "2" diff --git a/src/tools/rustdoc-gui-test/src/main.rs b/src/tools/rustdoc-gui-test/src/main.rs index f1c6e13d3ae8..addb0af4a541 100644 --- a/src/tools/rustdoc-gui-test/src/main.rs +++ b/src/tools/rustdoc-gui-test/src/main.rs @@ -118,7 +118,11 @@ If you want to install the `browser-ui-test` dependency, run `npm install browse ..Default::default() }; - let test_props = TestProps::from_file(&librs, None, &compiletest_c); + let test_props = TestProps::from_file( + &camino::Utf8PathBuf::try_from(librs).unwrap(), + None, + &compiletest_c, + ); if !test_props.compile_flags.is_empty() { cargo.env("RUSTDOCFLAGS", test_props.compile_flags.join(" ")); diff --git a/src/tools/rustfmt/src/items.rs b/src/tools/rustfmt/src/items.rs index 322af97d9dc4..5c3be769f9e0 100644 --- a/src/tools/rustfmt/src/items.rs +++ b/src/tools/rustfmt/src/items.rs @@ -2442,11 +2442,7 @@ pub(crate) fn span_hi_for_param(context: &RewriteContext<'_>, param: &ast::Param } pub(crate) fn is_named_param(param: &ast::Param) -> bool { - if let ast::PatKind::Ident(_, ident, _) = param.pat.kind { - ident.name != symbol::kw::Empty - } else { - true - } + !matches!(param.pat.kind, ast::PatKind::Missing) } #[derive(Copy, Clone, Debug, PartialEq, Eq)] diff --git a/src/tools/rustfmt/src/macros.rs b/src/tools/rustfmt/src/macros.rs index ddf3d2ce96af..1e16aace3041 100644 --- a/src/tools/rustfmt/src/macros.rs +++ b/src/tools/rustfmt/src/macros.rs @@ -858,18 +858,18 @@ impl MacroArgParser { }; self.result.push(ParsedMacroArg { - kind: MacroArgKind::Repeat(delim, inner, another, self.last_tok.clone()), + kind: MacroArgKind::Repeat(delim, inner, another, self.last_tok), }); Some(()) } - fn update_buffer(&mut self, t: &Token) { + fn update_buffer(&mut self, t: Token) { if self.buf.is_empty() { - self.start_tok = t.clone(); + self.start_tok = t; } else { let needs_space = match next_space(&self.last_tok.kind) { - SpaceState::Ident => ident_like(t), - SpaceState::Punctuation => !ident_like(t), + SpaceState::Ident => ident_like(&t), + SpaceState::Punctuation => !ident_like(&t), SpaceState::Always => true, SpaceState::Never => false, }; @@ -878,7 +878,7 @@ impl MacroArgParser { } } - self.buf.push_str(&pprust::token_to_string(t)); + self.buf.push_str(&pprust::token_to_string(&t)); } fn need_space_prefix(&self) -> bool { @@ -937,7 +937,7 @@ impl MacroArgParser { ) if self.is_meta_var => { self.add_meta_variable(&mut iter)?; } - TokenTree::Token(ref t, _) => self.update_buffer(t), + &TokenTree::Token(t, _) => self.update_buffer(t), &TokenTree::Delimited(_dspan, _spacing, delimited, ref tts) => { if !self.buf.is_empty() { if next_space(&self.last_tok.kind) == SpaceState::Always { diff --git a/src/tools/rustfmt/src/patterns.rs b/src/tools/rustfmt/src/patterns.rs index 8dc945745032..cb3879f4be8c 100644 --- a/src/tools/rustfmt/src/patterns.rs +++ b/src/tools/rustfmt/src/patterns.rs @@ -42,6 +42,7 @@ pub(crate) fn is_short_pattern( fn is_short_pattern_inner(context: &RewriteContext<'_>, pat: &ast::Pat) -> bool { match &pat.kind { + ast::PatKind::Missing => unreachable!(), ast::PatKind::Rest | ast::PatKind::Never | ast::PatKind::Wild | ast::PatKind::Err(_) => { true } @@ -100,6 +101,7 @@ impl Rewrite for Pat { fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult { match self.kind { + PatKind::Missing => unreachable!(), PatKind::Or(ref pats) => { let pat_strs = pats .iter() diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 682ab4875a12..dd7f9c6b146a 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -132,15 +132,16 @@ const EXCEPTIONS_CARGO: ExceptionList = &[ ("fiat-crypto", "MIT OR Apache-2.0 OR BSD-1-Clause"), ("foldhash", "Zlib"), ("im-rc", "MPL-2.0+"), + ("libz-rs-sys", "Zlib"), ("normalize-line-endings", "Apache-2.0"), ("openssl", "Apache-2.0"), ("ryu", "Apache-2.0 OR BSL-1.0"), // BSL is not acceptble, but we use it under Apache-2.0 - ("sha1_smol", "BSD-3-Clause"), ("similar", "Apache-2.0"), ("sized-chunks", "MPL-2.0+"), ("subtle", "BSD-3-Clause"), ("supports-hyperlinks", "Apache-2.0"), ("unicode-bom", "Apache-2.0"), + ("zlib-rs", "Zlib"), // tidy-alphabetical-end ]; @@ -164,7 +165,6 @@ const EXCEPTIONS_RUSTC_PERF: ExceptionList = &[ ("brotli-decompressor", "BSD-3-Clause/MIT"), ("encoding_rs", "(Apache-2.0 OR MIT) AND BSD-3-Clause"), ("inferno", "CDDL-1.0"), - ("instant", "BSD-3-Clause"), ("ring", NON_STANDARD_LICENSE), // see EXCEPTIONS_NON_STANDARD_LICENSE_DEPS for more. ("ryu", "Apache-2.0 OR BSL-1.0"), ("snap", "BSD-3-Clause"), @@ -260,7 +260,6 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "constant_time_eq", "cpufeatures", "crc32fast", - "crossbeam-channel", "crossbeam-deque", "crossbeam-epoch", "crossbeam-utils", @@ -270,7 +269,6 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "darling_core", "darling_macro", "datafrog", - "deranged", "derive-where", "derive_setters", "digest", @@ -296,7 +294,6 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "gimli", "gsgdt", "hashbrown", - "hermit-abi", "icu_list", "icu_list_data", "icu_locid", @@ -311,6 +308,8 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "intl_pluralrules", "itertools", "itoa", + "jiff", + "jiff-static", "jobserver", "lazy_static", "leb128", @@ -328,8 +327,6 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "miniz_oxide", "nix", "nu-ansi-term", - "num-conv", - "num_cpus", "object", "odht", "once_cell", @@ -341,7 +338,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "pin-project-lite", "polonius-engine", "portable-atomic", // dependency for platforms doesn't support `AtomicU64` in std - "powerfmt", + "portable-atomic-util", "ppv-lite86", "proc-macro-hack", "proc-macro2", @@ -362,7 +359,6 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "rustc-demangle", "rustc-hash", "rustc-literal-escaper", - "rustc-rayon", "rustc-rayon-core", "rustc-stable-hash", "rustc_apfloat", @@ -395,9 +391,6 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "thorin-dwp", "thread_local", "tikv-jemalloc-sys", - "time", - "time-core", - "time-macros", "tinystr", "tinyvec", "tinyvec_macros", @@ -687,8 +680,10 @@ pub static CRATES: &[&str] = &[ pub fn has_missing_submodule(root: &Path, submodules: &[&str]) -> bool { !CiEnv::is_ci() && submodules.iter().any(|submodule| { + let path = root.join(submodule); + !path.exists() // If the directory is empty, we can consider it as an uninitialized submodule. - read_dir(root.join(submodule)).unwrap().next().is_none() + || read_dir(path).unwrap().next().is_none() }) } diff --git a/tests/assembly/auxiliary/dwarf-mixed-versions-lto-aux.rs b/tests/assembly/auxiliary/dwarf-mixed-versions-lto-aux.rs index faff6e7e2d05..257608f881f1 100644 --- a/tests/assembly/auxiliary/dwarf-mixed-versions-lto-aux.rs +++ b/tests/assembly/auxiliary/dwarf-mixed-versions-lto-aux.rs @@ -1,4 +1,4 @@ -//@ compile-flags: -g --crate-type=rlib -Zdwarf-version=4 +//@ compile-flags: -g --crate-type=rlib -Cdwarf-version=4 pub fn check_is_even(number: &u64) -> bool { number % 2 == 0 diff --git a/tests/assembly/cstring-merging.rs b/tests/assembly/cstring-merging.rs index 7436e2418230..f7d0775f7aff 100644 --- a/tests/assembly/cstring-merging.rs +++ b/tests/assembly/cstring-merging.rs @@ -1,17 +1,20 @@ +// MIPS assembler uses the label prefix `$anon.` for local anonymous variables +// other architectures (including ARM and x86-64) use the prefix `.Lanon.` //@ only-linux //@ assembly-output: emit-asm -//@ compile-flags: --crate-type=lib -Copt-level=3 --edition 2024 +//@ compile-flags: --crate-type=lib -Copt-level=3 +//@ edition: 2024 use std::ffi::CStr; -// CHECK: .section .rodata.str1.1,"aMS" -// CHECK: .Lanon.{{.+}}: +// CHECK: .section .rodata.str1.{{[12]}},"aMS" +// CHECK: {{(\.L|\$)}}anon.{{.+}}: // CHECK-NEXT: .asciz "foo" #[unsafe(no_mangle)] static CSTR: &[u8; 4] = b"foo\0"; // CHECK-NOT: .section -// CHECK: .Lanon.{{.+}}: +// CHECK: {{(\.L|\$)}}anon.{{.+}}: // CHECK-NEXT: .asciz "bar" #[unsafe(no_mangle)] pub fn cstr() -> &'static CStr { @@ -19,7 +22,7 @@ pub fn cstr() -> &'static CStr { } // CHECK-NOT: .section -// CHECK: .Lanon.{{.+}}: +// CHECK: {{(\.L|\$)}}anon.{{.+}}: // CHECK-NEXT: .asciz "baz" #[unsafe(no_mangle)] pub fn manual_cstr() -> &'static str { diff --git a/tests/assembly/dwarf-mixed-versions-lto.rs b/tests/assembly/dwarf-mixed-versions-lto.rs index f1fc0814c9db..9910a6e2f5fc 100644 --- a/tests/assembly/dwarf-mixed-versions-lto.rs +++ b/tests/assembly/dwarf-mixed-versions-lto.rs @@ -4,7 +4,7 @@ //@ only-linux //@ aux-build:dwarf-mixed-versions-lto-aux.rs -//@ compile-flags: -C lto -g -Zdwarf-version=5 +//@ compile-flags: -C lto -g -Cdwarf-version=5 //@ assembly-output: emit-asm //@ no-prefer-dynamic diff --git a/tests/assembly/dwarf4.rs b/tests/assembly/dwarf4.rs index 6013adf3386a..03a388603b44 100644 --- a/tests/assembly/dwarf4.rs +++ b/tests/assembly/dwarf4.rs @@ -1,7 +1,7 @@ -// Makes sure that `-Z dwarf-version=4` causes `rustc` to emit DWARF version 4. +// Makes sure that `-C dwarf-version=4` causes `rustc` to emit DWARF version 4. //@ assembly-output: emit-asm //@ add-core-stubs -//@ compile-flags: -g --target x86_64-unknown-linux-gnu -Z dwarf-version=4 -Copt-level=0 +//@ compile-flags: -g --target x86_64-unknown-linux-gnu -C dwarf-version=4 -Copt-level=0 //@ needs-llvm-components: x86 #![feature(no_core, lang_items)] diff --git a/tests/assembly/dwarf5.rs b/tests/assembly/dwarf5.rs index 9cd596e78345..9bd92cc0d097 100644 --- a/tests/assembly/dwarf5.rs +++ b/tests/assembly/dwarf5.rs @@ -1,7 +1,7 @@ -// Makes sure that `-Z dwarf-version=5` causes `rustc` to emit DWARF version 5. +// Makes sure that `-C dwarf-version=5` causes `rustc` to emit DWARF version 5. //@ add-core-stubs //@ assembly-output: emit-asm -//@ compile-flags: -g --target x86_64-unknown-linux-gnu -Z dwarf-version=5 -Copt-level=0 +//@ compile-flags: -g --target x86_64-unknown-linux-gnu -C dwarf-version=5 -Copt-level=0 //@ needs-llvm-components: x86 #![feature(no_core, lang_items)] diff --git a/tests/assembly/simd-bitmask.rs b/tests/assembly/simd-bitmask.rs index a632791153b2..e41224610870 100644 --- a/tests/assembly/simd-bitmask.rs +++ b/tests/assembly/simd-bitmask.rs @@ -35,9 +35,8 @@ pub struct m64x2([i64; 2]); #[repr(simd)] pub struct m64x4([i64; 4]); -extern "rust-intrinsic" { - fn simd_bitmask(mask: V) -> B; -} +#[rustc_intrinsic] +unsafe fn simd_bitmask(mask: V) -> B; // CHECK-LABEL: bitmask_m8x16 #[no_mangle] diff --git a/tests/assembly/simd-intrinsic-gather.rs b/tests/assembly/simd-intrinsic-gather.rs index 8c17a58046d8..bcab0ba1cc09 100644 --- a/tests/assembly/simd-intrinsic-gather.rs +++ b/tests/assembly/simd-intrinsic-gather.rs @@ -22,9 +22,8 @@ pub struct m64x4([i64; 4]); #[repr(simd)] pub struct pf64x4([*const f64; 4]); -extern "rust-intrinsic" { - fn simd_gather(values: V, mask: M, pointer: P) -> V; -} +#[rustc_intrinsic] +unsafe fn simd_gather(values: V, mask: M, pointer: P) -> V; // CHECK-LABEL: gather_f64x4 #[no_mangle] diff --git a/tests/assembly/simd-intrinsic-mask-load.rs b/tests/assembly/simd-intrinsic-mask-load.rs index a0d0514c0141..d3f3453a780a 100644 --- a/tests/assembly/simd-intrinsic-mask-load.rs +++ b/tests/assembly/simd-intrinsic-mask-load.rs @@ -34,9 +34,8 @@ pub struct f64x4([f64; 4]); #[repr(simd)] pub struct m64x4([i64; 4]); -extern "rust-intrinsic" { - fn simd_masked_load(mask: M, pointer: P, values: T) -> T; -} +#[rustc_intrinsic] +unsafe fn simd_masked_load(mask: M, pointer: P, values: T) -> T; // CHECK-LABEL: load_i8x16 #[no_mangle] diff --git a/tests/assembly/simd-intrinsic-mask-reduce.rs b/tests/assembly/simd-intrinsic-mask-reduce.rs index 959c4ddefdb0..8b15ed0a254c 100644 --- a/tests/assembly/simd-intrinsic-mask-reduce.rs +++ b/tests/assembly/simd-intrinsic-mask-reduce.rs @@ -20,10 +20,10 @@ use minicore::*; #[repr(simd)] pub struct mask8x16([i8; 16]); -extern "rust-intrinsic" { - fn simd_reduce_all(x: T) -> bool; - fn simd_reduce_any(x: T) -> bool; -} +#[rustc_intrinsic] +unsafe fn simd_reduce_all(x: T) -> bool; +#[rustc_intrinsic] +unsafe fn simd_reduce_any(x: T) -> bool; // CHECK-LABEL: mask_reduce_all: #[no_mangle] diff --git a/tests/assembly/simd-intrinsic-mask-store.rs b/tests/assembly/simd-intrinsic-mask-store.rs index 4be9194943c7..001762e5060d 100644 --- a/tests/assembly/simd-intrinsic-mask-store.rs +++ b/tests/assembly/simd-intrinsic-mask-store.rs @@ -34,9 +34,8 @@ pub struct f64x4([f64; 4]); #[repr(simd)] pub struct m64x4([i64; 4]); -extern "rust-intrinsic" { - fn simd_masked_store(mask: M, pointer: P, values: T); -} +#[rustc_intrinsic] +unsafe fn simd_masked_store(mask: M, pointer: P, values: T); // CHECK-LABEL: store_i8x16 #[no_mangle] diff --git a/tests/assembly/simd-intrinsic-scatter.rs b/tests/assembly/simd-intrinsic-scatter.rs index 715de04af4d7..d77dfad3546d 100644 --- a/tests/assembly/simd-intrinsic-scatter.rs +++ b/tests/assembly/simd-intrinsic-scatter.rs @@ -22,9 +22,8 @@ pub struct m64x4([i64; 4]); #[repr(simd)] pub struct pf64x4([*mut f64; 4]); -extern "rust-intrinsic" { - fn simd_scatter(values: V, pointer: P, mask: M); -} +#[rustc_intrinsic] +unsafe fn simd_scatter(values: V, pointer: P, mask: M); // CHECK-LABEL: scatter_f64x4 #[no_mangle] diff --git a/tests/assembly/simd-intrinsic-select.rs b/tests/assembly/simd-intrinsic-select.rs index 7f1e42662bfb..4f8d6b825b61 100644 --- a/tests/assembly/simd-intrinsic-select.rs +++ b/tests/assembly/simd-intrinsic-select.rs @@ -48,9 +48,8 @@ pub struct f64x8([f64; 8]); #[repr(simd)] pub struct m64x8([i64; 8]); -extern "rust-intrinsic" { - fn simd_select(mask: M, a: V, b: V) -> V; -} +#[rustc_intrinsic] +unsafe fn simd_select(mask: M, a: V, b: V) -> V; // CHECK-LABEL: select_i8x16 #[no_mangle] diff --git a/tests/assembly/targets/targets-elf.rs b/tests/assembly/targets/targets-elf.rs index 8f2fef0e9c91..325559111949 100644 --- a/tests/assembly/targets/targets-elf.rs +++ b/tests/assembly/targets/targets-elf.rs @@ -571,6 +571,9 @@ //@ revisions: x86_64_linux_android //@ [x86_64_linux_android] compile-flags: --target x86_64-linux-android //@ [x86_64_linux_android] needs-llvm-components: x86 +//@ revisions: x86_64_lynx_lynxos178 +//@ [x86_64_lynx_lynxos178] compile-flags: --target x86_64-lynx-lynxos178 +//@ [x86_64_lynx_lynxos178] needs-llvm-components: x86 //@ revisions: x86_64_pc_nto_qnx710 //@ [x86_64_pc_nto_qnx710] compile-flags: --target x86_64-pc-nto-qnx710 //@ [x86_64_pc_nto_qnx710] needs-llvm-components: x86 diff --git a/tests/assembly/x86_64-typed-swap.rs b/tests/assembly/x86_64-typed-swap.rs index dfd6ee565bcc..a6753011d362 100644 --- a/tests/assembly/x86_64-typed-swap.rs +++ b/tests/assembly/x86_64-typed-swap.rs @@ -51,3 +51,31 @@ pub fn swap_simd(x: &mut __m128, y: &mut __m128) { // CHECK-NEXT: retq swap(x, y) } + +// CHECK-LABEL: swap_string: +#[no_mangle] +pub fn swap_string(x: &mut String, y: &mut String) { + // CHECK-NOT: mov + // CHECK-COUNT-4: movups + // CHECK-NOT: mov + // CHECK-COUNT-4: movq + // CHECK-NOT: mov + swap(x, y) +} + +// CHECK-LABEL: swap_44_bytes: +#[no_mangle] +pub fn swap_44_bytes(x: &mut [u8; 44], y: &mut [u8; 44]) { + // Ensure we do better than a long run of byte copies, + // see + + // CHECK-NOT: movb + // CHECK-COUNT-8: movups{{.+}}xmm + // CHECK-NOT: movb + // CHECK-COUNT-4: movq + // CHECK-NOT: movb + // CHECK-COUNT-4: movl + // CHECK-NOT: movb + // CHECK: retq + swap(x, y) +} diff --git a/tests/assembly/x86_64-windows-float-abi.rs b/tests/assembly/x86_64-windows-float-abi.rs index e8900be1aaee..cbc809108511 100644 --- a/tests/assembly/x86_64-windows-float-abi.rs +++ b/tests/assembly/x86_64-windows-float-abi.rs @@ -37,7 +37,8 @@ pub extern "C" fn second_f64(_: f64, x: f64) -> f64 { } // CHECK-LABEL: second_f128 -// CHECK: movaps %xmm1, %xmm0 +// FIXME(llvm21): this can be just %rdx instead of the regex once we don't test on LLVM 20 +// CHECK: movaps {{(%xmm1|\(%rdx\))}}, %xmm0 // CHECK-NEXT: retq #[no_mangle] pub extern "C" fn second_f128(_: f128, x: f128) -> f128 { diff --git a/tests/codegen/align-fn.rs b/tests/codegen/align-fn.rs index 97f23cc04230..660d8cd2bbf4 100644 --- a/tests/codegen/align-fn.rs +++ b/tests/codegen/align-fn.rs @@ -47,3 +47,22 @@ impl T for () {} pub fn foo() { ().trait_method(); } + +// CHECK-LABEL: align_specified_twice_1 +// CHECK-SAME: align 64 +#[no_mangle] +#[repr(align(32), align(64))] +pub fn align_specified_twice_1() {} + +// CHECK-LABEL: align_specified_twice_2 +// CHECK-SAME: align 128 +#[no_mangle] +#[repr(align(128), align(32))] +pub fn align_specified_twice_2() {} + +// CHECK-LABEL: align_specified_twice_3 +// CHECK-SAME: align 256 +#[no_mangle] +#[repr(align(32))] +#[repr(align(256))] +pub fn align_specified_twice_3() {} diff --git a/tests/codegen/array-cmp.rs b/tests/codegen/array-cmp.rs index 2565a385b61b..0d3376554017 100644 --- a/tests/codegen/array-cmp.rs +++ b/tests/codegen/array-cmp.rs @@ -1,6 +1,7 @@ // Ensure the asm for array comparisons is properly optimized. //@ compile-flags: -C opt-level=2 +//@ needs-deterministic-layouts (checks depend on tuple layout) #![crate_type = "lib"] @@ -17,3 +18,57 @@ pub fn compare() -> bool { [0x00, 0x00, 0x48, 0x41] } } + +// CHECK-LABEL: @array_of_tuple_le +#[no_mangle] +pub fn array_of_tuple_le(a: &[(i16, u16); 2], b: &[(i16, u16); 2]) -> bool { + // Ensure that, after all the optimizations have run, the happy path just checks + // `eq` on each corresponding pair and moves onto the next one if it is. + // Then there's a dedup'd comparison for the place that's different. + // (As opposed to, say, running a full `[su]cmp` as part of checking equality.) + + // This is written quite specifically because different library code was triggering + // along the way, so this + // has enough checks to make sure that's not happening. It doesn't need to be + // *exactly* this IR, but be careful if you ever need to update these checks. + + // CHECK: start: + // CHECK: %[[A00:.+]] = load i16, ptr %a + // CHECK: %[[B00:.+]] = load i16, ptr %b + // CHECK-NOT: cmp + // CHECK: %[[EQ00:.+]] = icmp eq i16 %[[A00]], %[[B00]] + // CHECK-NEXT: br i1 %[[EQ00]], label %[[L01:.+]], label %[[EXIT_S:.+]] + + // CHECK: [[L01]]: + // CHECK: %[[PA01:.+]] = getelementptr{{.+}}i8, ptr %a, {{i32|i64}} 2 + // CHECK: %[[PB01:.+]] = getelementptr{{.+}}i8, ptr %b, {{i32|i64}} 2 + // CHECK: %[[A01:.+]] = load i16, ptr %[[PA01]] + // CHECK: %[[B01:.+]] = load i16, ptr %[[PB01]] + // CHECK-NOT: cmp + // CHECK: %[[EQ01:.+]] = icmp eq i16 %[[A01]], %[[B01]] + // CHECK-NEXT: br i1 %[[EQ01]], label %[[L10:.+]], label %[[EXIT_U:.+]] + + // CHECK: [[L10]]: + // CHECK: %[[PA10:.+]] = getelementptr{{.+}}i8, ptr %a, {{i32|i64}} 4 + // CHECK: %[[PB10:.+]] = getelementptr{{.+}}i8, ptr %b, {{i32|i64}} 4 + // CHECK: %[[A10:.+]] = load i16, ptr %[[PA10]] + // CHECK: %[[B10:.+]] = load i16, ptr %[[PB10]] + // CHECK-NOT: cmp + // CHECK: %[[EQ10:.+]] = icmp eq i16 %[[A10]], %[[B10]] + // CHECK-NEXT: br i1 %[[EQ10]], label %[[L11:.+]], label %[[EXIT_S]] + + // CHECK: [[L11]]: + // CHECK: %[[PA11:.+]] = getelementptr{{.+}}i8, ptr %a, {{i32|i64}} 6 + // CHECK: %[[PB11:.+]] = getelementptr{{.+}}i8, ptr %b, {{i32|i64}} 6 + // CHECK: %[[A11:.+]] = load i16, ptr %[[PA11]] + // CHECK: %[[B11:.+]] = load i16, ptr %[[PB11]] + // CHECK-NOT: cmp + // CHECK: %[[EQ11:.+]] = icmp eq i16 %[[A11]], %[[B11]] + // CHECK-NEXT: br i1 %[[EQ11]], label %[[DONE:.+]], label %[[EXIT_U]] + + // CHECK: [[DONE]]: + // CHECK: %[[RET:.+]] = phi i1 [ %{{.+}}, %[[EXIT_S]] ], [ %{{.+}}, %[[EXIT_U]] ], [ true, %[[L11]] ] + // CHECK: ret i1 %[[RET]] + + a <= b +} diff --git a/tests/codegen/async-closure-debug.rs b/tests/codegen/async-closure-debug.rs index 2d67e02eb9ca..b5b369e6e54b 100644 --- a/tests/codegen/async-closure-debug.rs +++ b/tests/codegen/async-closure-debug.rs @@ -1,6 +1,7 @@ // Just make sure that async closures don't ICE. // -//@ compile-flags: -C debuginfo=2 --edition=2018 +//@ compile-flags: -C debuginfo=2 +//@ edition: 2018 //@ ignore-msvc // CHECK-DAG: [[GEN_FN:!.*]] = !DINamespace(name: "async_closure_test" diff --git a/tests/codegen/async-fn-debug-awaitee-field.rs b/tests/codegen/async-fn-debug-awaitee-field.rs index ab13d4509e2e..50860c90662a 100644 --- a/tests/codegen/async-fn-debug-awaitee-field.rs +++ b/tests/codegen/async-fn-debug-awaitee-field.rs @@ -7,7 +7,8 @@ //@[MSVC] only-msvc //@[NONMSVC] ignore-msvc -//@ compile-flags: -C debuginfo=2 --edition=2018 -Copt-level=0 +//@ compile-flags: -C debuginfo=2 -Copt-level=0 +//@ edition: 2018 #![crate_type = "lib"] diff --git a/tests/codegen/async-fn-debug-msvc.rs b/tests/codegen/async-fn-debug-msvc.rs index 7c695042b425..e0c601146f81 100644 --- a/tests/codegen/async-fn-debug-msvc.rs +++ b/tests/codegen/async-fn-debug-msvc.rs @@ -4,7 +4,8 @@ // - Other fields are not marked artificial // // -//@ compile-flags: -C debuginfo=2 --edition=2018 +//@ compile-flags: -C debuginfo=2 +//@ edition: 2018 //@ only-msvc async fn foo() {} @@ -19,23 +20,23 @@ async fn async_fn_test() { // CHECK-DAG: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "enum2$", // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant0", scope: [[GEN]], // For brevity, we only check the struct name and members of the last variant. -// CHECK-SAME: file: [[FILE:![0-9]*]], line: 11, +// CHECK-SAME: file: [[FILE:![0-9]*]], line: 12, // CHECK-NOT: flags: DIFlagArtificial // CHECK-SAME: ) // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant1", scope: [[GEN]], -// CHECK-SAME: file: [[FILE]], line: 15, +// CHECK-SAME: file: [[FILE]], line: 16, // CHECK-NOT: flags: DIFlagArtificial // CHECK-SAME: ) // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant2", scope: [[GEN]], -// CHECK-SAME: file: [[FILE]], line: 15, +// CHECK-SAME: file: [[FILE]], line: 16, // CHECK-NOT: flags: DIFlagArtificial // CHECK-SAME: ) // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant3", scope: [[GEN]], -// CHECK-SAME: file: [[FILE]], line: 12, +// CHECK-SAME: file: [[FILE]], line: 13, // CHECK-NOT: flags: DIFlagArtificial // CHECK-SAME: ) // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant4", scope: [[GEN]], -// CHECK-SAME: file: [[FILE]], line: 14, +// CHECK-SAME: file: [[FILE]], line: 15, // CHECK-SAME: baseType: [[VARIANT_WRAPPER:![0-9]*]] // CHECK-NOT: flags: DIFlagArtificial // CHECK-SAME: ) diff --git a/tests/codegen/async-fn-debug.rs b/tests/codegen/async-fn-debug.rs index 7be4ad456657..ed704c7cc8b9 100644 --- a/tests/codegen/async-fn-debug.rs +++ b/tests/codegen/async-fn-debug.rs @@ -4,7 +4,8 @@ // - Other fields are not marked artificial // // -//@ compile-flags: -C debuginfo=2 --edition=2018 +//@ compile-flags: -C debuginfo=2 +//@ edition: 2018 //@ ignore-msvc async fn foo() {} @@ -22,26 +23,26 @@ async fn async_fn_test() { // CHECK-NOT: flags: DIFlagArtificial // CHECK-SAME: discriminator: [[DISC:![0-9]*]] // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "0", scope: [[VARIANT]], -// CHECK-SAME: file: [[FILE:![0-9]*]], line: 11, +// CHECK-SAME: file: [[FILE:![0-9]*]], line: 12, // CHECK-NOT: flags: DIFlagArtificial // CHECK-SAME: ) // CHECK: {{!.*}} = !DICompositeType(tag: DW_TAG_structure_type, name: "Unresumed", scope: [[GEN]], // CHECK-NOT: flags: DIFlagArtificial // CHECK-SAME: ) // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "1", scope: [[VARIANT]], -// CHECK-SAME: file: [[FILE]], line: 15, +// CHECK-SAME: file: [[FILE]], line: 16, // CHECK-NOT: flags: DIFlagArtificial // CHECK-SAME: ) // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "2", scope: [[VARIANT]], -// CHECK-SAME: file: [[FILE]], line: 15, +// CHECK-SAME: file: [[FILE]], line: 16, // CHECK-NOT: flags: DIFlagArtificial // CHECK-SAME: ) // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "3", scope: [[VARIANT]], -// CHECK-SAME: file: [[FILE]], line: 12, +// CHECK-SAME: file: [[FILE]], line: 13, // CHECK-NOT: flags: DIFlagArtificial // CHECK-SAME: ) // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "4", scope: [[VARIANT]], -// CHECK-SAME: file: [[FILE]], line: 14, +// CHECK-SAME: file: [[FILE]], line: 15, // CHECK-NOT: flags: DIFlagArtificial // CHECK-SAME: ) // CHECK: [[S1:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend1", scope: [[GEN]], diff --git a/tests/codegen/autodiffv.rs b/tests/codegen/autodiff/batched.rs similarity index 100% rename from tests/codegen/autodiffv.rs rename to tests/codegen/autodiff/batched.rs diff --git a/tests/codegen/autodiff.rs b/tests/codegen/autodiff/scalar.rs similarity index 100% rename from tests/codegen/autodiff.rs rename to tests/codegen/autodiff/scalar.rs diff --git a/tests/codegen/autodiff/sret.rs b/tests/codegen/autodiff/sret.rs new file mode 100644 index 000000000000..5ead90041edc --- /dev/null +++ b/tests/codegen/autodiff/sret.rs @@ -0,0 +1,45 @@ +//@ compile-flags: -Zautodiff=Enable -C opt-level=3 -Clto=fat +//@ no-prefer-dynamic +//@ needs-enzyme + +// This test is almost identical to the scalar.rs one, +// but we intentionally add a few more floats. +// `df` would ret `{ f64, f32, f32 }`, but is lowered as an sret. +// We therefore use this test to verify some of our sret handling. + +#![feature(autodiff)] + +use std::autodiff::autodiff; + +#[no_mangle] +#[autodiff(df, Reverse, Active, Active, Active)] +fn primal(x: f32, y: f32) -> f64 { + (x * x * y) as f64 +} + +// CHECK:define internal fastcc void @_ZN4sret2df17h93be4316dd8ea006E(ptr dead_on_unwind noalias nocapture noundef nonnull writable writeonly align 8 dereferenceable(16) initializes((0, 16)) %_0, float noundef %x, float noundef %y) +// CHECK-NEXT:start: +// CHECK-NEXT: %0 = tail call fastcc { double, float, float } @diffeprimal(float %x, float %y) +// CHECK-NEXT: %.elt = extractvalue { double, float, float } %0, 0 +// CHECK-NEXT: store double %.elt, ptr %_0, align 8 +// CHECK-NEXT: %_0.repack1 = getelementptr inbounds nuw i8, ptr %_0, i64 8 +// CHECK-NEXT: %.elt2 = extractvalue { double, float, float } %0, 1 +// CHECK-NEXT: store float %.elt2, ptr %_0.repack1, align 8 +// CHECK-NEXT: %_0.repack3 = getelementptr inbounds nuw i8, ptr %_0, i64 12 +// CHECK-NEXT: %.elt4 = extractvalue { double, float, float } %0, 2 +// CHECK-NEXT: store float %.elt4, ptr %_0.repack3, align 4 +// CHECK-NEXT: ret void +// CHECK-NEXT:} + +fn main() { + let x = std::hint::black_box(3.0); + let y = std::hint::black_box(2.5); + let scalar = std::hint::black_box(1.0); + let (r1, r2, r3) = df(x, y, scalar); + // 3*3*1.5 = 22.5 + assert_eq!(r1, 22.5); + // 2*x*y = 2*3*2.5 = 15.0 + assert_eq!(r2, 15.0); + // x*x*1 = 3*3 = 9 + assert_eq!(r3, 9.0); +} diff --git a/tests/codegen/autodiffv2.rs b/tests/codegen/autodiffv2.rs new file mode 100644 index 000000000000..a40d19d3be3a --- /dev/null +++ b/tests/codegen/autodiffv2.rs @@ -0,0 +1,113 @@ +//@ compile-flags: -Zautodiff=Enable -C opt-level=3 -Clto=fat +//@ no-prefer-dynamic +//@ needs-enzyme +// +// In Enzyme, we test against a large range of LLVM versions (5+) and don't have overly many +// breakages. One benefit is that we match the IR generated by Enzyme only after running it +// through LLVM's O3 pipeline, which will remove most of the noise. +// However, our integration test could also be affected by changes in how rustc lowers MIR into +// LLVM-IR, which could cause additional noise and thus breakages. If that's the case, we should +// reduce this test to only match the first lines and the ret instructions. +// +// The function tested here has 4 inputs and 5 outputs, so we could either call forward-mode +// autodiff 4 times, or reverse mode 5 times. Since a forward-mode call is usually faster than +// reverse mode, we prefer it here. This file also tests a new optimization (batch mode), which +// allows us to call forward-mode autodiff only once, and get all 5 outputs in a single call. +// +// We support 2 different batch modes. `d_square2` has the same interface as scalar forward-mode, +// but each shadow argument is `width` times larger (thus 16 and 20 elements here). +// `d_square3` instead takes `width` (4) shadow arguments, which are all the same size as the +// original function arguments. +// +// FIXME(autodiff): We currently can't test `d_square1` and `d_square3` in the same file, since they +// generate the same dummy functions which get merged by LLVM, breaking pieces of our pipeline which +// try to rewrite the dummy functions later. We should consider to change to pure declarations both +// in our frontend and in the llvm backend to avoid these issues. + +#![feature(autodiff)] + +use std::autodiff::autodiff; + +#[no_mangle] +//#[autodiff(d_square1, Forward, Dual, Dual)] +#[autodiff(d_square2, Forward, 4, Dualv, Dualv)] +#[autodiff(d_square3, Forward, 4, Dual, Dual)] +fn square(x: &[f32], y: &mut [f32]) { + assert!(x.len() >= 4); + assert!(y.len() >= 5); + y[0] = 4.3 * x[0] + 1.2 * x[1] + 3.4 * x[2] + 2.1 * x[3]; + y[1] = 2.3 * x[0] + 4.5 * x[1] + 1.7 * x[2] + 6.4 * x[3]; + y[2] = 1.1 * x[0] + 3.3 * x[1] + 2.5 * x[2] + 4.7 * x[3]; + y[3] = 5.2 * x[0] + 1.4 * x[1] + 2.6 * x[2] + 3.8 * x[3]; + y[4] = 1.0 * x[0] + 2.0 * x[1] + 3.0 * x[2] + 4.0 * x[3]; +} + +fn main() { + let x1 = std::hint::black_box(vec![0.0, 1.0, 2.0, 3.0]); + + let dx1 = std::hint::black_box(vec![1.0; 12]); + + let z1 = std::hint::black_box(vec![1.0, 0.0, 0.0, 0.0]); + let z2 = std::hint::black_box(vec![0.0, 1.0, 0.0, 0.0]); + let z3 = std::hint::black_box(vec![0.0, 0.0, 1.0, 0.0]); + let z4 = std::hint::black_box(vec![0.0, 0.0, 0.0, 1.0]); + + let z5 = std::hint::black_box(vec![ + 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, + ]); + + let mut y1 = std::hint::black_box(vec![0.0; 5]); + let mut y2 = std::hint::black_box(vec![0.0; 5]); + let mut y3 = std::hint::black_box(vec![0.0; 5]); + let mut y4 = std::hint::black_box(vec![0.0; 5]); + + let mut y5 = std::hint::black_box(vec![0.0; 5]); + + let mut y6 = std::hint::black_box(vec![0.0; 5]); + + let mut dy1_1 = std::hint::black_box(vec![0.0; 5]); + let mut dy1_2 = std::hint::black_box(vec![0.0; 5]); + let mut dy1_3 = std::hint::black_box(vec![0.0; 5]); + let mut dy1_4 = std::hint::black_box(vec![0.0; 5]); + + let mut dy2 = std::hint::black_box(vec![0.0; 20]); + + let mut dy3_1 = std::hint::black_box(vec![0.0; 5]); + let mut dy3_2 = std::hint::black_box(vec![0.0; 5]); + let mut dy3_3 = std::hint::black_box(vec![0.0; 5]); + let mut dy3_4 = std::hint::black_box(vec![0.0; 5]); + + // scalar. + //d_square1(&x1, &z1, &mut y1, &mut dy1_1); + //d_square1(&x1, &z2, &mut y2, &mut dy1_2); + //d_square1(&x1, &z3, &mut y3, &mut dy1_3); + //d_square1(&x1, &z4, &mut y4, &mut dy1_4); + + // assert y1 == y2 == y3 == y4 + //for i in 0..5 { + // assert_eq!(y1[i], y2[i]); + // assert_eq!(y1[i], y3[i]); + // assert_eq!(y1[i], y4[i]); + //} + + // batch mode A) + d_square2(&x1, &z5, &mut y5, &mut dy2); + + // assert y1 == y2 == y3 == y4 == y5 + //for i in 0..5 { + // assert_eq!(y1[i], y5[i]); + //} + + // batch mode B) + d_square3(&x1, &z1, &z2, &z3, &z4, &mut y6, &mut dy3_1, &mut dy3_2, &mut dy3_3, &mut dy3_4); + for i in 0..5 { + assert_eq!(y5[i], y6[i]); + } + + for i in 0..5 { + assert_eq!(dy2[0..5][i], dy3_1[i]); + assert_eq!(dy2[5..10][i], dy3_2[i]); + assert_eq!(dy2[10..15][i], dy3_3[i]); + assert_eq!(dy2[15..20][i], dy3_4[i]); + } +} diff --git a/tests/codegen/avr/avr-func-addrspace.rs b/tests/codegen/avr/avr-func-addrspace.rs index 2ae2f40d7b34..e0192f8b45ab 100644 --- a/tests/codegen/avr/avr-func-addrspace.rs +++ b/tests/codegen/avr/avr-func-addrspace.rs @@ -17,9 +17,8 @@ extern crate minicore; use minicore::*; -extern "rust-intrinsic" { - pub fn transmute(src: Src) -> Dst; -} +#[rustc_intrinsic] +pub unsafe fn transmute(src: Src) -> Dst; pub static mut STORAGE_FOO: fn(&usize, &mut u32) -> Result<(), ()> = arbitrary_black_box; pub static mut STORAGE_BAR: u32 = 12; diff --git a/tests/codegen/cffi/ffi-const.rs b/tests/codegen/cffi/ffi-const.rs index 6c90902e89fe..3ea9d517ec25 100644 --- a/tests/codegen/cffi/ffi-const.rs +++ b/tests/codegen/cffi/ffi-const.rs @@ -10,6 +10,6 @@ extern "C" { // CHECK-LABEL: declare{{.*}}void @foo() // CHECK-SAME: [[ATTRS:#[0-9]+]] // CHECK-DAG: attributes [[ATTRS]] = { {{.*}}memory(none){{.*}} } - #[ffi_const] + #[unsafe(ffi_const)] pub fn foo(); } diff --git a/tests/codegen/cffi/ffi-pure.rs b/tests/codegen/cffi/ffi-pure.rs index 2c5d5f5b4b12..a61e80ecf652 100644 --- a/tests/codegen/cffi/ffi-pure.rs +++ b/tests/codegen/cffi/ffi-pure.rs @@ -10,6 +10,6 @@ extern "C" { // CHECK-LABEL: declare{{.*}}void @foo() // CHECK-SAME: [[ATTRS:#[0-9]+]] // CHECK-DAG: attributes [[ATTRS]] = { {{.*}}memory(read){{.*}} } - #[ffi_pure] + #[unsafe(ffi_pure)] pub fn foo(); } diff --git a/tests/codegen/coroutine-debug.rs b/tests/codegen/coroutine-debug.rs index d00667a37d5e..ff62e9709b4b 100644 --- a/tests/codegen/coroutine-debug.rs +++ b/tests/codegen/coroutine-debug.rs @@ -4,7 +4,8 @@ // - Other fields are not marked artificial // // -//@ compile-flags: -C debuginfo=2 --edition=2018 +//@ compile-flags: -C debuginfo=2 +//@ edition: 2018 //@ ignore-msvc #![feature(coroutines, coroutine_trait)] @@ -27,26 +28,26 @@ fn coroutine_test() -> impl Coroutine { // CHECK-NOT: flags: DIFlagArtificial // CHECK-SAME: discriminator: [[DISC:![0-9]*]] // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "0", scope: [[VARIANT]], -// CHECK-SAME: file: [[FILE:![0-9]*]], line: 15, +// CHECK-SAME: file: [[FILE:![0-9]*]], line: 16, // CHECK-NOT: flags: DIFlagArtificial // CHECK-SAME: ) // CHECK: {{!.*}} = !DICompositeType(tag: DW_TAG_structure_type, name: "Unresumed", scope: [[GEN]], // CHECK-NOT: flags: DIFlagArtificial // CHECK-SAME: ) // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "1", scope: [[VARIANT]], -// CHECK-SAME: file: [[FILE]], line: 19, +// CHECK-SAME: file: [[FILE]], line: 20, // CHECK-NOT: flags: DIFlagArtificial // CHECK-SAME: ) // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "2", scope: [[VARIANT]], -// CHECK-SAME: file: [[FILE]], line: 19, +// CHECK-SAME: file: [[FILE]], line: 20, // CHECK-NOT: flags: DIFlagArtificial // CHECK-SAME: ) // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "3", scope: [[VARIANT]], -// CHECK-SAME: file: [[FILE]], line: 16, +// CHECK-SAME: file: [[FILE]], line: 17, // CHECK-NOT: flags: DIFlagArtificial // CHECK-SAME: ) // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "4", scope: [[VARIANT]], -// CHECK-SAME: file: [[FILE]], line: 18, +// CHECK-SAME: file: [[FILE]], line: 19, // CHECK-NOT: flags: DIFlagArtificial // CHECK-SAME: ) // CHECK: [[S1:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend1", scope: [[GEN]], diff --git a/tests/codegen/debuginfo-generic-closure-env-names.rs b/tests/codegen/debuginfo-generic-closure-env-names.rs index 6b314c9abaeb..64bc58e1df7a 100644 --- a/tests/codegen/debuginfo-generic-closure-env-names.rs +++ b/tests/codegen/debuginfo-generic-closure-env-names.rs @@ -18,7 +18,8 @@ // legacy mangling scheme rustc version and generic parameters are both hashed into a single part // of the name, thus randomizing item order with respect to rustc version. -//@ compile-flags: -Cdebuginfo=2 --edition 2021 -Copt-level=0 -Csymbol-mangling-version=v0 +//@ compile-flags: -Cdebuginfo=2 -Copt-level=0 -Csymbol-mangling-version=v0 +//@ edition: 2021 // non_generic_closure() // NONMSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "{closure_env#0}", scope: ![[non_generic_closure_NAMESPACE:[0-9]+]], diff --git a/tests/codegen/dont-shuffle-bswaps.rs b/tests/codegen/dont-shuffle-bswaps.rs index e100474f606f..c1dab2bc2953 100644 --- a/tests/codegen/dont-shuffle-bswaps.rs +++ b/tests/codegen/dont-shuffle-bswaps.rs @@ -1,8 +1,11 @@ -//@ revisions: OPT2 OPT3 +//@ revisions: OPT2 OPT3 OPT3_S390X //@[OPT2] compile-flags: -Copt-level=2 //@[OPT3] compile-flags: -C opt-level=3 // some targets don't do the opt we are looking for //@[OPT3] only-64bit +//@[OPT3] ignore-s390x +//@[OPT3_S390X] compile-flags: -C opt-level=3 -C target-cpu=z13 +//@[OPT3_S390X] only-s390x #![crate_type = "lib"] #![no_std] @@ -17,6 +20,10 @@ // OPT3-NEXT: call <8 x i16> @llvm.bswap // OPT3-NEXT: store <8 x i16> // OPT3-NEXT: ret void +// OPT3_S390X: load <8 x i16> +// OPT3_S390X-NEXT: call <8 x i16> @llvm.bswap +// OPT3_S390X-NEXT: store <8 x i16> +// OPT3_S390X-NEXT: ret void #[no_mangle] pub fn convert(value: [u16; 8]) -> [u8; 16] { #[cfg(target_endian = "little")] diff --git a/tests/codegen/emscripten-catch-unwind-js-eh.rs b/tests/codegen/emscripten-catch-unwind-js-eh.rs index 018ad5454fc2..3ab4b5c9c631 100644 --- a/tests/codegen/emscripten-catch-unwind-js-eh.rs +++ b/tests/codegen/emscripten-catch-unwind-js-eh.rs @@ -23,13 +23,12 @@ fn size_of() -> usize { loop {} } -extern "rust-intrinsic" { - fn catch_unwind( - try_fn: fn(_: *mut u8), - data: *mut u8, - catch_fn: fn(_: *mut u8, _: *mut u8), - ) -> i32; -} +#[rustc_intrinsic] +unsafe fn catch_unwind( + try_fn: fn(_: *mut u8), + data: *mut u8, + catch_fn: fn(_: *mut u8, _: *mut u8), +) -> i32; // CHECK-LABEL: @ptr_size #[no_mangle] diff --git a/tests/codegen/emscripten-catch-unwind-wasm-eh.rs b/tests/codegen/emscripten-catch-unwind-wasm-eh.rs index 0fc9ae96720e..d0571e4df081 100644 --- a/tests/codegen/emscripten-catch-unwind-wasm-eh.rs +++ b/tests/codegen/emscripten-catch-unwind-wasm-eh.rs @@ -21,14 +21,12 @@ impl Copy for *mut T {} fn size_of() -> usize { loop {} } - -extern "rust-intrinsic" { - fn catch_unwind( - try_fn: fn(_: *mut u8), - data: *mut u8, - catch_fn: fn(_: *mut u8, _: *mut u8), - ) -> i32; -} +#[rustc_intrinsic] +unsafe fn catch_unwind( + try_fn: fn(_: *mut u8), + data: *mut u8, + catch_fn: fn(_: *mut u8, _: *mut u8), +) -> i32; // CHECK-LABEL: @ptr_size #[no_mangle] diff --git a/tests/codegen/enum/enum-match.rs b/tests/codegen/enum/enum-match.rs index a24b98050d23..6da6ad1f078d 100644 --- a/tests/codegen/enum/enum-match.rs +++ b/tests/codegen/enum/enum-match.rs @@ -1,21 +1,26 @@ //@ compile-flags: -Copt-level=1 -//@ only-x86_64 +//@ only-64bit #![crate_type = "lib"] +#![feature(core_intrinsics)] // Check each of the 3 cases for `codegen_get_discr`. +// FIXME: once our min-bar LLVM has `range` attributes, update the various +// tests here to no longer have the `range`s and `nsw`s as optional. + // Case 0: One tagged variant. pub enum Enum0 { A(bool), B, } -// CHECK: define noundef{{( range\(i8 [0-9]+, [0-9]+\))?}} i8 @match0{{.*}} +// CHECK-LABEL: define{{( dso_local)?}} noundef{{( range\(i8 [0-9]+, [0-9]+\))?}} i8 @match0(i8{{.+}}%0) // CHECK-NEXT: start: -// CHECK-NEXT: %1 = icmp eq i8 %0, 2 -// CHECK-NEXT: %2 = and i8 %0, 1 -// CHECK-NEXT: %{{.+}} = select i1 %1, i8 13, i8 %2 +// CHECK-NEXT: %[[IS_B:.+]] = icmp eq i8 %0, 2 +// CHECK-NEXT: %[[TRUNC:.+]] = and i8 %0, 1 +// CHECK-NEXT: %[[R:.+]] = select i1 %[[IS_B]], i8 13, i8 %[[TRUNC]] +// CHECK-NEXT: ret i8 %[[R]] #[no_mangle] pub fn match0(e: Enum0) -> u8 { use Enum0::*; @@ -32,13 +37,14 @@ pub enum Enum1 { C, } -// CHECK: define noundef{{( range\(i8 [0-9]+, [0-9]+\))?}} i8 @match1{{.*}} +// CHECK-LABEL: define{{( dso_local)?}} noundef{{( range\(i8 [0-9]+, [0-9]+\))?}} i8 @match1(i8{{.+}}%0) // CHECK-NEXT: start: -// CHECK-NEXT: %1 = add{{( nsw)?}} i8 %0, -2 -// CHECK-NEXT: %2 = zext i8 %1 to i64 -// CHECK-NEXT: %3 = icmp ult i8 %1, 2 -// CHECK-NEXT: %4 = add nuw nsw i64 %2, 1 -// CHECK-NEXT: %_2 = select i1 %3, i64 %4, i64 0 +// CHECK-NEXT: %[[REL_VAR:.+]] = add{{( nsw)?}} i8 %0, -2 +// CHECK-NEXT: %[[REL_VAR_WIDE:.+]] = zext i8 %[[REL_VAR]] to i64 +// CHECK-NEXT: %[[IS_NICHE:.+]] = icmp ult i8 %[[REL_VAR]], 2 +// CHECK-NEXT: %[[NICHE_DISCR:.+]] = add nuw nsw i64 %[[REL_VAR_WIDE]], 1 +// CHECK-NEXT: %[[DISCR:.+]] = select i1 %[[IS_NICHE]], i64 %[[NICHE_DISCR]], i64 0 +// CHECK-NEXT: switch i64 %[[DISCR]] #[no_mangle] pub fn match1(e: Enum1) -> u8 { use Enum1::*; @@ -92,14 +98,14 @@ pub enum Enum2 { E, } -// CHECK: define noundef{{( range\(i8 [0-9]+, [0-9]+\))?}} i8 @match2{{.*}} +// CHECK-LABEL: define{{( dso_local)?}} noundef{{( range\(i8 [0-9]+, [0-9]+\))?}} i8 @match2(i8{{.+}}%0) // CHECK-NEXT: start: -// CHECK-NEXT: %1 = add i8 %0, 2 -// CHECK-NEXT: %2 = zext i8 %1 to i64 -// CHECK-NEXT: %3 = icmp ult i8 %1, 4 -// CHECK-NEXT: %4 = add nuw nsw i64 %2, 1 -// CHECK-NEXT: %_2 = select i1 %3, i64 %4, i64 0 -// CHECK-NEXT: switch i64 %_2, label {{.*}} [ +// CHECK-NEXT: %[[REL_VAR:.+]] = add i8 %0, 2 +// CHECK-NEXT: %[[REL_VAR_WIDE:.+]] = zext i8 %[[REL_VAR]] to i64 +// CHECK-NEXT: %[[IS_NICHE:.+]] = icmp ult i8 %[[REL_VAR]], 4 +// CHECK-NEXT: %[[NICHE_DISCR:.+]] = add nuw nsw i64 %[[REL_VAR_WIDE]], 1 +// CHECK-NEXT: %[[DISCR:.+]] = select i1 %[[IS_NICHE]], i64 %[[NICHE_DISCR]], i64 0 +// CHECK-NEXT: switch i64 %[[DISCR]] #[no_mangle] pub fn match2(e: Enum2) -> u8 { use Enum2::*; @@ -111,3 +117,357 @@ pub fn match2(e: Enum2) -> u8 { E => 250, } } + +// And make sure it works even if the niched scalar is a pointer. +// (For example, that we don't try to `sub` on pointers.) + +// CHECK-LABEL: define{{( dso_local)?}} noundef{{( range\(i16 -?[0-9]+, -?[0-9]+\))?}} i16 @match3(ptr{{.+}}%0) +// CHECK-NEXT: start: +// CHECK-NEXT: %[[IS_NULL:.+]] = icmp eq ptr %0, null +// CHECK-NEXT: br i1 %[[IS_NULL]] +#[no_mangle] +pub fn match3(e: Option<&u8>) -> i16 { + match e { + Some(r) => *r as _, + None => -1, + } +} + +// If the untagged variant is in the middle, there's an impossible value that's +// not reflected in the `range` parameter attribute, so we assume it away. + +#[derive(PartialEq)] +pub enum MiddleNiche { + A, + B, + C(bool), + D, + E, +} + +// CHECK-LABEL: define{{( dso_local)?}} noundef{{( range\(i8 -?[0-9]+, -?[0-9]+\))?}} i8 @match4(i8{{.+}}%0) +// CHECK-NEXT: start: +// CHECK-NEXT: %[[REL_VAR:.+]] = add{{( nsw)?}} i8 %0, -2 +// CHECK-NEXT: %[[IS_NICHE:.+]] = icmp ult i8 %[[REL_VAR]], 5 +// CHECK-NEXT: %[[NOT_IMPOSSIBLE:.+]] = icmp ne i8 %[[REL_VAR]], 2 +// CHECK-NEXT: call void @llvm.assume(i1 %[[NOT_IMPOSSIBLE]]) +// CHECK-NEXT: %[[DISCR:.+]] = select i1 %[[IS_NICHE]], i8 %[[REL_VAR]], i8 2 +// CHECK-NEXT: switch i8 %[[DISCR]] +#[no_mangle] +pub fn match4(e: MiddleNiche) -> u8 { + use MiddleNiche::*; + match e { + A => 13, + B => 100, + C(b) => b as u8, + D => 200, + E => 250, + } +} + +// CHECK-LABEL: define{{.+}}i1 @match4_is_c(i8{{.+}}%e) +// CHECK-NEXT: start +// CHECK-NEXT: %[[REL_VAR:.+]] = add{{( nsw)?}} i8 %e, -2 +// CHECK-NEXT: %[[NOT_NICHE:.+]] = icmp ugt i8 %[[REL_VAR]], 4 +// CHECK-NEXT: %[[NOT_IMPOSSIBLE:.+]] = icmp ne i8 %[[REL_VAR]], 2 +// CHECK-NEXT: call void @llvm.assume(i1 %[[NOT_IMPOSSIBLE]]) +// CHECK-NEXT: ret i1 %[[NOT_NICHE]] +#[no_mangle] +pub fn match4_is_c(e: MiddleNiche) -> bool { + // Before #139098, this couldn't optimize out the `select` because it looked + // like it was possible for a `2` to be produced on both sides. + + std::intrinsics::discriminant_value(&e) == 2 +} + +// You have to do something pretty obnoxious to get a variant index that doesn't +// fit in the tag size, but it's possible + +pub enum Never {} + +pub enum HugeVariantIndex { + V000(Never), + V001(Never), + V002(Never), + V003(Never), + V004(Never), + V005(Never), + V006(Never), + V007(Never), + V008(Never), + V009(Never), + V010(Never), + V011(Never), + V012(Never), + V013(Never), + V014(Never), + V015(Never), + V016(Never), + V017(Never), + V018(Never), + V019(Never), + V020(Never), + V021(Never), + V022(Never), + V023(Never), + V024(Never), + V025(Never), + V026(Never), + V027(Never), + V028(Never), + V029(Never), + V030(Never), + V031(Never), + V032(Never), + V033(Never), + V034(Never), + V035(Never), + V036(Never), + V037(Never), + V038(Never), + V039(Never), + V040(Never), + V041(Never), + V042(Never), + V043(Never), + V044(Never), + V045(Never), + V046(Never), + V047(Never), + V048(Never), + V049(Never), + V050(Never), + V051(Never), + V052(Never), + V053(Never), + V054(Never), + V055(Never), + V056(Never), + V057(Never), + V058(Never), + V059(Never), + V060(Never), + V061(Never), + V062(Never), + V063(Never), + V064(Never), + V065(Never), + V066(Never), + V067(Never), + V068(Never), + V069(Never), + V070(Never), + V071(Never), + V072(Never), + V073(Never), + V074(Never), + V075(Never), + V076(Never), + V077(Never), + V078(Never), + V079(Never), + V080(Never), + V081(Never), + V082(Never), + V083(Never), + V084(Never), + V085(Never), + V086(Never), + V087(Never), + V088(Never), + V089(Never), + V090(Never), + V091(Never), + V092(Never), + V093(Never), + V094(Never), + V095(Never), + V096(Never), + V097(Never), + V098(Never), + V099(Never), + V100(Never), + V101(Never), + V102(Never), + V103(Never), + V104(Never), + V105(Never), + V106(Never), + V107(Never), + V108(Never), + V109(Never), + V110(Never), + V111(Never), + V112(Never), + V113(Never), + V114(Never), + V115(Never), + V116(Never), + V117(Never), + V118(Never), + V119(Never), + V120(Never), + V121(Never), + V122(Never), + V123(Never), + V124(Never), + V125(Never), + V126(Never), + V127(Never), + V128(Never), + V129(Never), + V130(Never), + V131(Never), + V132(Never), + V133(Never), + V134(Never), + V135(Never), + V136(Never), + V137(Never), + V138(Never), + V139(Never), + V140(Never), + V141(Never), + V142(Never), + V143(Never), + V144(Never), + V145(Never), + V146(Never), + V147(Never), + V148(Never), + V149(Never), + V150(Never), + V151(Never), + V152(Never), + V153(Never), + V154(Never), + V155(Never), + V156(Never), + V157(Never), + V158(Never), + V159(Never), + V160(Never), + V161(Never), + V162(Never), + V163(Never), + V164(Never), + V165(Never), + V166(Never), + V167(Never), + V168(Never), + V169(Never), + V170(Never), + V171(Never), + V172(Never), + V173(Never), + V174(Never), + V175(Never), + V176(Never), + V177(Never), + V178(Never), + V179(Never), + V180(Never), + V181(Never), + V182(Never), + V183(Never), + V184(Never), + V185(Never), + V186(Never), + V187(Never), + V188(Never), + V189(Never), + V190(Never), + V191(Never), + V192(Never), + V193(Never), + V194(Never), + V195(Never), + V196(Never), + V197(Never), + V198(Never), + V199(Never), + V200(Never), + V201(Never), + V202(Never), + V203(Never), + V204(Never), + V205(Never), + V206(Never), + V207(Never), + V208(Never), + V209(Never), + V210(Never), + V211(Never), + V212(Never), + V213(Never), + V214(Never), + V215(Never), + V216(Never), + V217(Never), + V218(Never), + V219(Never), + V220(Never), + V221(Never), + V222(Never), + V223(Never), + V224(Never), + V225(Never), + V226(Never), + V227(Never), + V228(Never), + V229(Never), + V230(Never), + V231(Never), + V232(Never), + V233(Never), + V234(Never), + V235(Never), + V236(Never), + V237(Never), + V238(Never), + V239(Never), + V240(Never), + V241(Never), + V242(Never), + V243(Never), + V244(Never), + V245(Never), + V246(Never), + V247(Never), + V248(Never), + V249(Never), + V250(Never), + V251(Never), + V252(Never), + V253(Never), + V254(Never), + V255(Never), + V256(Never), + + Possible257, + Bool258(bool), + Possible259, +} + +// CHECK-LABEL: define{{( dso_local)?}} noundef{{( range\(i8 [0-9]+, [0-9]+\))?}} i8 @match5(i8{{.+}}%0) +// CHECK-NEXT: start: +// CHECK-NEXT: %[[REL_VAR:.+]] = add{{( nsw)?}} i8 %0, -2 +// CHECK-NEXT: %[[REL_VAR_WIDE:.+]] = zext i8 %[[REL_VAR]] to i64 +// CHECK-NEXT: %[[IS_NICHE:.+]] = icmp ult i8 %[[REL_VAR]], 3 +// CHECK-NEXT: %[[NOT_IMPOSSIBLE:.+]] = icmp ne i8 %[[REL_VAR]], 1 +// CHECK-NEXT: call void @llvm.assume(i1 %[[NOT_IMPOSSIBLE]]) +// CHECK-NEXT: %[[NICHE_DISCR:.+]] = add nuw nsw i64 %[[REL_VAR_WIDE]], 257 +// CHECK-NEXT: %[[DISCR:.+]] = select i1 %[[IS_NICHE]], i64 %[[NICHE_DISCR]], i64 258 +// CHECK-NEXT: switch i64 %[[DISCR]], +// CHECK-NEXT: i64 257, +// CHECK-NEXT: i64 258, +// CHECK-NEXT: i64 259, +#[no_mangle] +pub fn match5(e: HugeVariantIndex) -> u8 { + use HugeVariantIndex::*; + match e { + Possible257 => 13, + Bool258(b) => b as u8, + Possible259 => 100, + } +} diff --git a/tests/codegen/enum/enum-two-variants-match.rs b/tests/codegen/enum/enum-two-variants-match.rs index 21ae1f96bca7..12d9edc4d623 100644 --- a/tests/codegen/enum/enum-two-variants-match.rs +++ b/tests/codegen/enum/enum-two-variants-match.rs @@ -1,8 +1,12 @@ //@ compile-flags: -Copt-level=3 -C no-prepopulate-passes -//@ only-x86_64 (because these discriminants are isize) +//@ only-64bit (because these discriminants are isize) #![crate_type = "lib"] +// This directly tests what we emit for these matches, rather than what happens +// after optimization, so it doesn't need to worry about extra flags on the +// instructions and is less susceptible to being broken on LLVM updates. + // CHECK-LABEL: @option_match #[no_mangle] pub fn option_match(x: Option) -> u16 { @@ -51,3 +55,76 @@ pub fn result_match(x: Result) -> u16 { Ok(_) => 42, } } + +// CHECK-LABEL: @option_bool_match( +#[no_mangle] +pub fn option_bool_match(x: Option) -> char { + // CHECK: %[[RAW:.+]] = load i8, ptr %x + // CHECK: %[[IS_NONE:.+]] = icmp eq i8 %[[RAW]], 2 + // CHECK: %[[OPT_DISCR:.+]] = select i1 %[[IS_NONE]], i64 0, i64 1 + // CHECK: %[[OPT_DISCR_T:.+]] = trunc nuw i64 %[[OPT_DISCR]] to i1 + // CHECK: br i1 %[[OPT_DISCR_T]], label %[[BB_SOME:.+]], label %[[BB_NONE:.+]] + + // CHECK: [[BB_SOME]]: + // CHECK: %[[FIELD:.+]] = load i8, ptr %x + // CHECK: %[[FIELD_T:.+]] = trunc nuw i8 %[[FIELD]] to i1 + // CHECK: br i1 %[[FIELD_T]] + match x { + None => 'n', + Some(false) => 'f', + Some(true) => 't', + } +} + +use std::cmp::Ordering::{self, *}; +// CHECK-LABEL: @option_ordering_match( +#[no_mangle] +pub fn option_ordering_match(x: Option) -> char { + // CHECK: %[[RAW:.+]] = load i8, ptr %x + // CHECK: %[[IS_NONE:.+]] = icmp eq i8 %[[RAW]], 2 + // CHECK: %[[OPT_DISCR:.+]] = select i1 %[[IS_NONE]], i64 0, i64 1 + // CHECK: %[[OPT_DISCR_T:.+]] = trunc nuw i64 %[[OPT_DISCR]] to i1 + // CHECK: br i1 %[[OPT_DISCR_T]], label %[[BB_SOME:.+]], label %[[BB_NONE:.+]] + + // CHECK: [[BB_SOME]]: + // CHECK: %[[FIELD:.+]] = load i8, ptr %x + // CHECK: switch i8 %[[FIELD]], label %[[UNREACHABLE:.+]] [ + // CHECK-NEXT: i8 -1, label + // CHECK-NEXT: i8 0, label + // CHECK-NEXT: i8 1, label + // CHECK-NEXT: ] + + // CHECK: [[UNREACHABLE]]: + // CHECK-NEXT: unreachable + match x { + None => '?', + Some(Less) => '<', + Some(Equal) => '=', + Some(Greater) => '>', + } +} + +// CHECK-LABEL: @option_nonzero_match( +#[no_mangle] +pub fn option_nonzero_match(x: Option>) -> u16 { + // CHECK: %[[OUT:.+]] = alloca [2 x i8] + + // CHECK: %[[IS_NONE:.+]] = icmp eq i16 %x, 0 + // CHECK: %[[OPT_DISCR:.+]] = select i1 %[[IS_NONE]], i64 0, i64 1 + // CHECK: %[[OPT_DISCR_T:.+]] = trunc nuw i64 %[[OPT_DISCR]] to i1 + // CHECK: br i1 %[[OPT_DISCR_T]], label %[[BB_SOME:.+]], label %[[BB_NONE:.+]] + + // CHECK: [[BB_SOME]]: + // CHECK: store i16 987, ptr %[[OUT]] + + // CHECK: [[BB_NONE]]: + // CHECK: store i16 123, ptr %[[OUT]] + + // CHECK: %[[RET:.+]] = load i16, ptr %[[OUT]] + // CHECK: ret i16 %[[RET]] + + match x { + None => 123, + Some(_) => 987, + } +} diff --git a/tests/codegen/ergonomic-clones/closure.rs b/tests/codegen/ergonomic-clones/closure.rs new file mode 100644 index 000000000000..b6fc81726419 --- /dev/null +++ b/tests/codegen/ergonomic-clones/closure.rs @@ -0,0 +1,55 @@ +//@ compile-flags: -C no-prepopulate-passes -Copt-level=0 -Zmir-opt-level=0 + +#![crate_type = "lib"] + +#![feature(ergonomic_clones)] +#![allow(incomplete_features)] + +use std::clone::UseCloned; + +pub fn ergonomic_clone_closure_move() -> String { + let s = String::from("hi"); + + // CHECK-NOT: ; call core::clone::impls::::clone + let cl = use || s; + cl() +} + +#[derive(Clone)] +struct Foo; + +impl UseCloned for Foo {} + +pub fn ergonomic_clone_closure_use_cloned() -> Foo { + let f = Foo; + + // CHECK: ; call ::clone + let f1 = use || f; + + // CHECK: ; call ::clone + let f2 = use || f; + + f +} + +pub fn ergonomic_clone_closure_copy() -> i32 { + let i = 1; + + // CHECK-NOT: ; call core::clone::impls::::clone + let i1 = use || i; + + // CHECK-NOT: ; call core::clone::impls::::clone + let i2 = use || i; + + i +} + +pub fn ergonomic_clone_closure_use_cloned_generics(f: T) -> T { + // CHECK-NOT: ; call core::clone::impls::::clone + let f1 = use || f; + + // CHECK-NOT: ; call core::clone::impls::::clone + let f2 = use || f; + + f +} diff --git a/tests/codegen/infallible-unwrap-in-opt-z.rs b/tests/codegen/infallible-unwrap-in-opt-z.rs index 3756fafe3840..c2297c58e778 100644 --- a/tests/codegen/infallible-unwrap-in-opt-z.rs +++ b/tests/codegen/infallible-unwrap-in-opt-z.rs @@ -1,4 +1,5 @@ -//@ compile-flags: -C opt-level=z --edition=2021 +//@ compile-flags: -C opt-level=z +//@ edition: 2021 #![crate_type = "lib"] diff --git a/tests/codegen/inline-function-args-debug-info.rs b/tests/codegen/inline-function-args-debug-info.rs index 53a179160dc3..c31419cb9140 100644 --- a/tests/codegen/inline-function-args-debug-info.rs +++ b/tests/codegen/inline-function-args-debug-info.rs @@ -2,7 +2,8 @@ // gets inlined by MIR inlining. Without function argument indexes, `info args` in gdb won't show // arguments and their values for the current function. -//@ compile-flags: -Zinline-mir=yes -Cdebuginfo=2 --edition=2021 +//@ compile-flags: -Zinline-mir=yes -Cdebuginfo=2 +//@ edition: 2021 #![crate_type = "lib"] @@ -14,9 +15,9 @@ pub fn outer_function(x: usize, y: usize) -> usize { #[inline] fn inner_function(aaaa: usize, bbbb: usize) -> usize { // CHECK: !DILocalVariable(name: "aaaa", arg: 1 - // CHECK-SAME: line: 15 + // CHECK-SAME: line: 16 // CHECK-NOT: !DILexicalBlock( // CHECK: !DILocalVariable(name: "bbbb", arg: 2 - // CHECK-SAME: line: 15 + // CHECK-SAME: line: 16 aaaa + bbbb } diff --git a/tests/codegen/intrinsic-no-unnamed-attr.rs b/tests/codegen/intrinsic-no-unnamed-attr.rs index fce0de80d7b6..4bec579831dc 100644 --- a/tests/codegen/intrinsic-no-unnamed-attr.rs +++ b/tests/codegen/intrinsic-no-unnamed-attr.rs @@ -1,10 +1,9 @@ //@ compile-flags: -C no-prepopulate-passes -#![feature(intrinsics)] +#![feature(core_intrinsics)] + +use std::intrinsics::sqrtf32; -extern "rust-intrinsic" { - fn sqrtf32(x: f32) -> f32; -} // CHECK: @llvm.sqrt.f32(float) #{{[0-9]*}} fn main() { diff --git a/tests/codegen/intrinsics/nontemporal.rs b/tests/codegen/intrinsics/nontemporal.rs index 1d4fae83c29d..a151d4bd2974 100644 --- a/tests/codegen/intrinsics/nontemporal.rs +++ b/tests/codegen/intrinsics/nontemporal.rs @@ -18,9 +18,8 @@ extern crate minicore; use minicore::*; -extern "rust-intrinsic" { - pub fn nontemporal_store(ptr: *mut T, val: T); -} +#[rustc_intrinsic] +pub unsafe fn nontemporal_store(ptr: *mut T, val: T); #[no_mangle] pub fn a(a: &mut u32, b: u32) { diff --git a/tests/codegen/intrinsics/select_unpredictable.rs b/tests/codegen/intrinsics/select_unpredictable.rs index 68a02c8342d0..2db4ae174b33 100644 --- a/tests/codegen/intrinsics/select_unpredictable.rs +++ b/tests/codegen/intrinsics/select_unpredictable.rs @@ -46,21 +46,21 @@ pub fn test_zst(p: bool, a: (), b: ()) -> () { pub fn test_int2(p: bool, a: u64, b: u64) -> u64 { // CHECK-LABEL: define{{.*}} @test_int2 // CHECK: select i1 %p, i64 %a, i64 %b, !unpredictable - p.select_unpredictable(a, b) + core::hint::select_unpredictable(p, a, b) } #[no_mangle] pub fn test_pair2(p: bool, a: (u64, u64), b: (u64, u64)) -> (u64, u64) { // CHECK-LABEL: define{{.*}} @test_pair2 // CHECK: select i1 %p, {{.*}}, !unpredictable - p.select_unpredictable(a, b) + core::hint::select_unpredictable(p, a, b) } #[no_mangle] pub fn test_struct2(p: bool, a: Large, b: Large) -> Large { // CHECK-LABEL: define{{.*}} @test_struct2 // CHECK: select i1 %p, {{.*}}, !unpredictable - p.select_unpredictable(a, b) + core::hint::select_unpredictable(p, a, b) } #[no_mangle] @@ -68,5 +68,5 @@ pub fn test_zst2(p: bool, a: (), b: ()) -> () { // CHECK-LABEL: define{{.*}} @test_zst2 // CHECK-NEXT: start: // CHECK-NEXT: ret void - p.select_unpredictable(a, b) + core::hint::select_unpredictable(p, a, b) } diff --git a/tests/codegen/issues/issue-101082.rs b/tests/codegen/issues/issue-101082.rs index 7fb850ca2532..8d15921ddb4e 100644 --- a/tests/codegen/issues/issue-101082.rs +++ b/tests/codegen/issues/issue-101082.rs @@ -1,9 +1,18 @@ //@ compile-flags: -Copt-level=3 -//@ revisions: host x86-64-v3 +//@ revisions: host x86-64 x86-64-v3 //@ min-llvm-version: 20 -// This particular CPU regressed in #131563 +//@[host] ignore-x86_64 + +// Set the base cpu explicitly, in case the default has been changed. +//@[x86-64] only-x86_64 +//@[x86-64] compile-flags: -Ctarget-cpu=x86-64 + +// FIXME(cuviper) x86-64-v3 in particular regressed in #131563, and the workaround +// at the time still sometimes fails, so only verify it for the power-of-two size +// - https://github.com/llvm/llvm-project/issues/134735 //@[x86-64-v3] only-x86_64 +//@[x86-64-v3] min-llvm-version: 21 //@[x86-64-v3] compile-flags: -Ctarget-cpu=x86-64-v3 #![crate_type = "lib"] @@ -19,3 +28,15 @@ pub fn test() -> usize { } acc } + +#[no_mangle] +pub fn test_eight() -> usize { + // CHECK-LABEL: @test_eight( + // CHECK: ret {{i64|i32}} 220 + let values = [23, 16, 54, 3, 60, 9, 13, 42]; + let mut acc = 0; + for item in values { + acc += item; + } + acc +} diff --git a/tests/codegen/issues/issue-119422.rs b/tests/codegen/issues/issue-119422.rs index e1a082c377f8..17ae71605b58 100644 --- a/tests/codegen/issues/issue-119422.rs +++ b/tests/codegen/issues/issue-119422.rs @@ -1,7 +1,8 @@ //! This test checks that compiler don't generate useless compares to zeros //! for `NonZero` integer types. //! -//@ compile-flags: -Copt-level=3 --edition=2021 -Zmerge-functions=disabled +//@ compile-flags: -Copt-level=3 -Zmerge-functions=disabled +//@ edition: 2021 //@ only-64bit (because the LLVM type of i64 for usize shows up) #![crate_type = "lib"] diff --git a/tests/codegen/remap_path_prefix/aux_mod.rs b/tests/codegen/remap_path_prefix/aux_mod.rs index c37e91c705cc..3217e9e51e75 100644 --- a/tests/codegen/remap_path_prefix/aux_mod.rs +++ b/tests/codegen/remap_path_prefix/aux_mod.rs @@ -1,4 +1,4 @@ -//@ ignore-test: this is not a test +//@ ignore-auxiliary (used by `./main.rs`) #[inline] pub fn some_aux_mod_function() -> i32 { diff --git a/tests/codegen/simd/extract-insert-dyn.rs b/tests/codegen/simd/extract-insert-dyn.rs new file mode 100644 index 000000000000..584e2c7887ad --- /dev/null +++ b/tests/codegen/simd/extract-insert-dyn.rs @@ -0,0 +1,75 @@ +//@compile-flags: -C opt-level=3 -C no-prepopulate-passes + +#![feature(core_intrinsics, repr_simd)] +#![no_std] +#![crate_type = "lib"] +#![allow(non_camel_case_types)] + +// Test that `core::intrinsics::simd::{simd_extract_dyn, simd_insert_dyn}` +// lower to an LLVM extractelement or insertelement operation. + +use core::intrinsics::simd::{simd_extract, simd_extract_dyn, simd_insert, simd_insert_dyn}; + +#[repr(simd)] +#[derive(Clone, Copy)] +pub struct u32x16([u32; 16]); + +#[repr(simd)] +#[derive(Clone, Copy)] +pub struct i8x16([i8; 16]); + +// CHECK-LABEL: dyn_simd_extract +// CHECK: extractelement <16 x i8> %x, i32 %idx +#[no_mangle] +unsafe extern "C" fn dyn_simd_extract(x: i8x16, idx: u32) -> i8 { + simd_extract_dyn(x, idx) +} + +// CHECK-LABEL: literal_dyn_simd_extract +// CHECK: extractelement <16 x i8> %x, i32 7 +#[no_mangle] +unsafe extern "C" fn literal_dyn_simd_extract(x: i8x16) -> i8 { + simd_extract_dyn(x, 7) +} + +// CHECK-LABEL: const_dyn_simd_extract +// CHECK: extractelement <16 x i8> %x, i32 7 +#[no_mangle] +unsafe extern "C" fn const_dyn_simd_extract(x: i8x16) -> i8 { + simd_extract_dyn(x, const { 3 + 4 }) +} + +// CHECK-LABEL: const_simd_extract +// CHECK: extractelement <16 x i8> %x, i32 7 +#[no_mangle] +unsafe extern "C" fn const_simd_extract(x: i8x16) -> i8 { + simd_extract(x, const { 3 + 4 }) +} + +// CHECK-LABEL: dyn_simd_insert +// CHECK: insertelement <16 x i8> %x, i8 %e, i32 %idx +#[no_mangle] +unsafe extern "C" fn dyn_simd_insert(x: i8x16, e: i8, idx: u32) -> i8x16 { + simd_insert_dyn(x, idx, e) +} + +// CHECK-LABEL: literal_dyn_simd_insert +// CHECK: insertelement <16 x i8> %x, i8 %e, i32 7 +#[no_mangle] +unsafe extern "C" fn literal_dyn_simd_insert(x: i8x16, e: i8) -> i8x16 { + simd_insert_dyn(x, 7, e) +} + +// CHECK-LABEL: const_dyn_simd_insert +// CHECK: insertelement <16 x i8> %x, i8 %e, i32 7 +#[no_mangle] +unsafe extern "C" fn const_dyn_simd_insert(x: i8x16, e: i8) -> i8x16 { + simd_insert_dyn(x, const { 3 + 4 }, e) +} + +// CHECK-LABEL: const_simd_insert +// CHECK: insertelement <16 x i8> %x, i8 %e, i32 7 +#[no_mangle] +unsafe extern "C" fn const_simd_insert(x: i8x16, e: i8) -> i8x16 { + simd_insert(x, const { 3 + 4 }, e) +} diff --git a/tests/codegen/simd/simd-wide-sum.rs b/tests/codegen/simd/simd-wide-sum.rs index fb9b61884e7a..95117b2c7488 100644 --- a/tests/codegen/simd/simd-wide-sum.rs +++ b/tests/codegen/simd/simd-wide-sum.rs @@ -1,5 +1,6 @@ //@ revisions: llvm mir-opt3 -//@ compile-flags: -C opt-level=3 -Z merge-functions=disabled --edition=2021 +//@ compile-flags: -C opt-level=3 -Z merge-functions=disabled +//@ edition: 2021 //@ only-x86_64 //@ [mir-opt3]compile-flags: -Zmir-opt-level=3 //@ [mir-opt3]build-pass diff --git a/tests/codegen/simd/swap-simd-types.rs b/tests/codegen/simd/swap-simd-types.rs index 69767d0a7558..c063cc683a61 100644 --- a/tests/codegen/simd/swap-simd-types.rs +++ b/tests/codegen/simd/swap-simd-types.rs @@ -23,8 +23,8 @@ pub fn swap_single_m256(x: &mut __m256, y: &mut __m256) { #[no_mangle] pub fn swap_m256_slice(x: &mut [__m256], y: &mut [__m256]) { // CHECK-NOT: alloca - // CHECK: load <8 x float>{{.+}}align 32 - // CHECK: store <8 x float>{{.+}}align 32 + // CHECK-COUNT-2: load <4 x i64>{{.+}}align 32 + // CHECK-COUNT-2: store <4 x i64>{{.+}}align 32 if x.len() == y.len() { x.swap_with_slice(y); } @@ -34,7 +34,7 @@ pub fn swap_m256_slice(x: &mut [__m256], y: &mut [__m256]) { #[no_mangle] pub fn swap_bytes32(x: &mut [u8; 32], y: &mut [u8; 32]) { // CHECK-NOT: alloca - // CHECK: load <32 x i8>{{.+}}align 1 - // CHECK: store <32 x i8>{{.+}}align 1 + // CHECK-COUNT-2: load <4 x i64>{{.+}}align 1 + // CHECK-COUNT-2: store <4 x i64>{{.+}}align 1 swap(x, y) } diff --git a/tests/codegen/string-push.rs b/tests/codegen/string-push.rs new file mode 100644 index 000000000000..cf5f6bb1aa39 --- /dev/null +++ b/tests/codegen/string-push.rs @@ -0,0 +1,11 @@ +//! Check that `String::push` is optimized enough not to call `memcpy`. + +//@ compile-flags: -O +#![crate_type = "lib"] + +// CHECK-LABEL: @string_push_does_not_call_memcpy +#[no_mangle] +pub fn string_push_does_not_call_memcpy(s: &mut String, ch: char) { + // CHECK-NOT: call void @llvm.memcpy + s.push(ch); +} diff --git a/tests/codegen/swap-large-types.rs b/tests/codegen/swap-large-types.rs index 49a41bb14692..08c486affd94 100644 --- a/tests/codegen/swap-large-types.rs +++ b/tests/codegen/swap-large-types.rs @@ -12,6 +12,16 @@ type KeccakBuffer = [[u64; 5]; 5]; // to stack for large types, which is completely unnecessary as the lack of // overlap means we can just do whatever fits in registers at a time. +// The tests here (after the first one showing that the problem still exists) +// are less about testing *exactly* what the codegen is, and more about testing +// 1) That things are swapped directly from one argument to the other, +// never going through stack along the way, and +// 2) That we're doing the swapping for big things using large vector types, +// rather then `i64` or `<8 x i8>` (or, even worse, `i8`) at a time. +// +// (There are separate tests for intrinsics::typed_swap_nonoverlapping that +// check that it, as an intrinsic, are emitting exactly what it should.) + // CHECK-LABEL: @swap_basic #[no_mangle] pub fn swap_basic(x: &mut KeccakBuffer, y: &mut KeccakBuffer) { @@ -26,55 +36,55 @@ pub fn swap_basic(x: &mut KeccakBuffer, y: &mut KeccakBuffer) { } } -// This test verifies that the library does something smarter, and thus -// doesn't need any scratch space on the stack. - // CHECK-LABEL: @swap_std #[no_mangle] pub fn swap_std(x: &mut KeccakBuffer, y: &mut KeccakBuffer) { // CHECK-NOT: alloca - // CHECK: load <{{[0-9]+}} x i64> - // CHECK: store <{{[0-9]+}} x i64> + // CHECK: load <{{2|4}} x i64> + // CHECK: store <{{2|4}} x i64> swap(x, y) } -// Verify that types with usize alignment are swapped via vectored usizes, -// not falling back to byte-level code. - // CHECK-LABEL: @swap_slice #[no_mangle] pub fn swap_slice(x: &mut [KeccakBuffer], y: &mut [KeccakBuffer]) { // CHECK-NOT: alloca - // CHECK: load <{{[0-9]+}} x i64> - // CHECK: store <{{[0-9]+}} x i64> + // CHECK: load <{{2|4}} x i64> + // CHECK: store <{{2|4}} x i64> if x.len() == y.len() { x.swap_with_slice(y); } } -// But for a large align-1 type, vectorized byte copying is what we want. - type OneKilobyteBuffer = [u8; 1024]; // CHECK-LABEL: @swap_1kb_slices #[no_mangle] pub fn swap_1kb_slices(x: &mut [OneKilobyteBuffer], y: &mut [OneKilobyteBuffer]) { // CHECK-NOT: alloca - // CHECK: load <{{[0-9]+}} x i8> - // CHECK: store <{{[0-9]+}} x i8> + + // CHECK-NOT: load i32 + // CHECK-NOT: store i32 + // CHECK-NOT: load i16 + // CHECK-NOT: store i16 + // CHECK-NOT: load i8 + // CHECK-NOT: store i8 + + // CHECK: load <{{2|4}} x i64>{{.+}}align 1, + // CHECK: store <{{2|4}} x i64>{{.+}}align 1, + + // CHECK-NOT: load i32 + // CHECK-NOT: store i32 + // CHECK-NOT: load i16 + // CHECK-NOT: store i16 + // CHECK-NOT: load i8 + // CHECK-NOT: store i8 + if x.len() == y.len() { x.swap_with_slice(y); } } -// This verifies that the 2×read + 2×write optimizes to just 3 memcpys -// for an unusual type like this. It's not clear whether we should do anything -// smarter in Rust for these, so for now it's fine to leave these up to the backend. -// That's not as bad as it might seem, as for example, LLVM will lower the -// memcpys below to VMOVAPS on YMMs if one enables the AVX target feature. -// Eventually we'll be able to pass `align_of::` to a const generic and -// thus pick a smarter chunk size ourselves without huge code duplication. - #[repr(align(64))] pub struct BigButHighlyAligned([u8; 64 * 3]); @@ -82,9 +92,25 @@ pub struct BigButHighlyAligned([u8; 64 * 3]); #[no_mangle] pub fn swap_big_aligned(x: &mut BigButHighlyAligned, y: &mut BigButHighlyAligned) { // CHECK-NOT: call void @llvm.memcpy - // CHECK: call void @llvm.memcpy.{{.+}}(ptr noundef nonnull align 64 dereferenceable(192) - // CHECK: call void @llvm.memcpy.{{.+}}(ptr noundef nonnull align 64 dereferenceable(192) - // CHECK: call void @llvm.memcpy.{{.+}}(ptr noundef nonnull align 64 dereferenceable(192) + // CHECK-NOT: load i32 + // CHECK-NOT: store i32 + // CHECK-NOT: load i16 + // CHECK-NOT: store i16 + // CHECK-NOT: load i8 + // CHECK-NOT: store i8 + + // CHECK-COUNT-2: load <{{2|4}} x i64>{{.+}}align 64, + // CHECK-COUNT-2: store <{{2|4}} x i64>{{.+}}align 64, + + // CHECK-COUNT-2: load <{{2|4}} x i64>{{.+}}align 32, + // CHECK-COUNT-2: store <{{2|4}} x i64>{{.+}}align 32, + + // CHECK-NOT: load i32 + // CHECK-NOT: store i32 + // CHECK-NOT: load i16 + // CHECK-NOT: store i16 + // CHECK-NOT: load i8 + // CHECK-NOT: store i8 // CHECK-NOT: call void @llvm.memcpy swap(x, y) } diff --git a/tests/codegen/swap-small-types.rs b/tests/codegen/swap-small-types.rs index 76bb853e6423..7aa613ae9c22 100644 --- a/tests/codegen/swap-small-types.rs +++ b/tests/codegen/swap-small-types.rs @@ -1,5 +1,7 @@ //@ compile-flags: -Copt-level=3 -Z merge-functions=disabled //@ only-x86_64 +//@ min-llvm-version: 20 +//@ ignore-std-debug-assertions (`ptr::swap_nonoverlapping` has one which blocks some optimizations) #![crate_type = "lib"] @@ -27,13 +29,19 @@ pub fn swap_rgb48_manually(x: &mut RGB48, y: &mut RGB48) { pub fn swap_rgb48(x: &mut RGB48, y: &mut RGB48) { // CHECK-NOT: alloca - // Whether `i8` is the best for this is unclear, but - // might as well record what's actually happening right now. + // Swapping `i48` might be cleaner in LLVM-IR here, but `i32`+`i16` isn't bad, + // and is closer to the assembly it generates anyway. - // CHECK: load i8 - // CHECK: load i8 - // CHECK: store i8 - // CHECK: store i8 + // CHECK-NOT: load{{ }} + // CHECK: load i32{{.+}}align 2 + // CHECK-NEXT: load i32{{.+}}align 2 + // CHECK-NEXT: store i32{{.+}}align 2 + // CHECK-NEXT: store i32{{.+}}align 2 + // CHECK: load i16{{.+}}align 2 + // CHECK-NEXT: load i16{{.+}}align 2 + // CHECK-NEXT: store i16{{.+}}align 2 + // CHECK-NEXT: store i16{{.+}}align 2 + // CHECK-NOT: store{{ }} swap(x, y) } @@ -76,30 +84,49 @@ pub fn swap_slices<'a>(x: &mut &'a [u32], y: &mut &'a [u32]) { swap(x, y) } -// LLVM doesn't vectorize a loop over 3-byte elements, -// so we chunk it down to bytes and loop over those instead. type RGB24 = [u8; 3]; // CHECK-LABEL: @swap_rgb24_slices #[no_mangle] pub fn swap_rgb24_slices(x: &mut [RGB24], y: &mut [RGB24]) { // CHECK-NOT: alloca - // CHECK: load <{{[0-9]+}} x i8> - // CHECK: store <{{[0-9]+}} x i8> + + // CHECK: mul nuw nsw i64 %{{x|y}}.1, 3 + + // CHECK: load <{{[0-9]+}} x i64> + // CHECK: store <{{[0-9]+}} x i64> + + // CHECK-COUNT-2: load i32 + // CHECK-COUNT-2: store i32 + // CHECK-COUNT-2: load i16 + // CHECK-COUNT-2: store i16 + // CHECK-COUNT-2: load i8 + // CHECK-COUNT-2: store i8 if x.len() == y.len() { x.swap_with_slice(y); } } -// This one has a power-of-two size, so we iterate over it directly type RGBA32 = [u8; 4]; // CHECK-LABEL: @swap_rgba32_slices #[no_mangle] pub fn swap_rgba32_slices(x: &mut [RGBA32], y: &mut [RGBA32]) { // CHECK-NOT: alloca - // CHECK: load <{{[0-9]+}} x i32> - // CHECK: store <{{[0-9]+}} x i32> + + // Because the size in bytes in a multiple of 4, we can skip the smallest sizes. + + // CHECK: load <{{[0-9]+}} x i64> + // CHECK: store <{{[0-9]+}} x i64> + + // CHECK-COUNT-2: load i32 + // CHECK-COUNT-2: store i32 + + // CHECK-NOT: load i16 + // CHECK-NOT: store i16 + // CHECK-NOT: load i8 + // CHECK-NOT: store i8 + if x.len() == y.len() { x.swap_with_slice(y); } @@ -113,8 +140,8 @@ const _: () = assert!(!std::mem::size_of::().is_power_of_two()); #[no_mangle] pub fn swap_string_slices(x: &mut [String], y: &mut [String]) { // CHECK-NOT: alloca - // CHECK: load <{{[0-9]+}} x i64> - // CHECK: store <{{[0-9]+}} x i64> + // CHECK: load <{{[0-9]+}} x i64>{{.+}}, align 8, + // CHECK: store <{{[0-9]+}} x i64>{{.+}}, align 8, if x.len() == y.len() { x.swap_with_slice(y); } @@ -130,6 +157,26 @@ pub struct Packed { #[no_mangle] pub fn swap_packed_structs(x: &mut Packed, y: &mut Packed) { // CHECK-NOT: alloca + + // CHECK-NOT: load + // CHECK-NOT: store + + // CHECK: %[[A:.+]] = load i64, ptr %x, align 1, + // CHECK-NEXT: %[[B:.+]] = load i64, ptr %y, align 1, + // CHECK-NEXT: store i64 %[[B]], ptr %x, align 1, + // CHECK-NEXT: store i64 %[[A]], ptr %y, align 1, + + // CHECK-NOT: load + // CHECK-NOT: store + + // CHECK: %[[C:.+]] = load i8, ptr %[[X8:.+]], align 1, + // CHECK-NEXT: %[[D:.+]] = load i8, ptr %[[Y8:.+]], align 1, + // CHECK-NEXT: store i8 %[[D]], ptr %[[X8]], align 1, + // CHECK-NEXT: store i8 %[[C]], ptr %[[Y8]], align 1, + + // CHECK-NOT: load + // CHECK-NOT: store + // CHECK: ret void swap(x, y) } diff --git a/tests/codegen/try_question_mark_nop.rs b/tests/codegen/try_question_mark_nop.rs index 9f68d742a75e..398c9a580bc3 100644 --- a/tests/codegen/try_question_mark_nop.rs +++ b/tests/codegen/try_question_mark_nop.rs @@ -1,4 +1,5 @@ -//@ compile-flags: -Copt-level=3 -Z merge-functions=disabled --edition=2021 +//@ compile-flags: -Copt-level=3 -Z merge-functions=disabled +//@ edition: 2021 //@ only-x86_64 //@ revisions: NINETEEN TWENTY //@[NINETEEN] exact-llvm-major-version: 19 diff --git a/tests/crashes/100618.rs b/tests/crashes/100618.rs deleted file mode 100644 index 911c4098badc..000000000000 --- a/tests/crashes/100618.rs +++ /dev/null @@ -1,12 +0,0 @@ -//@ known-bug: #100618 -//@ compile-flags: -Cdebuginfo=2 - -//@ only-x86_64 -enum Foo { - Value(T), - Recursive(&'static Foo>), -} - -fn main() { - let _x = Foo::Value(()); -} diff --git a/tests/crashes/115994.rs b/tests/crashes/115994.rs deleted file mode 100644 index 23d1507136f7..000000000000 --- a/tests/crashes/115994.rs +++ /dev/null @@ -1,17 +0,0 @@ -//@ known-bug: #115994 -//@ compile-flags: -Cdebuginfo=2 --crate-type lib - -// To prevent "overflow while adding drop-check rules". -use std::mem::ManuallyDrop; - -pub enum Foo { - Leaf(U), - - Branch(BoxedFoo>), -} - -pub type BoxedFoo = ManuallyDrop>>; - -pub fn test() -> Foo { - todo!() -} diff --git a/tests/crashes/119095.rs b/tests/crashes/119095.rs index 28742e0d5dae..9b6c976d3e5d 100644 --- a/tests/crashes/119095.rs +++ b/tests/crashes/119095.rs @@ -1,5 +1,5 @@ //@ known-bug: #119095 -//@ compile-flags: --edition=2021 +//@ edition: 2021 fn any() -> T { loop {} diff --git a/tests/crashes/120016.rs b/tests/crashes/120016.rs index faba1af91b4b..7eda330e7ade 100644 --- a/tests/crashes/120016.rs +++ b/tests/crashes/120016.rs @@ -1,5 +1,6 @@ //@ known-bug: #120016 -//@ compile-flags: -Zcrate-attr=feature(const_async_blocks) --edition=2021 +//@ compile-flags: -Zcrate-attr=feature(const_async_blocks) +//@ edition: 2021 #![feature(type_alias_impl_trait, const_async_blocks)] diff --git a/tests/crashes/121538.rs b/tests/crashes/121538.rs deleted file mode 100644 index f18bad84b572..000000000000 --- a/tests/crashes/121538.rs +++ /dev/null @@ -1,30 +0,0 @@ -//@ known-bug: #121538 -//@ compile-flags: -Cdebuginfo=2 - -use std::marker::PhantomData; - -struct Digit { - elem: T -} - -struct Node { m: PhantomData<&'static T> } - -enum FingerTree { - Single(T), - - Deep( - Digit, - Node>>, - ) -} - -enum Wrapper { - Simple, - Other(FingerTree), -} - -fn main() { - let w = - Some(Wrapper::Simple::); - -} diff --git a/tests/crashes/127033.rs b/tests/crashes/127033.rs index 919c9dfd30e8..52b880e4859b 100644 --- a/tests/crashes/127033.rs +++ b/tests/crashes/127033.rs @@ -1,5 +1,5 @@ //@ known-bug: #127033 -//@ compile-flags: --edition=2021 +//@ edition: 2021 pub trait RaftLogStorage { fn save_vote(vote: ()) -> impl std::future::Future + Send; diff --git a/tests/crashes/128094.rs b/tests/crashes/128094.rs index 5f0ae108f8f6..56d09d78bed9 100644 --- a/tests/crashes/128094.rs +++ b/tests/crashes/128094.rs @@ -1,5 +1,6 @@ //@ known-bug: rust-lang/rust#128094 -//@ compile-flags: -Zmir-enable-passes=+GVN --edition=2018 +//@ compile-flags: -Zmir-enable-passes=+GVN +//@ edition: 2018 pub enum Request { TestSome(T), diff --git a/tests/crashes/129372.rs b/tests/crashes/129372.rs deleted file mode 100644 index 43be01b35df2..000000000000 --- a/tests/crashes/129372.rs +++ /dev/null @@ -1,52 +0,0 @@ -//@ known-bug: #129372 -//@ compile-flags: -Cdebuginfo=2 -Copt-level=0 - -pub struct Wrapper(T); -struct Struct; - -pub trait TraitA { - type AssocA<'t>; -} -pub trait TraitB { - type AssocB; -} - -pub fn helper(v: impl MethodTrait) { - let _local_that_causes_ice = v.method(); -} - -pub fn main() { - helper(Wrapper(Struct)); -} - -pub trait MethodTrait { - type Assoc<'a>; - - fn method(self) -> impl for<'a> FnMut(&'a ()) -> Self::Assoc<'a>; -} - -impl MethodTrait for T -where - ::AssocB: TraitA, -{ - type Assoc<'a> = ::AssocA<'a>; - - fn method(self) -> impl for<'a> FnMut(&'a ()) -> Self::Assoc<'a> { - move |_| loop {} - } -} - -impl TraitB for Wrapper -where - B: TraitB, -{ - type AssocB = T; -} - -impl TraitB for Struct { - type AssocB = Struct; -} - -impl TraitA for Struct { - type AssocA<'t> = Self; -} diff --git a/tests/crashes/132103.rs b/tests/crashes/132103.rs index 5bf4792c44c9..e2d8378efe6a 100644 --- a/tests/crashes/132103.rs +++ b/tests/crashes/132103.rs @@ -1,5 +1,6 @@ //@ known-bug: #132103 -//@compile-flags: -Zvalidate-mir --edition=2018 -Zinline-mir=yes +//@ compile-flags: -Zvalidate-mir -Zinline-mir=yes +//@ edition: 2018 use core::future::{async_drop_in_place, Future}; use core::mem::{self}; use core::pin::pin; diff --git a/tests/crashes/132430.rs b/tests/crashes/132430.rs index 995bdf06224e..81c8c6d6f7d3 100644 --- a/tests/crashes/132430.rs +++ b/tests/crashes/132430.rs @@ -1,6 +1,7 @@ //@ known-bug: #132430 -//@compile-flags: --edition=2018 --crate-type=lib +//@ compile-flags: --crate-type=lib +//@ edition: 2018 #![feature(cmse_nonsecure_entry)] struct Test; diff --git a/tests/crashes/135128.rs b/tests/crashes/135128.rs index a8fd1ae1ff56..c718b758dc69 100644 --- a/tests/crashes/135128.rs +++ b/tests/crashes/135128.rs @@ -1,5 +1,6 @@ //@ known-bug: #135128 -//@ compile-flags: -Copt-level=1 --edition=2021 +//@ compile-flags: -Copt-level=1 +//@ edition: 2021 #![feature(trivial_bounds)] diff --git a/tests/crashes/135470.rs b/tests/crashes/135470.rs index 7d357a9317f3..efa017b5457c 100644 --- a/tests/crashes/135470.rs +++ b/tests/crashes/135470.rs @@ -1,5 +1,6 @@ //@ known-bug: #135470 -//@ compile-flags: --edition=2021 -Copt-level=0 +//@ compile-flags: -Copt-level=0 +//@ edition: 2021 use std::future::Future; trait Access { diff --git a/tests/crashes/135646.rs b/tests/crashes/135646.rs index 67b0ad93db4c..841ea5b81b41 100644 --- a/tests/crashes/135646.rs +++ b/tests/crashes/135646.rs @@ -1,5 +1,7 @@ //@ known-bug: #135646 -//@ compile-flags: --edition=2024 -Zpolonius=next +//@ compile-flags: -Zpolonius=next +//@ edition: 2024 + fn main() { &{ [1, 2, 3][4] }; } diff --git a/tests/crashes/137467-1.rs b/tests/crashes/137467-1.rs index 1d62cba59a79..b6bff2bdc4e8 100644 --- a/tests/crashes/137467-1.rs +++ b/tests/crashes/137467-1.rs @@ -1,5 +1,5 @@ //@ known-bug: #137467 -//@ compile-flags: --edition=2021 +//@ edition: 2021 enum Camera { Normal { base_transform: i32 }, Volume { transform: i32 }, diff --git a/tests/crashes/137467-2.rs b/tests/crashes/137467-2.rs index 151d6a0767f0..a70ea92b22dc 100644 --- a/tests/crashes/137467-2.rs +++ b/tests/crashes/137467-2.rs @@ -1,5 +1,5 @@ //@ known-bug: #137467 -//@ compile-flags: --edition=2021 +//@ edition: 2021 enum Camera { Normal { base_transform: i32 }, diff --git a/tests/crashes/137467-3.rs b/tests/crashes/137467-3.rs index 2140fe044a77..cb81a9a912e7 100644 --- a/tests/crashes/137467-3.rs +++ b/tests/crashes/137467-3.rs @@ -1,5 +1,5 @@ //@ known-bug: #137467 -//@ compile-flags: --edition=2021 +//@ edition: 2021 fn meow(x: (u32, u32, u32)) { let f = || { diff --git a/tests/crashes/137916.rs b/tests/crashes/137916.rs index 3d6b0e0fbab4..b25e7b200d95 100644 --- a/tests/crashes/137916.rs +++ b/tests/crashes/137916.rs @@ -1,5 +1,5 @@ //@ known-bug: #137916 -//@ compile-flags: --edition=2021 +//@ edition: 2021 use std::ptr::null; async fn a() -> Box { diff --git a/tests/crashes/74451.rs b/tests/crashes/74451.rs deleted file mode 100644 index 8f9369946789..000000000000 --- a/tests/crashes/74451.rs +++ /dev/null @@ -1,42 +0,0 @@ -//@ known-bug: #74451 -//@ compile-flags: -Copt-level=0 - -#![feature(specialization)] -#![feature(unsize, coerce_unsized)] -#![allow(incomplete_features)] -#![crate_type = "lib"] - -use std::ops::CoerceUnsized; - -pub struct SmartassPtr(A::Data); - -pub trait Smartass { - type Data; - type Data2: CoerceUnsized<*const [u8]>; -} - -pub trait MaybeObjectSafe {} - -impl MaybeObjectSafe for () {} - -impl Smartass for T { - type Data = ::Data2; - default type Data2 = *const [u8; 0]; -} - -impl Smartass for () { - type Data2 = *const [u8; 1]; -} - -impl Smartass for dyn MaybeObjectSafe { - type Data = *const [u8]; - type Data2 = *const [u8; 0]; -} - -impl CoerceUnsized> for SmartassPtr - where ::Data: std::ops::CoerceUnsized<::Data> -{} - -pub fn conv(s: SmartassPtr<()>) -> SmartassPtr { - s // This shouldn't coerce -} diff --git a/tests/debuginfo/coroutine-closure.rs b/tests/debuginfo/coroutine-closure.rs index ffb6ae68a2b8..002531084fb9 100644 --- a/tests/debuginfo/coroutine-closure.rs +++ b/tests/debuginfo/coroutine-closure.rs @@ -1,6 +1,7 @@ #![feature(async_closure)] //@ only-cdb -//@ compile-flags:-g --edition=2021 +//@ compile-flags: -g +//@ edition: 2021 // === CDB TESTS ================================================================================== diff --git a/tests/debuginfo/drop-locations.rs b/tests/debuginfo/drop-locations.rs index a55cf7b50a81..91b3da5c34a8 100644 --- a/tests/debuginfo/drop-locations.rs +++ b/tests/debuginfo/drop-locations.rs @@ -1,5 +1,7 @@ //@ ignore-android -//@ ignore-test: #128971 + +// FIXME: stepping with "next" in a debugger skips past end-of-scope drops +//@ ignore-test (broken, see #128971) #![allow(unused)] diff --git a/tests/debuginfo/recursive-enum.rs b/tests/debuginfo/recursive-enum.rs index c2c3e71b8a4f..b861e6d617c8 100644 --- a/tests/debuginfo/recursive-enum.rs +++ b/tests/debuginfo/recursive-enum.rs @@ -4,7 +4,7 @@ // gdb-command:run // Test whether compiling a recursive enum definition crashes debug info generation. The test case -// is taken from issue #11083. +// is taken from issue #11083 and #135093. #![allow(unused_variables)] #![feature(omit_gdb_pretty_printer_section)] @@ -18,6 +18,21 @@ struct WindowCallbacks<'a> { pos_callback: Option>, } +enum ExpandingRecursive { + Recurse(Indirect), + Item(T), +} + +struct Indirect { + rec: *const ExpandingRecursive>, +} + + fn main() { let x = WindowCallbacks { pos_callback: None }; + + // EXPANDING RECURSIVE + let expanding_recursive: ExpandingRecursive = ExpandingRecursive::Recurse(Indirect { + rec: &ExpandingRecursive::Item(Option::Some(42)), + }); } diff --git a/tests/crashes/107362.rs b/tests/debuginfo/recursive-type-with-gat.rs similarity index 96% rename from tests/crashes/107362.rs rename to tests/debuginfo/recursive-type-with-gat.rs index 8d55d611eb13..b8a67d8d24b4 100644 --- a/tests/crashes/107362.rs +++ b/tests/debuginfo/recursive-type-with-gat.rs @@ -1,4 +1,3 @@ -//@ known-bug: #107362 //@ compile-flags: -Cdebuginfo=2 pub trait Functor diff --git a/tests/incremental/circular-dependencies.rs b/tests/incremental/circular-dependencies.rs index c7b5b931fbbe..bd3b109b62c7 100644 --- a/tests/incremental/circular-dependencies.rs +++ b/tests/incremental/circular-dependencies.rs @@ -15,6 +15,7 @@ pub struct Foo; pub fn consume_foo(_: Foo) {} //[cfail2]~^ NOTE function defined here +//[cfail2]~| NOTE pub fn produce_foo() -> Foo { Foo diff --git a/tests/incremental/const-generic-type-cycle.rs b/tests/incremental/const-generic-type-cycle.rs index cd0437f7ef66..40a40ebd13fe 100644 --- a/tests/incremental/const-generic-type-cycle.rs +++ b/tests/incremental/const-generic-type-cycle.rs @@ -3,7 +3,6 @@ // //@ compile-flags: -Zincremental-ignore-spans //@ revisions: cpass cfail -//@ error-pattern: cycle detected when computing type of `Bar::N` #![feature(trait_alias)] #![crate_type="lib"] @@ -13,5 +12,9 @@ trait Bar {} #[cfg(cfail)] trait Bar {} +//[cfail]~^ ERROR cycle detected when computing type of `Bar::N` +//[cfail]~| ERROR cycle detected when computing type of `Bar::N` +//[cfail]~| ERROR cycle detected when computing type of `Bar::N` +//[cfail]~| ERROR `(dyn Bar<{ 2 + 1 }> + 'static)` is forbidden as the type of a const generic parameter trait BB = Bar<{ 2 + 1 }>; diff --git a/tests/incremental/delayed_span_bug.rs b/tests/incremental/delayed_span_bug.rs index 1534aca5dddf..7b409db2e18e 100644 --- a/tests/incremental/delayed_span_bug.rs +++ b/tests/incremental/delayed_span_bug.rs @@ -1,8 +1,7 @@ //@ revisions: cfail1 cfail2 //@ should-ice -//@ error-pattern: delayed bug triggered by #[rustc_delayed_bug_from_inside_query] #![feature(rustc_attrs)] #[rustc_delayed_bug_from_inside_query] -fn main() {} +fn main() {} //~ ERROR delayed bug triggered by #[rustc_delayed_bug_from_inside_query] diff --git a/tests/incremental/issue-85360-eval-obligation-ice.rs b/tests/incremental/issue-85360-eval-obligation-ice.rs index 6efae1aa12d7..70bb43f39ecf 100644 --- a/tests/incremental/issue-85360-eval-obligation-ice.rs +++ b/tests/incremental/issue-85360-eval-obligation-ice.rs @@ -1,6 +1,7 @@ //@ revisions:cfail1 cfail2 -//@[cfail1] compile-flags: --crate-type=lib --edition=2021 -Zassert-incr-state=not-loaded -//@[cfail2] compile-flags: --crate-type=lib --edition=2021 -Zassert-incr-state=loaded +//@[cfail1] compile-flags: --crate-type=lib -Zassert-incr-state=not-loaded +//@[cfail2] compile-flags: --crate-type=lib -Zassert-incr-state=loaded +//@ edition: 2021 //@ build-pass use core::any::Any; diff --git a/tests/incremental/link_order/main.rs b/tests/incremental/link_order/main.rs index 847a47a75598..20931e25dd4b 100644 --- a/tests/incremental/link_order/main.rs +++ b/tests/incremental/link_order/main.rs @@ -1,5 +1,4 @@ //@ aux-build:my_lib.rs -//@ error-pattern: error: linking with //@ revisions:cfail1 cfail2 //@ compile-flags:-Z query-dep-graph @@ -10,3 +9,5 @@ extern crate my_lib; fn main() {} + +//~? ERROR linking with diff --git a/tests/mir-opt/const_prop/address_of_pair.fn0.GVN.diff b/tests/mir-opt/const_prop/address_of_pair.fn0.GVN.diff index e33185f17bcf..c23afae829f4 100644 --- a/tests/mir-opt/const_prop/address_of_pair.fn0.GVN.diff +++ b/tests/mir-opt/const_prop/address_of_pair.fn0.GVN.diff @@ -31,15 +31,13 @@ (*_3) = const true; _4 = const (); StorageDead(_4); -- StorageLive(_5); -+ nop; + StorageLive(_5); StorageLive(_6); _6 = copy (_2.1: bool); _5 = Not(move _6); StorageDead(_6); _0 = copy _5; -- StorageDead(_5); -+ nop; + StorageDead(_5); StorageDead(_3); StorageDead(_2); return; diff --git a/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.32bit.panic-abort.diff b/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.32bit.panic-abort.diff index 37dd14e6c896..35eb4fbd106a 100644 --- a/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.32bit.panic-abort.diff +++ b/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.32bit.panic-abort.diff @@ -69,8 +69,7 @@ bb0: { StorageLive(_1); -- StorageLive(_2); -+ nop; + StorageLive(_2); StorageLive(_3); StorageLive(_11); StorageLive(_12); @@ -119,8 +118,7 @@ StorageDead(_11); _2 = &_3; _1 = copy _2; -- StorageDead(_2); -+ nop; + StorageDead(_2); StorageLive(_4); - _9 = deref_copy _3; + _9 = copy _3; @@ -141,7 +139,7 @@ StorageLive(_8); _8 = copy _5; - _7 = copy _8 as *mut () (PtrToPtr); -+ _7 = copy _5 as *mut () (PtrToPtr); ++ _7 = copy ((_9.0: std::ptr::Unique<()>).0: std::ptr::NonNull<()>) as *mut () (Transmute); StorageDead(_8); StorageDead(_7); - StorageDead(_5); diff --git a/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.32bit.panic-unwind.diff b/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.32bit.panic-unwind.diff index 6bac68059431..b2085afb7137 100644 --- a/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.32bit.panic-unwind.diff +++ b/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.32bit.panic-unwind.diff @@ -35,8 +35,7 @@ bb0: { StorageLive(_1); -- StorageLive(_2); -+ nop; + StorageLive(_2); StorageLive(_3); _3 = Box::<()>::new(const ()) -> [return: bb1, unwind continue]; } @@ -44,8 +43,7 @@ bb1: { _2 = &_3; _1 = copy _2; -- StorageDead(_2); -+ nop; + StorageDead(_2); StorageLive(_4); - _9 = deref_copy _3; + _9 = copy _3; @@ -66,7 +64,7 @@ StorageLive(_8); _8 = copy _5; - _7 = copy _8 as *mut () (PtrToPtr); -+ _7 = copy _5 as *mut () (PtrToPtr); ++ _7 = copy ((_9.0: std::ptr::Unique<()>).0: std::ptr::NonNull<()>) as *mut () (Transmute); StorageDead(_8); StorageDead(_7); - StorageDead(_5); diff --git a/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.64bit.panic-abort.diff b/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.64bit.panic-abort.diff index 1cf0f6de011e..4427a5fcc7de 100644 --- a/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.64bit.panic-abort.diff +++ b/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.64bit.panic-abort.diff @@ -69,8 +69,7 @@ bb0: { StorageLive(_1); -- StorageLive(_2); -+ nop; + StorageLive(_2); StorageLive(_3); StorageLive(_11); StorageLive(_12); @@ -119,8 +118,7 @@ StorageDead(_11); _2 = &_3; _1 = copy _2; -- StorageDead(_2); -+ nop; + StorageDead(_2); StorageLive(_4); - _9 = deref_copy _3; + _9 = copy _3; @@ -141,7 +139,7 @@ StorageLive(_8); _8 = copy _5; - _7 = copy _8 as *mut () (PtrToPtr); -+ _7 = copy _5 as *mut () (PtrToPtr); ++ _7 = copy ((_9.0: std::ptr::Unique<()>).0: std::ptr::NonNull<()>) as *mut () (Transmute); StorageDead(_8); StorageDead(_7); - StorageDead(_5); diff --git a/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.64bit.panic-unwind.diff b/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.64bit.panic-unwind.diff index 6bac68059431..b2085afb7137 100644 --- a/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.64bit.panic-unwind.diff +++ b/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.64bit.panic-unwind.diff @@ -35,8 +35,7 @@ bb0: { StorageLive(_1); -- StorageLive(_2); -+ nop; + StorageLive(_2); StorageLive(_3); _3 = Box::<()>::new(const ()) -> [return: bb1, unwind continue]; } @@ -44,8 +43,7 @@ bb1: { _2 = &_3; _1 = copy _2; -- StorageDead(_2); -+ nop; + StorageDead(_2); StorageLive(_4); - _9 = deref_copy _3; + _9 = copy _3; @@ -66,7 +64,7 @@ StorageLive(_8); _8 = copy _5; - _7 = copy _8 as *mut () (PtrToPtr); -+ _7 = copy _5 as *mut () (PtrToPtr); ++ _7 = copy ((_9.0: std::ptr::Unique<()>).0: std::ptr::NonNull<()>) as *mut () (Transmute); StorageDead(_8); StorageDead(_7); - StorageDead(_5); diff --git a/tests/mir-opt/ergonomic-clones/closure.rs b/tests/mir-opt/ergonomic-clones/closure.rs new file mode 100644 index 000000000000..682f48449841 --- /dev/null +++ b/tests/mir-opt/ergonomic-clones/closure.rs @@ -0,0 +1,55 @@ +#![crate_type = "lib"] +#![feature(ergonomic_clones)] +#![allow(incomplete_features)] + +use std::clone::UseCloned; + +pub fn ergonomic_clone_closure_move() -> String { + // CHECK-LABEL: fn ergonomic_clone_closure_move( + // CHECK: _0 = move (_1.0: std::string::String); + // CHECK-NOT: ::clone + let s = String::from("hi"); + + let cl = use || s; + cl() +} + +#[derive(Clone)] +struct Foo; + +impl UseCloned for Foo {} + +pub fn ergonomic_clone_closure_use_cloned() -> Foo { + // CHECK-LABEL: fn ergonomic_clone_closure_use_cloned( + // CHECK: ::clone + let f = Foo; + + let f1 = use || f; + + let f2 = use || f; + + f +} + +pub fn ergonomic_clone_closure_copy() -> i32 { + // CHECK-LABEL: fn ergonomic_clone_closure_copy( + // CHECK: _0 = copy ((*_1).0: i32); + // CHECK-NOT: ::clone + let i = 1; + + let i1 = use || i; + + let i2 = use || i; + + i +} + +pub fn ergonomic_clone_closure_use_cloned_generics(f: T) -> T { + // CHECK-LABEL: fn ergonomic_clone_closure_use_cloned_generics( + // CHECK: ::clone + let f1 = use || f; + + let f2 = use || f; + + f +} diff --git a/tests/mir-opt/gvn_copy_constant_projection.compare_constant_index.GVN.panic-abort.diff b/tests/mir-opt/gvn_copy_constant_projection.compare_constant_index.GVN.panic-abort.diff new file mode 100644 index 000000000000..e2e55304921b --- /dev/null +++ b/tests/mir-opt/gvn_copy_constant_projection.compare_constant_index.GVN.panic-abort.diff @@ -0,0 +1,58 @@ +- // MIR for `compare_constant_index` before GVN ++ // MIR for `compare_constant_index` after GVN + + fn compare_constant_index(_1: [i32; 1], _2: [i32; 1]) -> std::cmp::Ordering { + debug x => _1; + debug y => _2; + let mut _0: std::cmp::Ordering; + let _3: &i32; + let _4: usize; + let mut _5: bool; + let _6: &i32; + let _7: usize; + let mut _8: bool; + scope 1 (inlined std::cmp::impls::::cmp) { + let mut _9: i32; + let mut _10: i32; + } + + bb0: { +- StorageLive(_4); ++ nop; + _4 = const 0_usize; +- _5 = Lt(copy _4, const 1_usize); +- assert(move _5, "index out of bounds: the length is {} but the index is {}", const 1_usize, copy _4) -> [success: bb1, unwind unreachable]; ++ _5 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 1_usize, const 0_usize) -> [success: bb1, unwind unreachable]; + } + + bb1: { +- _3 = &_1[_4]; ++ _3 = &_1[0 of 1]; + StorageLive(_7); + _7 = const 0_usize; +- _8 = Lt(copy _7, const 1_usize); +- assert(move _8, "index out of bounds: the length is {} but the index is {}", const 1_usize, copy _7) -> [success: bb2, unwind unreachable]; ++ _8 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 1_usize, const 0_usize) -> [success: bb2, unwind unreachable]; + } + + bb2: { +- _6 = &_2[_7]; ++ _6 = &_2[0 of 1]; + StorageLive(_9); +- _9 = copy (*_3); ++ _9 = copy _1[0 of 1]; + StorageLive(_10); +- _10 = copy (*_6); ++ _10 = copy _2[0 of 1]; + _0 = Cmp(move _9, move _10); + StorageDead(_10); + StorageDead(_9); + StorageDead(_7); +- StorageDead(_4); ++ nop; + return; + } + } + diff --git a/tests/mir-opt/gvn_copy_constant_projection.compare_constant_index.GVN.panic-unwind.diff b/tests/mir-opt/gvn_copy_constant_projection.compare_constant_index.GVN.panic-unwind.diff new file mode 100644 index 000000000000..60611146a0ee --- /dev/null +++ b/tests/mir-opt/gvn_copy_constant_projection.compare_constant_index.GVN.panic-unwind.diff @@ -0,0 +1,58 @@ +- // MIR for `compare_constant_index` before GVN ++ // MIR for `compare_constant_index` after GVN + + fn compare_constant_index(_1: [i32; 1], _2: [i32; 1]) -> std::cmp::Ordering { + debug x => _1; + debug y => _2; + let mut _0: std::cmp::Ordering; + let _3: &i32; + let _4: usize; + let mut _5: bool; + let _6: &i32; + let _7: usize; + let mut _8: bool; + scope 1 (inlined std::cmp::impls::::cmp) { + let mut _9: i32; + let mut _10: i32; + } + + bb0: { +- StorageLive(_4); ++ nop; + _4 = const 0_usize; +- _5 = Lt(copy _4, const 1_usize); +- assert(move _5, "index out of bounds: the length is {} but the index is {}", const 1_usize, copy _4) -> [success: bb1, unwind continue]; ++ _5 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 1_usize, const 0_usize) -> [success: bb1, unwind continue]; + } + + bb1: { +- _3 = &_1[_4]; ++ _3 = &_1[0 of 1]; + StorageLive(_7); + _7 = const 0_usize; +- _8 = Lt(copy _7, const 1_usize); +- assert(move _8, "index out of bounds: the length is {} but the index is {}", const 1_usize, copy _7) -> [success: bb2, unwind continue]; ++ _8 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 1_usize, const 0_usize) -> [success: bb2, unwind continue]; + } + + bb2: { +- _6 = &_2[_7]; ++ _6 = &_2[0 of 1]; + StorageLive(_9); +- _9 = copy (*_3); ++ _9 = copy _1[0 of 1]; + StorageLive(_10); +- _10 = copy (*_6); ++ _10 = copy _2[0 of 1]; + _0 = Cmp(move _9, move _10); + StorageDead(_10); + StorageDead(_9); + StorageDead(_7); +- StorageDead(_4); ++ nop; + return; + } + } + diff --git a/tests/mir-opt/gvn_copy_constant_projection.rs b/tests/mir-opt/gvn_copy_constant_projection.rs new file mode 100644 index 000000000000..a08ae0ac7c97 --- /dev/null +++ b/tests/mir-opt/gvn_copy_constant_projection.rs @@ -0,0 +1,18 @@ +// EMIT_MIR_FOR_EACH_PANIC_STRATEGY + +use std::cmp::Ordering; +fn compare_constant_index(x: [i32; 1], y: [i32; 1]) -> Ordering { + // CHECK-LABEL: fn compare_constant_index( + // CHECK-NOT: (*{{_.*}}); + // CHECK: [[lhs:_.*]] = copy _1[0 of 1]; + // CHECK-NOT: (*{{_.*}}); + // CHECK: [[rhs:_.*]] = copy _2[0 of 1]; + // CHECK: _0 = Cmp(move [[lhs]], move [[rhs]]); + Ord::cmp(&x[0], &y[0]) +} + +fn main() { + compare_constant_index([1], [2]); +} + +// EMIT_MIR gvn_copy_constant_projection.compare_constant_index.GVN.diff diff --git a/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-abort.diff b/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-abort.diff index 56d4d50e967e..151580da19e0 100644 --- a/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-abort.diff +++ b/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-abort.diff @@ -33,7 +33,7 @@ - _4 = g() -> [return: bb1, unwind unreachable]; + _4 = {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8 (#0)}; + _3 = &mut _4; -+ _2 = Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8}> { __pointer: copy _3 }; ++ _2 = Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8}> { pointer: copy _3 }; + StorageDead(_3); + StorageLive(_5); + _5 = const false; diff --git a/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-unwind.diff b/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-unwind.diff index 751916a00f14..6196fc0d0c6b 100644 --- a/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-unwind.diff +++ b/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-unwind.diff @@ -33,7 +33,7 @@ - _4 = g() -> [return: bb1, unwind continue]; + _4 = {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8 (#0)}; + _3 = &mut _4; -+ _2 = Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8}> { __pointer: copy _3 }; ++ _2 = Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8}> { pointer: copy _3 }; + StorageDead(_3); + StorageLive(_5); + _5 = const false; diff --git a/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff index eb97af1e2845..1e9a6dd4f5c8 100644 --- a/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff +++ b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff @@ -121,7 +121,7 @@ - } - - bb2: { -+ _4 = Pin::<&mut {async fn body of ActionPermit<'_, T>::perform()}> { __pointer: copy _5 }; ++ _4 = Pin::<&mut {async fn body of ActionPermit<'_, T>::perform()}> { pointer: copy _5 }; StorageDead(_5); StorageLive(_6); StorageLive(_7); @@ -218,7 +218,7 @@ + _37 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()}); + _21 = &mut (((*_37) as variant#3).1: std::future::Ready<()>); + _20 = &mut (*_21); -+ _19 = Pin::<&mut std::future::Ready<()>> { __pointer: copy _20 }; ++ _19 = Pin::<&mut std::future::Ready<()>> { pointer: copy _20 }; + StorageDead(_20); + StorageLive(_22); + StorageLive(_23); @@ -229,7 +229,6 @@ + StorageDead(_24); + StorageLive(_45); + StorageLive(_46); -+ StorageLive(_49); + StorageLive(_51); + StorageLive(_42); + StorageLive(_43); @@ -240,12 +239,14 @@ + _48 = &mut (_19.0: &mut std::future::Ready<()>); + _45 = copy (_19.0: &mut std::future::Ready<()>); + StorageDead(_48); -+ _47 = Pin::<&mut std::future::Ready<()>> { __pointer: copy _45 }; ++ _47 = Pin::<&mut std::future::Ready<()>> { pointer: copy _45 }; + StorageDead(_47); + _44 = &mut ((*_45).0: std::option::Option<()>); ++ StorageLive(_49); + _49 = Option::<()>::None; + _43 = copy ((*_45).0: std::option::Option<()>); + ((*_45).0: std::option::Option<()>) = copy _49; ++ StorageDead(_49); + StorageDead(_44); + StorageLive(_50); + _50 = discriminant(_43); @@ -322,7 +323,6 @@ + _18 = Poll::<()>::Ready(move _42); + StorageDead(_42); + StorageDead(_51); -+ StorageDead(_49); + StorageDead(_46); + StorageDead(_45); + StorageDead(_22); diff --git a/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff index eb757e091145..94b89a310baa 100644 --- a/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff +++ b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff @@ -123,7 +123,7 @@ - } - - bb2: { -+ _4 = Pin::<&mut {async fn body of ActionPermit<'_, T>::perform()}> { __pointer: copy _5 }; ++ _4 = Pin::<&mut {async fn body of ActionPermit<'_, T>::perform()}> { pointer: copy _5 }; StorageDead(_5); StorageLive(_6); StorageLive(_7); @@ -235,7 +235,7 @@ + _37 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()}); + _21 = &mut (((*_37) as variant#3).1: std::future::Ready<()>); + _20 = &mut (*_21); -+ _19 = Pin::<&mut std::future::Ready<()>> { __pointer: copy _20 }; ++ _19 = Pin::<&mut std::future::Ready<()>> { pointer: copy _20 }; + StorageDead(_20); + StorageLive(_22); + StorageLive(_23); @@ -246,7 +246,6 @@ + StorageDead(_24); + StorageLive(_47); + StorageLive(_48); -+ StorageLive(_51); + StorageLive(_53); + StorageLive(_44); + StorageLive(_45); @@ -257,12 +256,14 @@ + _50 = &mut (_19.0: &mut std::future::Ready<()>); + _47 = copy (_19.0: &mut std::future::Ready<()>); + StorageDead(_50); -+ _49 = Pin::<&mut std::future::Ready<()>> { __pointer: copy _47 }; ++ _49 = Pin::<&mut std::future::Ready<()>> { pointer: copy _47 }; + StorageDead(_49); + _46 = &mut ((*_47).0: std::option::Option<()>); ++ StorageLive(_51); + _51 = Option::<()>::None; + _45 = copy ((*_47).0: std::option::Option<()>); + ((*_47).0: std::option::Option<()>) = copy _51; ++ StorageDead(_51); + StorageDead(_46); + StorageLive(_52); + _52 = discriminant(_45); @@ -363,7 +364,6 @@ + _18 = Poll::<()>::Ready(move _44); + StorageDead(_44); + StorageDead(_53); -+ StorageDead(_51); + StorageDead(_48); + StorageDead(_47); + StorageDead(_22); diff --git a/tests/mir-opt/jump_threading.bitwise_not.JumpThreading.panic-abort.diff b/tests/mir-opt/jump_threading.bitwise_not.JumpThreading.panic-abort.diff index 047441e60991..c3272f21d6c1 100644 --- a/tests/mir-opt/jump_threading.bitwise_not.JumpThreading.panic-abort.diff +++ b/tests/mir-opt/jump_threading.bitwise_not.JumpThreading.panic-abort.diff @@ -3,7 +3,7 @@ fn bitwise_not() -> i32 { let mut _0: i32; - let mut _1: i32; + let _1: i32; let mut _2: bool; let mut _3: i32; let mut _4: i32; @@ -13,7 +13,6 @@ bb0: { StorageLive(_1); - _1 = const 0_i32; _1 = const 1_i32; StorageLive(_2); StorageLive(_3); @@ -22,7 +21,8 @@ _3 = Not(move _4); StorageDead(_4); _2 = Eq(move _3, const 0_i32); - switchInt(move _2) -> [0: bb2, otherwise: bb1]; +- switchInt(move _2) -> [0: bb2, otherwise: bb1]; ++ goto -> bb2; } bb1: { diff --git a/tests/mir-opt/jump_threading.bitwise_not.JumpThreading.panic-unwind.diff b/tests/mir-opt/jump_threading.bitwise_not.JumpThreading.panic-unwind.diff index 047441e60991..c3272f21d6c1 100644 --- a/tests/mir-opt/jump_threading.bitwise_not.JumpThreading.panic-unwind.diff +++ b/tests/mir-opt/jump_threading.bitwise_not.JumpThreading.panic-unwind.diff @@ -3,7 +3,7 @@ fn bitwise_not() -> i32 { let mut _0: i32; - let mut _1: i32; + let _1: i32; let mut _2: bool; let mut _3: i32; let mut _4: i32; @@ -13,7 +13,6 @@ bb0: { StorageLive(_1); - _1 = const 0_i32; _1 = const 1_i32; StorageLive(_2); StorageLive(_3); @@ -22,7 +21,8 @@ _3 = Not(move _4); StorageDead(_4); _2 = Eq(move _3, const 0_i32); - switchInt(move _2) -> [0: bb2, otherwise: bb1]; +- switchInt(move _2) -> [0: bb2, otherwise: bb1]; ++ goto -> bb2; } bb1: { diff --git a/tests/mir-opt/jump_threading.logical_not.JumpThreading.panic-abort.diff b/tests/mir-opt/jump_threading.logical_not.JumpThreading.panic-abort.diff new file mode 100644 index 000000000000..ad8be1ef5a18 --- /dev/null +++ b/tests/mir-opt/jump_threading.logical_not.JumpThreading.panic-abort.diff @@ -0,0 +1,46 @@ +- // MIR for `logical_not` before JumpThreading ++ // MIR for `logical_not` after JumpThreading + + fn logical_not() -> i32 { + let mut _0: i32; + let _1: bool; + let mut _2: bool; + let mut _3: bool; + let mut _4: bool; + scope 1 { + debug a => _1; + } + + bb0: { + StorageLive(_1); + _1 = const false; + StorageLive(_2); + StorageLive(_3); + StorageLive(_4); + _4 = copy _1; + _3 = Not(move _4); + StorageDead(_4); + _2 = Eq(move _3, const true); +- switchInt(move _2) -> [0: bb2, otherwise: bb1]; ++ goto -> bb1; + } + + bb1: { + StorageDead(_3); + _0 = const 1_i32; + goto -> bb3; + } + + bb2: { + StorageDead(_3); + _0 = const 0_i32; + goto -> bb3; + } + + bb3: { + StorageDead(_2); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/jump_threading.logical_not.JumpThreading.panic-unwind.diff b/tests/mir-opt/jump_threading.logical_not.JumpThreading.panic-unwind.diff new file mode 100644 index 000000000000..ad8be1ef5a18 --- /dev/null +++ b/tests/mir-opt/jump_threading.logical_not.JumpThreading.panic-unwind.diff @@ -0,0 +1,46 @@ +- // MIR for `logical_not` before JumpThreading ++ // MIR for `logical_not` after JumpThreading + + fn logical_not() -> i32 { + let mut _0: i32; + let _1: bool; + let mut _2: bool; + let mut _3: bool; + let mut _4: bool; + scope 1 { + debug a => _1; + } + + bb0: { + StorageLive(_1); + _1 = const false; + StorageLive(_2); + StorageLive(_3); + StorageLive(_4); + _4 = copy _1; + _3 = Not(move _4); + StorageDead(_4); + _2 = Eq(move _3, const true); +- switchInt(move _2) -> [0: bb2, otherwise: bb1]; ++ goto -> bb1; + } + + bb1: { + StorageDead(_3); + _0 = const 1_i32; + goto -> bb3; + } + + bb2: { + StorageDead(_3); + _0 = const 0_i32; + goto -> bb3; + } + + bb3: { + StorageDead(_2); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/jump_threading.rs b/tests/mir-opt/jump_threading.rs index 743ee8e728bb..009e1060700c 100644 --- a/tests/mir-opt/jump_threading.rs +++ b/tests/mir-opt/jump_threading.rs @@ -532,14 +532,19 @@ fn floats() -> u32 { pub fn bitwise_not() -> i32 { // CHECK-LABEL: fn bitwise_not( - // CHECK: switchInt( // Test for #131195, which was optimizing `!a == b` into `a != b`. - let mut a: i32 = 0; - a = 1; + let a = 1; if !a == 0 { 1 } else { 0 } } +pub fn logical_not() -> i32 { + // CHECK-LABEL: fn logical_not( + + let a = false; + if !a == true { 1 } else { 0 } +} + fn main() { // CHECK-LABEL: fn main( too_complex(Ok(0)); @@ -555,6 +560,8 @@ fn main() { aggregate(7); assume(7, false); floats(); + bitwise_not(); + logical_not(); } // EMIT_MIR jump_threading.too_complex.JumpThreading.diff @@ -572,3 +579,4 @@ fn main() { // EMIT_MIR jump_threading.aggregate_copy.JumpThreading.diff // EMIT_MIR jump_threading.floats.JumpThreading.diff // EMIT_MIR jump_threading.bitwise_not.JumpThreading.diff +// EMIT_MIR jump_threading.logical_not.JumpThreading.diff diff --git a/tests/mir-opt/lower_intrinsics.rs b/tests/mir-opt/lower_intrinsics.rs index 4859d9354619..5afddc5ff730 100644 --- a/tests/mir-opt/lower_intrinsics.rs +++ b/tests/mir-opt/lower_intrinsics.rs @@ -153,11 +153,10 @@ pub fn discriminant(t: T) { core::intrinsics::discriminant_value(&E::B); } -extern "rust-intrinsic" { - // Cannot use `std::intrinsics::copy_nonoverlapping` as that is a wrapper function - #[rustc_nounwind] - fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize); -} +// Cannot use `std::intrinsics::copy_nonoverlapping` as that is a wrapper function +#[rustc_nounwind] +#[rustc_intrinsic] +unsafe fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize); // EMIT_MIR lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.diff pub fn f_copy_nonoverlapping() { diff --git a/tests/mir-opt/lower_intrinsics.three_way_compare_char.LowerIntrinsics.panic-unwind.diff b/tests/mir-opt/lower_intrinsics.three_way_compare_char.LowerIntrinsics.panic-unwind.diff index 596ad70b3bfa..f29bc5dfc6e4 100644 --- a/tests/mir-opt/lower_intrinsics.three_way_compare_char.LowerIntrinsics.panic-unwind.diff +++ b/tests/mir-opt/lower_intrinsics.three_way_compare_char.LowerIntrinsics.panic-unwind.diff @@ -18,7 +18,7 @@ _4 = copy _1; StorageLive(_5); _5 = copy _2; -- _3 = three_way_compare::(move _4, move _5) -> [return: bb1, unwind continue]; +- _3 = three_way_compare::(move _4, move _5) -> [return: bb1, unwind unreachable]; + _3 = Cmp(move _4, move _5); + goto -> bb1; } diff --git a/tests/mir-opt/lower_intrinsics.three_way_compare_signed.LowerIntrinsics.panic-unwind.diff b/tests/mir-opt/lower_intrinsics.three_way_compare_signed.LowerIntrinsics.panic-unwind.diff index 987c21666927..654cb2503df5 100644 --- a/tests/mir-opt/lower_intrinsics.three_way_compare_signed.LowerIntrinsics.panic-unwind.diff +++ b/tests/mir-opt/lower_intrinsics.three_way_compare_signed.LowerIntrinsics.panic-unwind.diff @@ -15,7 +15,7 @@ _4 = copy _1; StorageLive(_5); _5 = copy _2; -- _3 = three_way_compare::(move _4, move _5) -> [return: bb1, unwind continue]; +- _3 = three_way_compare::(move _4, move _5) -> [return: bb1, unwind unreachable]; + _3 = Cmp(move _4, move _5); + goto -> bb1; } diff --git a/tests/mir-opt/lower_intrinsics.three_way_compare_unsigned.LowerIntrinsics.panic-unwind.diff b/tests/mir-opt/lower_intrinsics.three_way_compare_unsigned.LowerIntrinsics.panic-unwind.diff index d7ec6dcfa2c3..82c89b7ce549 100644 --- a/tests/mir-opt/lower_intrinsics.three_way_compare_unsigned.LowerIntrinsics.panic-unwind.diff +++ b/tests/mir-opt/lower_intrinsics.three_way_compare_unsigned.LowerIntrinsics.panic-unwind.diff @@ -18,7 +18,7 @@ _4 = copy _1; StorageLive(_5); _5 = copy _2; -- _3 = three_way_compare::(move _4, move _5) -> [return: bb1, unwind continue]; +- _3 = three_way_compare::(move _4, move _5) -> [return: bb1, unwind unreachable]; + _3 = Cmp(move _4, move _5); + goto -> bb1; } diff --git a/tests/mir-opt/pre-codegen/derived_ord.demo_le.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/derived_ord.demo_le.PreCodegen.after.mir index 49314a64c3fc..8746cb089916 100644 --- a/tests/mir-opt/pre-codegen/derived_ord.demo_le.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/derived_ord.demo_le.PreCodegen.after.mir @@ -40,6 +40,7 @@ fn demo_le(_1: &MultiField, _2: &MultiField) -> bool { StorageLive(_12); StorageLive(_11); StorageLive(_5); + StorageLive(_6); StorageLive(_7); StorageLive(_3); _3 = copy ((*_1).0: char); @@ -65,6 +66,7 @@ fn demo_le(_1: &MultiField, _2: &MultiField) -> bool { _11 = Option::::Some(move _10); StorageDead(_10); StorageDead(_7); + StorageDead(_6); StorageDead(_5); goto -> bb3; } @@ -72,6 +74,7 @@ fn demo_le(_1: &MultiField, _2: &MultiField) -> bool { bb2: { _11 = copy _6; StorageDead(_7); + StorageDead(_6); StorageDead(_5); goto -> bb3; } diff --git a/tests/mir-opt/pre-codegen/tuple_ord.demo_ge_partial.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/tuple_ord.demo_ge_partial.PreCodegen.after.mir index dd2eebc8f4a1..c4d0e318b58d 100644 --- a/tests/mir-opt/pre-codegen/tuple_ord.demo_ge_partial.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/tuple_ord.demo_ge_partial.PreCodegen.after.mir @@ -44,8 +44,10 @@ fn demo_ge_partial(_1: &(f32, f32), _2: &(f32, f32)) -> bool { StorageDead(_5); StorageDead(_4); StorageDead(_3); + StorageLive(_8); _8 = copy ((_7 as Break).0: bool); _0 = copy _8; + StorageDead(_8); goto -> bb3; } diff --git a/tests/mir-opt/pre-codegen/tuple_ord.demo_le_total.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/tuple_ord.demo_le_total.PreCodegen.after.mir index ea1d164cefaf..44df8b279935 100644 --- a/tests/mir-opt/pre-codegen/tuple_ord.demo_le_total.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/tuple_ord.demo_le_total.PreCodegen.after.mir @@ -44,8 +44,10 @@ fn demo_le_total(_1: &(u16, i16), _2: &(u16, i16)) -> bool { StorageDead(_5); StorageDead(_4); StorageDead(_3); + StorageLive(_8); _8 = copy ((_7 as Break).0: bool); _0 = copy _8; + StorageDead(_8); goto -> bb3; } diff --git a/tests/mir-opt/tail_expr_drop_order_unwind.method_1.ElaborateDrops.after.panic-abort.mir b/tests/mir-opt/tail_expr_drop_order_unwind.method_1.ElaborateDrops.after.panic-abort.mir index ee6e16d20fd8..7d7cb76960ed 100644 --- a/tests/mir-opt/tail_expr_drop_order_unwind.method_1.ElaborateDrops.after.panic-abort.mir +++ b/tests/mir-opt/tail_expr_drop_order_unwind.method_1.ElaborateDrops.after.panic-abort.mir @@ -73,9 +73,6 @@ fn method_1(_1: Guard) -> () { } bb7: { - backward incompatible drop(_2); - backward incompatible drop(_4); - backward incompatible drop(_5); goto -> bb21; } diff --git a/tests/mir-opt/tail_expr_drop_order_unwind.method_1.ElaborateDrops.after.panic-unwind.mir b/tests/mir-opt/tail_expr_drop_order_unwind.method_1.ElaborateDrops.after.panic-unwind.mir index ee6e16d20fd8..7d7cb76960ed 100644 --- a/tests/mir-opt/tail_expr_drop_order_unwind.method_1.ElaborateDrops.after.panic-unwind.mir +++ b/tests/mir-opt/tail_expr_drop_order_unwind.method_1.ElaborateDrops.after.panic-unwind.mir @@ -73,9 +73,6 @@ fn method_1(_1: Guard) -> () { } bb7: { - backward incompatible drop(_2); - backward incompatible drop(_4); - backward incompatible drop(_5); goto -> bb21; } diff --git a/tests/pretty/ast-stmt-expr-attr.rs b/tests/pretty/ast-stmt-expr-attr.rs index fd7272a1b1fd..4ca60465b54c 100644 --- a/tests/pretty/ast-stmt-expr-attr.rs +++ b/tests/pretty/ast-stmt-expr-attr.rs @@ -2,7 +2,7 @@ fn main() {} -#[cfg(FALSE)] +#[cfg(false)] fn syntax() { let _ = #[attr] []; let _ = #[attr] [0]; diff --git a/tests/pretty/autodiff_forward.pp b/tests/pretty/autodiff_forward.pp index 4b2fb6166ff7..713b8f541ae0 100644 --- a/tests/pretty/autodiff_forward.pp +++ b/tests/pretty/autodiff_forward.pp @@ -29,6 +29,8 @@ pub fn f1(x: &[f64], y: f64) -> f64 { // Make sure, that we add the None for the default return. + // We want to make sure that we can use the macro for functions defined inside of functions + ::core::panicking::panic("not implemented") } #[rustc_autodiff(Forward, 1, Dual, Const, Dual)] @@ -158,4 +160,25 @@ fn f8_1(x: &f32, bx_0: &f32) -> f32 { ::core::hint::black_box((bx_0,)); ::core::hint::black_box(::default()) } +pub fn f9() { + #[rustc_autodiff] + #[inline(never)] + fn inner(x: f32) -> f32 { x * x } + #[rustc_autodiff(Forward, 1, Dual, Dual)] + #[inline(never)] + fn d_inner_2(x: f32, bx_0: f32) -> (f32, f32) { + unsafe { asm!("NOP", options(pure, nomem)); }; + ::core::hint::black_box(inner(x)); + ::core::hint::black_box((bx_0,)); + ::core::hint::black_box(<(f32, f32)>::default()) + } + #[rustc_autodiff(Forward, 1, Dual, DualOnly)] + #[inline(never)] + fn d_inner_1(x: f32, bx_0: f32) -> f32 { + unsafe { asm!("NOP", options(pure, nomem)); }; + ::core::hint::black_box(inner(x)); + ::core::hint::black_box((bx_0,)); + ::core::hint::black_box(::default()) + } +} fn main() {} diff --git a/tests/pretty/autodiff_forward.rs b/tests/pretty/autodiff_forward.rs index a765738c2a81..5a0660a08e52 100644 --- a/tests/pretty/autodiff_forward.rs +++ b/tests/pretty/autodiff_forward.rs @@ -54,4 +54,13 @@ fn f8(x: &f32) -> f32 { unimplemented!() } +// We want to make sure that we can use the macro for functions defined inside of functions +pub fn f9() { + #[autodiff(d_inner_1, Forward, Dual, DualOnly)] + #[autodiff(d_inner_2, Forward, Dual, Dual)] + fn inner(x: f32) -> f32 { + x * x + } +} + fn main() {} diff --git a/tests/pretty/enum-variant-vis.rs b/tests/pretty/enum-variant-vis.rs index 3397e7dc8e28..5b9f7e037595 100644 --- a/tests/pretty/enum-variant-vis.rs +++ b/tests/pretty/enum-variant-vis.rs @@ -4,5 +4,5 @@ fn main() {} -#[cfg(FALSE)] +#[cfg(false)] enum Foo { pub V, } diff --git a/tests/pretty/hir-delegation.pp b/tests/pretty/hir-delegation.pp new file mode 100644 index 000000000000..872a6a45aede --- /dev/null +++ b/tests/pretty/hir-delegation.pp @@ -0,0 +1,23 @@ +//@ pretty-compare-only +//@ pretty-mode:hir +//@ pp-exact:hir-delegation.pp + +#![allow(incomplete_features)]#![feature(fn_delegation)] +#[prelude_import] +use ::std::prelude::rust_2015::*; +#[macro_use] +extern crate std; + +fn b(e: C) { } + +trait G { + fn b(arg0: _) -> _ { b({ }) } +} + +mod m { + fn add(a: u32, b: u32) -> u32 { a + b } +} + +fn add(arg0: _, arg1: _) -> _ { m::add(arg0, arg1) } + +fn main() { { let _ = add(1, 2); }; } diff --git a/tests/pretty/hir-delegation.rs b/tests/pretty/hir-delegation.rs new file mode 100644 index 000000000000..9e351a1e32f3 --- /dev/null +++ b/tests/pretty/hir-delegation.rs @@ -0,0 +1,22 @@ +//@ pretty-compare-only +//@ pretty-mode:hir +//@ pp-exact:hir-delegation.pp + +#![allow(incomplete_features)] +#![feature(fn_delegation)] + +fn b(e: C) {} + +trait G { + reuse b {} +} + +mod m { + pub fn add(a: u32, b: u32) -> u32 { a + b } +} + +reuse m::add; + +fn main() { + _ = add(1, 2); +} diff --git a/tests/pretty/hir-fn-variadic.pp b/tests/pretty/hir-fn-variadic.pp index dfbaff696440..b6bc8e95127f 100644 --- a/tests/pretty/hir-fn-variadic.pp +++ b/tests/pretty/hir-fn-variadic.pp @@ -13,3 +13,39 @@ extern "C" { } unsafe extern "C" fn bar(_: i32, mut va2: ...) -> usize { va2.arg::() } + +fn main() { + fn g1(_: extern "C" fn(_: u8, va: ...)) { } + fn g2(_: extern "C" fn(_: u8, ...)) { } + fn g3(_: extern "C" fn(u8, va: ...)) { } + fn g4(_: extern "C" fn(u8, ...)) { } + + fn g5(_: extern "C" fn(va: ...)) { } + fn g6(_: extern "C" fn(...)) { } + + { + let _ = + { + unsafe extern "C" fn f1(_: u8, va: ...) { } + }; + }; + { + let _ = + { + unsafe extern "C" fn f2(_: u8, _: ...) { } + }; + }; + + { + let _ = + { + unsafe extern "C" fn f5(va: ...) { } + }; + }; + { + let _ = + { + unsafe extern "C" fn f6(_: ...) { } + }; + }; +} diff --git a/tests/pretty/hir-fn-variadic.rs b/tests/pretty/hir-fn-variadic.rs index 3d3f7ee18315..99aa402c480b 100644 --- a/tests/pretty/hir-fn-variadic.rs +++ b/tests/pretty/hir-fn-variadic.rs @@ -11,3 +11,19 @@ extern "C" { pub unsafe extern "C" fn bar(_: i32, mut va2: ...) -> usize { va2.arg::() } + +fn main() { + fn g1(_: extern "C" fn(_: u8, va: ...)) {} + fn g2(_: extern "C" fn(_: u8, ...)) {} + fn g3(_: extern "C" fn(u8, va: ...)) {} + fn g4(_: extern "C" fn(u8, ...)) {} + + fn g5(_: extern "C" fn(va: ...)) {} + fn g6(_: extern "C" fn(...)) {} + + _ = { unsafe extern "C" fn f1(_: u8, va: ...) {} }; + _ = { unsafe extern "C" fn f2(_: u8, ...) {} }; + + _ = { unsafe extern "C" fn f5(va: ...) {} }; + _ = { unsafe extern "C" fn f6(...) {} }; +} diff --git a/tests/pretty/if-attr.rs b/tests/pretty/if-attr.rs index 89d6130f6592..8b343a83a1c5 100644 --- a/tests/pretty/if-attr.rs +++ b/tests/pretty/if-attr.rs @@ -1,6 +1,6 @@ //@ pp-exact -#[cfg(FALSE)] +#[cfg(false)] fn simple_attr() { #[attr] @@ -10,21 +10,21 @@ fn simple_attr() { if true {} } -#[cfg(FALSE)] +#[cfg(false)] fn if_else_chain() { #[first_attr] if true {} else if false {} else {} } -#[cfg(FALSE)] +#[cfg(false)] fn if_let() { #[attr] if let Some(_) = Some(true) {} } -#[cfg(FALSE)] +#[cfg(false)] fn let_attr_if() { let _ = #[attr] if let _ = 0 {}; let _ = #[attr] if true {}; diff --git a/tests/pretty/nested-item-vis-defaultness.rs b/tests/pretty/nested-item-vis-defaultness.rs index 1e971fcf07a5..68f56a1be450 100644 --- a/tests/pretty/nested-item-vis-defaultness.rs +++ b/tests/pretty/nested-item-vis-defaultness.rs @@ -4,7 +4,7 @@ fn main() {} -#[cfg(FALSE)] +#[cfg(false)] extern "C" { static X: u8; type X; @@ -14,7 +14,7 @@ extern "C" { pub fn foo(); } -#[cfg(FALSE)] +#[cfg(false)] trait T { const X: u8; type X; @@ -30,7 +30,7 @@ trait T { pub default fn foo(); } -#[cfg(FALSE)] +#[cfg(false)] impl T for S { const X: u8; type X; diff --git a/tests/pretty/postfix-yield.rs b/tests/pretty/postfix-yield.rs index f76e8142ae86..60380a4071c5 100644 --- a/tests/pretty/postfix-yield.rs +++ b/tests/pretty/postfix-yield.rs @@ -2,7 +2,8 @@ //@ edition: 2024 //@ pp-exact -#![feature(gen_blocks, coroutines, coroutine_trait, yield_expr)] +#![feature(gen_blocks, coroutines, coroutine_trait, yield_expr, +stmt_expr_attributes)] use std::ops::{Coroutine, CoroutineState}; use std::pin::pin; diff --git a/tests/run-make/atomic-lock-free/atomic_lock_free.rs b/tests/run-make/atomic-lock-free/atomic_lock_free.rs index 1f1116b9bfd1..b49c5044f31d 100644 --- a/tests/run-make/atomic-lock-free/atomic_lock_free.rs +++ b/tests/run-make/atomic-lock-free/atomic_lock_free.rs @@ -2,9 +2,8 @@ #![crate_type = "rlib"] #![no_core] -extern "rust-intrinsic" { - fn atomic_xadd_seqcst(dst: *mut T, src: T) -> T; -} +#[rustc_intrinsic] +unsafe fn atomic_xadd_seqcst(dst: *mut T, src: T) -> T; #[lang = "sized"] trait Sized {} diff --git a/tests/run-make/avr-rjmp-offset/avr-rjmp-offsets.rs b/tests/run-make/avr-rjmp-offset/avr-rjmp-offsets.rs index 2f97fc1ed95a..c91cd695ceea 100644 --- a/tests/run-make/avr-rjmp-offset/avr-rjmp-offsets.rs +++ b/tests/run-make/avr-rjmp-offset/avr-rjmp-offsets.rs @@ -37,10 +37,9 @@ mod minicore { #[inline] #[rustc_diagnostic_item = "ptr_write_volatile"] pub unsafe fn write_volatile(dst: *mut T, src: T) { - extern "rust-intrinsic" { - #[rustc_nounwind] - pub fn volatile_store(dst: *mut T, val: T); - } + #[rustc_intrinsic] + pub unsafe fn volatile_store(dst: *mut T, val: T); + unsafe { volatile_store(dst, src) }; } } diff --git a/tests/run-make/broken-pipe-no-ice/rmake.rs b/tests/run-make/broken-pipe-no-ice/rmake.rs index 3e54b576fd42..0521b3950207 100644 --- a/tests/run-make/broken-pipe-no-ice/rmake.rs +++ b/tests/run-make/broken-pipe-no-ice/rmake.rs @@ -14,9 +14,7 @@ use std::io::Read; use std::process::{Command, Stdio}; -// FIXME(#137532): replace `os_pipe` dependency with std `anonymous_pipe` once that stabilizes and -// reaches beta. -use run_make_support::{env_var, os_pipe}; +use run_make_support::env_var; #[derive(Debug, PartialEq)] enum Binary { @@ -25,7 +23,7 @@ enum Binary { } fn check_broken_pipe_handled_gracefully(bin: Binary, mut cmd: Command) { - let (reader, writer) = os_pipe::pipe().unwrap(); + let (reader, writer) = std::io::pipe().unwrap(); drop(reader); // close read-end cmd.stdout(writer).stderr(Stdio::piped()); diff --git a/tests/run-make/crate-data-smoke/rmake.rs b/tests/run-make/crate-data-smoke/rmake.rs index 70f8e46b6d92..b5708d05a82b 100644 --- a/tests/run-make/crate-data-smoke/rmake.rs +++ b/tests/run-make/crate-data-smoke/rmake.rs @@ -1,9 +1,20 @@ -use run_make_support::{bin_name, rust_lib_name, rustc}; +use run_make_support::{bin_name, rust_lib_name, rustc, target}; fn main() { - rustc().print("crate-name").input("crate.rs").run().assert_stdout_equals("foo"); - rustc().print("file-names").input("crate.rs").run().assert_stdout_equals(bin_name("foo")); rustc() + .target(target()) + .print("crate-name") + .input("crate.rs") + .run() + .assert_stdout_equals("foo"); + rustc() + .target(target()) + .print("file-names") + .input("crate.rs") + .run() + .assert_stdout_equals(bin_name("foo")); + rustc() + .target(target()) .print("file-names") .crate_type("lib") .arg("--test") @@ -11,11 +22,22 @@ fn main() { .run() .assert_stdout_equals(bin_name("foo")); rustc() + .target(target()) .print("file-names") .arg("--test") .input("lib.rs") .run() .assert_stdout_equals(bin_name("mylib")); - rustc().print("file-names").input("lib.rs").run().assert_stdout_equals(rust_lib_name("mylib")); - rustc().print("file-names").input("rlib.rs").run().assert_stdout_equals(rust_lib_name("mylib")); + rustc() + .target(target()) + .print("file-names") + .input("lib.rs") + .run() + .assert_stdout_equals(rust_lib_name("mylib")); + rustc() + .target(target()) + .print("file-names") + .input("rlib.rs") + .run() + .assert_stdout_equals(rust_lib_name("mylib")); } diff --git a/tests/run-make/crate-name-priority/rmake.rs b/tests/run-make/crate-name-priority/rmake.rs index 5bdb49b33cea..82e482b5a2ef 100644 --- a/tests/run-make/crate-name-priority/rmake.rs +++ b/tests/run-make/crate-name-priority/rmake.rs @@ -4,6 +4,8 @@ // and the compiler flags, and checks that the flag is favoured each time. // See https://github.com/rust-lang/rust/pull/15518 +//@ ignore-cross-compile (relocations in generic ELF against `arm-unknown-linux-gnueabihf`) + use run_make_support::{bin_name, rfs, rustc}; fn main() { diff --git a/tests/run-make/dirty-incr-due-to-hard-link/rmake.rs b/tests/run-make/dirty-incr-due-to-hard-link/rmake.rs new file mode 100644 index 000000000000..942b667814a9 --- /dev/null +++ b/tests/run-make/dirty-incr-due-to-hard-link/rmake.rs @@ -0,0 +1,32 @@ +//@ only-x86_64-unknown-linux-gnu + +// Regression test for the incremental bug in . +// +// A detailed explanation is described in , +// however the gist of the issue is that hard-linking temporary files can interact strangely +// across incremental sessions that are not finalized due to errors originating from the +// codegen backend. + +use run_make_support::{run, rustc}; + +fn main() { + let mk_rustc = || { + let mut rustc = rustc(); + rustc.input("test.rs").incremental("incr").arg("-Csave-temps").output("test"); + rustc + }; + + // Revision 1 + mk_rustc().cfg("rpass1").run(); + + run("test"); + + // Revision 2 + mk_rustc().cfg("cfail2").run_fail(); + // Expected to fail. + + // Revision 3 + mk_rustc().cfg("rpass3").run(); + + run("test"); +} diff --git a/tests/run-make/dirty-incr-due-to-hard-link/test.rs b/tests/run-make/dirty-incr-due-to-hard-link/test.rs new file mode 100644 index 000000000000..dba5a6bbc826 --- /dev/null +++ b/tests/run-make/dirty-incr-due-to-hard-link/test.rs @@ -0,0 +1,31 @@ +#[inline(never)] +#[cfg(any(rpass1, rpass3))] +fn a() -> i32 { + 0 +} + +#[cfg(any(cfail2))] +fn a() -> i32 { + 1 +} + +fn main() { + evil::evil(); + assert_eq!(a(), 0); +} + +mod evil { + #[cfg(any(rpass1, rpass3))] + pub fn evil() { + unsafe { + std::arch::asm!("/* */"); + } + } + + #[cfg(any(cfail2))] + pub fn evil() { + unsafe { + std::arch::asm!("missing"); + } + } +} diff --git a/tests/run-make/embed-source-dwarf/rmake.rs b/tests/run-make/embed-source-dwarf/rmake.rs index 0aae07ff2e64..550c8b9b3c90 100644 --- a/tests/run-make/embed-source-dwarf/rmake.rs +++ b/tests/run-make/embed-source-dwarf/rmake.rs @@ -21,7 +21,7 @@ fn main() { .output(&output) .arg("-g") .arg("-Zembed-source=yes") - .arg("-Zdwarf-version=5") + .arg("-Cdwarf-version=5") .run(); let output = rfs::read(output); let obj = object::File::parse(output.as_slice()).unwrap(); diff --git a/tests/run-make/extra-filename-with-temp-outputs/rmake.rs b/tests/run-make/extra-filename-with-temp-outputs/rmake.rs index 0910045bb857..f93a3ecc8d1b 100644 --- a/tests/run-make/extra-filename-with-temp-outputs/rmake.rs +++ b/tests/run-make/extra-filename-with-temp-outputs/rmake.rs @@ -6,6 +6,8 @@ // are named as expected. // See https://github.com/rust-lang/rust/pull/15686 +//@ ignore-cross-compile (relocations in generic ELF against `arm-unknown-linux-gnueabihf`) + use run_make_support::{bin_name, cwd, has_prefix, has_suffix, rfs, rustc, shallow_find_files}; fn main() { diff --git a/tests/run-make/output-type-permutations/rmake.rs b/tests/run-make/output-type-permutations/rmake.rs index c0569af6e84a..8da0bfaa12db 100644 --- a/tests/run-make/output-type-permutations/rmake.rs +++ b/tests/run-make/output-type-permutations/rmake.rs @@ -4,6 +4,9 @@ // files are exactly what is expected, no more, no less. // See https://github.com/rust-lang/rust/pull/12020 +//@ ignore-cross-compile +// Reason: some cross-compiled targets don't support various crate types and fail to link. + use std::path::PathBuf; use run_make_support::{ @@ -17,6 +20,7 @@ use run_make_support::{ // `dir`: the name of the directory where the test happens // `rustc_invocation`: the rustc command being tested // Any unexpected output files not listed in `must_exist` or `can_exist` will cause a failure. +#[track_caller] fn assert_expected_output_files(expectations: Expectations, rustc_invocation: impl Fn()) { let Expectations { expected_files: must_exist, allowed_files: can_exist, test_dir: dir } = expectations; diff --git a/tests/run-make/print-request-help-stable-unstable/help-diff.diff b/tests/run-make/print-request-help-stable-unstable/help-diff.diff new file mode 100644 index 000000000000..07eafca32710 --- /dev/null +++ b/tests/run-make/print-request-help-stable-unstable/help-diff.diff @@ -0,0 +1,7 @@ +@@ -1,5 +1,5 @@ + error: unknown print request: `xxx` + | +- = help: valid print requests are: `calling-conventions`, `cfg`, `code-models`, `crate-name`, `deployment-target`, `file-names`, `host-tuple`, `link-args`, `native-static-libs`, `relocation-models`, `split-debuginfo`, `stack-protector-strategies`, `sysroot`, `target-cpus`, `target-features`, `target-libdir`, `target-list`, `tls-models` ++ = help: valid print requests are: `all-target-specs-json`, `calling-conventions`, `cfg`, `check-cfg`, `code-models`, `crate-name`, `crate-root-lint-levels`, `deployment-target`, `file-names`, `host-tuple`, `link-args`, `native-static-libs`, `relocation-models`, `split-debuginfo`, `stack-protector-strategies`, `supported-crate-types`, `sysroot`, `target-cpus`, `target-features`, `target-libdir`, `target-list`, `target-spec-json`, `tls-models` + = help: for more information, see the rustc book: https://doc.rust-lang.org/rustc/command-line-arguments.html#--print-print-compiler-information + diff --git a/tests/run-make/print-request-help-stable-unstable/rmake.rs b/tests/run-make/print-request-help-stable-unstable/rmake.rs new file mode 100644 index 000000000000..a59963da5c49 --- /dev/null +++ b/tests/run-make/print-request-help-stable-unstable/rmake.rs @@ -0,0 +1,33 @@ +//! Check that unstable print requests are omitted from help if compiler is in stable channel. +//! +//! Issue: +use run_make_support::{diff, rustc, similar}; + +fn main() { + let stable_invalid_print_request_help = rustc() + .env("RUSTC_BOOTSTRAP", "-1") + .cfg("force_stable") + .print("xxx") + .run_fail() + .stderr_utf8(); + assert!(!stable_invalid_print_request_help.contains("all-target-specs-json")); + diff() + .expected_file("stable-invalid-print-request-help.err") + .actual_text("stable_invalid_print_request_help", &stable_invalid_print_request_help) + .run(); + + let unstable_invalid_print_request_help = rustc().print("xxx").run_fail().stderr_utf8(); + assert!(unstable_invalid_print_request_help.contains("all-target-specs-json")); + diff() + .expected_file("unstable-invalid-print-request-help.err") + .actual_text("unstable_invalid_print_request_help", &unstable_invalid_print_request_help) + .run(); + + let help_diff = similar::TextDiff::from_lines( + &stable_invalid_print_request_help, + &unstable_invalid_print_request_help, + ) + .unified_diff() + .to_string(); + diff().expected_file("help-diff.diff").actual_text("help_diff", help_diff).run(); +} diff --git a/tests/run-make/print-request-help-stable-unstable/stable-invalid-print-request-help.err b/tests/run-make/print-request-help-stable-unstable/stable-invalid-print-request-help.err new file mode 100644 index 000000000000..019a578dad3e --- /dev/null +++ b/tests/run-make/print-request-help-stable-unstable/stable-invalid-print-request-help.err @@ -0,0 +1,5 @@ +error: unknown print request: `xxx` + | + = help: valid print requests are: `calling-conventions`, `cfg`, `code-models`, `crate-name`, `deployment-target`, `file-names`, `host-tuple`, `link-args`, `native-static-libs`, `relocation-models`, `split-debuginfo`, `stack-protector-strategies`, `sysroot`, `target-cpus`, `target-features`, `target-libdir`, `target-list`, `tls-models` + = help: for more information, see the rustc book: https://doc.rust-lang.org/rustc/command-line-arguments.html#--print-print-compiler-information + diff --git a/tests/run-make/print-request-help-stable-unstable/unstable-invalid-print-request-help.err b/tests/run-make/print-request-help-stable-unstable/unstable-invalid-print-request-help.err new file mode 100644 index 000000000000..50ef340e3dd0 --- /dev/null +++ b/tests/run-make/print-request-help-stable-unstable/unstable-invalid-print-request-help.err @@ -0,0 +1,5 @@ +error: unknown print request: `xxx` + | + = help: valid print requests are: `all-target-specs-json`, `calling-conventions`, `cfg`, `check-cfg`, `code-models`, `crate-name`, `crate-root-lint-levels`, `deployment-target`, `file-names`, `host-tuple`, `link-args`, `native-static-libs`, `relocation-models`, `split-debuginfo`, `stack-protector-strategies`, `supported-crate-types`, `sysroot`, `target-cpus`, `target-features`, `target-libdir`, `target-list`, `target-spec-json`, `tls-models` + = help: for more information, see the rustc book: https://doc.rust-lang.org/rustc/command-line-arguments.html#--print-print-compiler-information + diff --git a/tests/run-make/reproducible-build/rmake.rs b/tests/run-make/reproducible-build/rmake.rs index 8a8b0d6d652b..93fc30de07d7 100644 --- a/tests/run-make/reproducible-build/rmake.rs +++ b/tests/run-make/reproducible-build/rmake.rs @@ -20,6 +20,8 @@ // See https://github.com/rust-lang/rust/pull/32293 // Tracking Issue: https://github.com/rust-lang/rust/issues/129080 +//@ ignore-cross-compile (linker binary needs to run) + use run_make_support::{ bin_name, cwd, diff, is_darwin, is_windows, regex, rfs, run_in_tmpdir, rust_lib_name, rustc, }; diff --git a/tests/run-make/rustc-help/help-v.diff b/tests/run-make/rustc-help/help-v.diff index 22c5dd81bdb0..30703f6424e7 100644 --- a/tests/run-make/rustc-help/help-v.diff +++ b/tests/run-make/rustc-help/help-v.diff @@ -1,4 +1,4 @@ -@@ -51,10 +51,27 @@ +@@ -53,10 +53,27 @@ Set a codegen option -V, --version Print version info and exit -v, --verbose Use verbose output diff --git a/tests/run-make/rustc-help/help-v.stdout b/tests/run-make/rustc-help/help-v.stdout index f19ca1e9f90a..13af6e21060b 100644 --- a/tests/run-make/rustc-help/help-v.stdout +++ b/tests/run-make/rustc-help/help-v.stdout @@ -29,8 +29,10 @@ Options: --emit [asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir] Comma separated list of types of output for the compiler to emit - --print [all-target-specs-json|calling-conventions|cfg|check-cfg|code-models|crate-name|crate-root-lint-levels|deployment-target|file-names|host-tuple|link-args|native-static-libs|relocation-models|split-debuginfo|stack-protector-strategies|supported-crate-types|sysroot|target-cpus|target-features|target-libdir|target-list|target-spec-json|tls-models] - Compiler information to print on stdout + --print INFO[=FILE] + Compiler information to print on stdout (or to a file) + INFO may be one of + (all-target-specs-json|calling-conventions|cfg|check-cfg|code-models|crate-name|crate-root-lint-levels|deployment-target|file-names|host-tuple|link-args|native-static-libs|relocation-models|split-debuginfo|stack-protector-strategies|supported-crate-types|sysroot|target-cpus|target-features|target-libdir|target-list|target-spec-json|tls-models). -g Equivalent to -C debuginfo=2 -O Equivalent to -C opt-level=3 -o FILENAME Write output to diff --git a/tests/run-make/rustc-help/help.stdout b/tests/run-make/rustc-help/help.stdout index f7d352966035..62757d989eb3 100644 --- a/tests/run-make/rustc-help/help.stdout +++ b/tests/run-make/rustc-help/help.stdout @@ -29,8 +29,10 @@ Options: --emit [asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir] Comma separated list of types of output for the compiler to emit - --print [all-target-specs-json|calling-conventions|cfg|check-cfg|code-models|crate-name|crate-root-lint-levels|deployment-target|file-names|host-tuple|link-args|native-static-libs|relocation-models|split-debuginfo|stack-protector-strategies|supported-crate-types|sysroot|target-cpus|target-features|target-libdir|target-list|target-spec-json|tls-models] - Compiler information to print on stdout + --print INFO[=FILE] + Compiler information to print on stdout (or to a file) + INFO may be one of + (all-target-specs-json|calling-conventions|cfg|check-cfg|code-models|crate-name|crate-root-lint-levels|deployment-target|file-names|host-tuple|link-args|native-static-libs|relocation-models|split-debuginfo|stack-protector-strategies|supported-crate-types|sysroot|target-cpus|target-features|target-libdir|target-list|target-spec-json|tls-models). -g Equivalent to -C debuginfo=2 -O Equivalent to -C opt-level=3 -o FILENAME Write output to diff --git a/tests/run-make/strip/rmake.rs b/tests/run-make/strip/rmake.rs index ef1acc26b455..01b31ac30948 100644 --- a/tests/run-make/strip/rmake.rs +++ b/tests/run-make/strip/rmake.rs @@ -1,4 +1,5 @@ -//@ ignore-windows Windows does not actually strip +//@ ignore-windows (Windows does not actually strip) +//@ ignore-cross-compile (relocations in generic ELF against `arm-unknown-linux-gnueabihf`) // Test that -Cstrip correctly strips/preserves debuginfo and symbols. diff --git a/tests/run-make/symbols-all-mangled/rmake.rs b/tests/run-make/symbols-all-mangled/rmake.rs index 1fb03c62399a..79ddd06bb94b 100644 --- a/tests/run-make/symbols-all-mangled/rmake.rs +++ b/tests/run-make/symbols-all-mangled/rmake.rs @@ -1,5 +1,7 @@ // Check that all symbols in cdylibs, staticlibs and bins are mangled //@ only-elf some object file formats create multiple symbols for each function with different names +//@ ignore-nvptx64 (needs target std) +//@ ignore-cross-compile (host-only) use run_make_support::object::read::{Object, ObjectSymbol}; use run_make_support::{bin_name, dynamic_lib_name, object, rfs, rustc, static_lib_name}; diff --git a/tests/run-make/unstable-feature-usage-metrics-incremental/main.rs b/tests/run-make/unstable-feature-usage-metrics-incremental/main.rs new file mode 100644 index 000000000000..f970d395b2cf --- /dev/null +++ b/tests/run-make/unstable-feature-usage-metrics-incremental/main.rs @@ -0,0 +1,16 @@ +#![feature(ascii_char)] // random lib feature +#![feature(box_patterns)] // random lang feature + +// picked arbitrary unstable features, just need a random lib and lang feature, ideally ones that +// won't be stabilized any time soon so we don't have to update this test +fn main() { + for s in quix("foo/bar") { + print!("{s}"); + } + println!(); +} + +// need a latebound var to trigger the incremental compilation ICE +fn quix(foo: &str) -> impl Iterator + '_ { + foo.split('/') +} diff --git a/tests/run-make/unstable-feature-usage-metrics-incremental/rmake.rs b/tests/run-make/unstable-feature-usage-metrics-incremental/rmake.rs new file mode 100644 index 000000000000..7e070d80c793 --- /dev/null +++ b/tests/run-make/unstable-feature-usage-metrics-incremental/rmake.rs @@ -0,0 +1,94 @@ +//! This test checks if unstable feature usage metric dump files `unstable-feature-usage*.json` work +//! as expected. +//! +//! - Basic sanity checks on a default ICE dump. +//! +//! See . +//! +//! # Test history +//! +//! - forked from dump-ice-to-disk test, which has flakeyness issues on i686-mingw, I'm assuming +//! those will be present in this test as well on the same platform + +//@ ignore-windows +//FIXME(#128911): still flakey on i686-mingw. + +use std::path::{Path, PathBuf}; + +use run_make_support::rfs::create_dir_all; +use run_make_support::{ + cwd, filename_contains, has_extension, rfs, run_in_tmpdir, rustc, serde_json, + shallow_find_files, +}; + +fn find_feature_usage_metrics>(dir: P) -> Vec { + shallow_find_files(dir, |path| { + if filename_contains(path, "unstable_feature_usage") && has_extension(path, "json") { + true + } else { + dbg!(path); + false + } + }) +} + +fn main() { + test_metrics_dump(); + test_metrics_errors(); +} + +#[track_caller] +fn test_metrics_dump() { + run_in_tmpdir(|| { + let metrics_dir = cwd().join("metrics"); + create_dir_all(&metrics_dir); + rustc() + .input("main.rs") + .incremental("incremental") + .env("RUST_BACKTRACE", "short") + .arg(format!("-Zmetrics-dir={}", metrics_dir.display())) + .run(); + let mut metrics = find_feature_usage_metrics(&metrics_dir); + let json_path = + metrics.pop().expect("there should be one metrics file in the output directory"); + + // After the `pop` above, there should be no files left. + assert!( + metrics.is_empty(), + "there should be no more than one metrics file in the output directory" + ); + + let message = rfs::read_to_string(json_path); + let mut parsed: serde_json::Value = + serde_json::from_str(&message).expect("metrics should be dumped as json"); + // remove timestamps + assert!(parsed["lib_features"][0]["timestamp"].is_number()); + assert!(parsed["lang_features"][0]["timestamp"].is_number()); + parsed["lib_features"][0]["timestamp"] = serde_json::json!(null); + parsed["lang_features"][0]["timestamp"] = serde_json::json!(null); + let expected = serde_json::json!( + { + "lib_features":[{"symbol":"ascii_char", "timestamp":null}], + "lang_features":[{"symbol":"box_patterns","since":null, "timestamp":null}] + } + ); + + assert_eq!(expected, parsed); + }); +} + +#[track_caller] +fn test_metrics_errors() { + run_in_tmpdir(|| { + rustc() + .input("main.rs") + .incremental("incremental") + .env("RUST_BACKTRACE", "short") + .arg("-Zmetrics-dir=invaliddirectorythatdefinitelydoesntexist") + .run_fail() + .assert_stderr_contains( + "error: cannot dump feature usage metrics: No such file or directory", + ) + .assert_stdout_not_contains("internal compiler error"); + }); +} diff --git a/tests/rustdoc-gui/settings.goml b/tests/rustdoc-gui/settings.goml index 4ab5b83d7c41..11d3696ccf6a 100644 --- a/tests/rustdoc-gui/settings.goml +++ b/tests/rustdoc-gui/settings.goml @@ -314,6 +314,13 @@ compare-elements-position: (".sub form", "#settings", ["x"]) // Check that setting-line has the same margin in this mode as in the popover. assert-css: (".setting-line", {"margin": |setting_line_margin|}) +// We will check that the checkboxes size doesn't change either. +assert-size: ( + "#settings label > input[type='checkbox']", + {"width": 19, "height": 19}, + ALL, +) + // We now check the display with JS disabled. assert-false: "noscript section" javascript: false @@ -327,3 +334,10 @@ reload: set-window-size: (300, 1000) wait-for: "#settings" assert-css: (".setting-radio", {"cursor": "pointer"}) + +// We ensure that the checkboxes size didn't change. +assert-size: ( + "#settings label > input[type='checkbox']", + {"width": 19, "height": 19}, + ALL, +) diff --git a/tests/rustdoc-js-std/unbox-type-result.js b/tests/rustdoc-js-std/unbox-type-result.js new file mode 100644 index 000000000000..1f5cba58adf6 --- /dev/null +++ b/tests/rustdoc-js-std/unbox-type-result.js @@ -0,0 +1,20 @@ +// exact-check + +// Test case for https://github.com/rust-lang/rust/issues/139665 +// make sure that std::io::Result and std::thread::Result get unboxed + +const EXPECTED = [ + { + query: "File -> Metadata", + others: [ + { path: "std::fs::File", name: "metadata" }, + { path: "std::fs::File", name: "metadata_at" }, + ] + }, + { + query: "JoinHandle -> T", + others: [ + { path: "std::thread::JoinHandle", name: "join" }, + ] + }, +]; diff --git a/tests/rustdoc-js/generics-unbox.js b/tests/rustdoc-js/generics-unbox.js index 6baf00c814bb..a4f2ba8e3a63 100644 --- a/tests/rustdoc-js/generics-unbox.js +++ b/tests/rustdoc-js/generics-unbox.js @@ -31,4 +31,10 @@ const EXPECTED = [ { 'path': 'generics_unbox', 'name': 'beta' }, ], }, + { + 'query': '-> Sigma', + 'others': [ + { 'path': 'generics_unbox', 'name': 'delta' }, + ], + }, ]; diff --git a/tests/rustdoc-js/generics-unbox.rs b/tests/rustdoc-js/generics-unbox.rs index c2578575997b..b16e35ee3d46 100644 --- a/tests/rustdoc-js/generics-unbox.rs +++ b/tests/rustdoc-js/generics-unbox.rs @@ -42,3 +42,15 @@ pub fn beta(_: Inside) -> Out, Out4> { pub fn gamma(_: Inside) -> Out, Out4> { loop {} } + +pub fn delta(_: i32) -> Epsilon { + loop {} +} + +#[doc(search_unbox)] +pub struct Theta(T); + +#[doc(search_unbox)] +pub type Epsilon = Theta; + +pub struct Sigma; diff --git a/tests/rustdoc-json/targets/aarch64_apple_darwin.rs b/tests/rustdoc-json/targets/aarch64_apple_darwin.rs new file mode 100644 index 000000000000..c6ae5517d476 --- /dev/null +++ b/tests/rustdoc-json/targets/aarch64_apple_darwin.rs @@ -0,0 +1,14 @@ +//@ only-aarch64-apple-darwin + +//@ is "$.target.triple" \"aarch64-apple-darwin\" +//@ is "$.target.target_features[?(@.name=='vh')].globally_enabled" true +//@ is "$.target.target_features[?(@.name=='sve')].globally_enabled" false +//@ has "$.target.target_features[?(@.name=='sve2')].implies_features" '["sve"]' +//@ is "$.target.target_features[?(@.name=='sve2')].unstable_feature_gate" null + +// If this breaks due to stabilization, check rustc_target::target_features for a replacement +//@ is "$.target.target_features[?(@.name=='cssc')].unstable_feature_gate" '"aarch64_unstable_target_feature"' +//@ is "$.target.target_features[?(@.name=='v9a')].unstable_feature_gate" '"aarch64_ver_target_feature"' + +// Ensure we don't look like x86-64 +//@ !has "$.target.target_features[?(@.name=='avx2')]" diff --git a/tests/rustdoc-json/targets/aarch64_reflects_compiler_options.rs b/tests/rustdoc-json/targets/aarch64_reflects_compiler_options.rs new file mode 100644 index 000000000000..f91221eb23c6 --- /dev/null +++ b/tests/rustdoc-json/targets/aarch64_reflects_compiler_options.rs @@ -0,0 +1,10 @@ +//@ only-aarch64 + +// If we enable SVE Bit Permute, we should see that it is enabled +//@ compile-flags: -Ctarget-feature=+sve2-bitperm +//@ is "$.target.target_features[?(@.name=='sve2-bitperm')].globally_enabled" true + +// As well as its dependency chain +//@ is "$.target.target_features[?(@.name=='sve2')].globally_enabled" true +//@ is "$.target.target_features[?(@.name=='sve')].globally_enabled" true +//@ is "$.target.target_features[?(@.name=='neon')].globally_enabled" true diff --git a/tests/rustdoc-json/targets/aarch64_unknown_linux_gnu.rs b/tests/rustdoc-json/targets/aarch64_unknown_linux_gnu.rs new file mode 100644 index 000000000000..9139b00a1285 --- /dev/null +++ b/tests/rustdoc-json/targets/aarch64_unknown_linux_gnu.rs @@ -0,0 +1,14 @@ +//@ only-aarch64-unknown-linux-gnu + +//@ is "$.target.triple" \"aarch64-unknown-linux-gnu\" +//@ is "$.target.target_features[?(@.name=='neon')].globally_enabled" true +//@ is "$.target.target_features[?(@.name=='sve')].globally_enabled" false +//@ has "$.target.target_features[?(@.name=='sve2')].implies_features" '["sve"]' +//@ is "$.target.target_features[?(@.name=='sve2')].unstable_feature_gate" null + +// If this breaks due to stabilization, check rustc_target::target_features for a replacement +//@ is "$.target.target_features[?(@.name=='cssc')].unstable_feature_gate" '"aarch64_unstable_target_feature"' +//@ is "$.target.target_features[?(@.name=='v9a')].unstable_feature_gate" '"aarch64_ver_target_feature"' + +// Ensure we don't look like x86-64 +//@ !has "$.target.target_features[?(@.name=='avx2')]" diff --git a/tests/rustdoc-json/targets/i686_pc_windows_msvc.rs b/tests/rustdoc-json/targets/i686_pc_windows_msvc.rs new file mode 100644 index 000000000000..088c741d1138 --- /dev/null +++ b/tests/rustdoc-json/targets/i686_pc_windows_msvc.rs @@ -0,0 +1,14 @@ +//@ only-i686-pc-windows-msvc + +//@ is "$.target.triple" \"i686-pc-windows-msvc\" +//@ is "$.target.target_features[?(@.name=='sse2')].globally_enabled" true +//@ is "$.target.target_features[?(@.name=='avx2')].globally_enabled" false +//@ has "$.target.target_features[?(@.name=='avx2')].implies_features" '["avx"]' +//@ is "$.target.target_features[?(@.name=='avx2')].unstable_feature_gate" null + +// If this breaks due to stabilization, check rustc_target::target_features for a replacement +//@ is "$.target.target_features[?(@.name=='amx-tile')].unstable_feature_gate" '"x86_amx_intrinsics"' +//@ is "$.target.target_features[?(@.name=='x87')].unstable_feature_gate" '"x87_target_feature"' + +// Ensure we don't look like aarch64 +//@ !has "$.target.target_features[?(@.name=='sve2')]" diff --git a/tests/rustdoc-json/targets/i686_unknown_linux_gnu.rs b/tests/rustdoc-json/targets/i686_unknown_linux_gnu.rs new file mode 100644 index 000000000000..03788b000f12 --- /dev/null +++ b/tests/rustdoc-json/targets/i686_unknown_linux_gnu.rs @@ -0,0 +1,14 @@ +//@ only-i686-unknown-linux-gnu + +//@ is "$.target.triple" \"i686-unknown-linux-gnu\" +//@ is "$.target.target_features[?(@.name=='sse2')].globally_enabled" true +//@ is "$.target.target_features[?(@.name=='avx2')].globally_enabled" false +//@ has "$.target.target_features[?(@.name=='avx2')].implies_features" '["avx"]' +//@ is "$.target.target_features[?(@.name=='avx2')].unstable_feature_gate" null + +// If this breaks due to stabilization, check rustc_target::target_features for a replacement +//@ is "$.target.target_features[?(@.name=='amx-tile')].unstable_feature_gate" '"x86_amx_intrinsics"' +//@ is "$.target.target_features[?(@.name=='x87')].unstable_feature_gate" '"x87_target_feature"' + +// Ensure we don't look like aarch64 +//@ !has "$.target.target_features[?(@.name=='sve2')]" diff --git a/tests/rustdoc-json/targets/x86_64_apple_darwin.rs b/tests/rustdoc-json/targets/x86_64_apple_darwin.rs new file mode 100644 index 000000000000..a46f9138e867 --- /dev/null +++ b/tests/rustdoc-json/targets/x86_64_apple_darwin.rs @@ -0,0 +1,14 @@ +//@ only-x86_64-apple-darwin + +//@ is "$.target.triple" \"x86_64-apple-darwin\" +//@ is "$.target.target_features[?(@.name=='sse2')].globally_enabled" true +//@ is "$.target.target_features[?(@.name=='avx2')].globally_enabled" false +//@ has "$.target.target_features[?(@.name=='avx2')].implies_features" '["avx"]' +//@ is "$.target.target_features[?(@.name=='avx2')].unstable_feature_gate" null + +// If this breaks due to stabilization, check rustc_target::target_features for a replacement +//@ is "$.target.target_features[?(@.name=='amx-tile')].unstable_feature_gate" '"x86_amx_intrinsics"' +//@ is "$.target.target_features[?(@.name=='x87')].unstable_feature_gate" '"x87_target_feature"' + +// Ensure we don't look like aarch64 +//@ !has "$.target.target_features[?(@.name=='sve2')]" diff --git a/tests/rustdoc-json/targets/x86_64_pc_windows_gnu.rs b/tests/rustdoc-json/targets/x86_64_pc_windows_gnu.rs new file mode 100644 index 000000000000..7da12eb4d580 --- /dev/null +++ b/tests/rustdoc-json/targets/x86_64_pc_windows_gnu.rs @@ -0,0 +1,14 @@ +//@ only-x86_64-pc-windows-gnu + +//@ is "$.target.triple" \"x86_64-pc-windows-gnu\" +//@ is "$.target.target_features[?(@.name=='sse2')].globally_enabled" true +//@ is "$.target.target_features[?(@.name=='avx2')].globally_enabled" false +//@ has "$.target.target_features[?(@.name=='avx2')].implies_features" '["avx"]' +//@ is "$.target.target_features[?(@.name=='avx2')].unstable_feature_gate" null + +// If this breaks due to stabilization, check rustc_target::target_features for a replacement +//@ is "$.target.target_features[?(@.name=='amx-tile')].unstable_feature_gate" '"x86_amx_intrinsics"' +//@ is "$.target.target_features[?(@.name=='x87')].unstable_feature_gate" '"x87_target_feature"' + +// Ensure we don't look like aarch64 +//@ !has "$.target.target_features[?(@.name=='sve2')]" diff --git a/tests/rustdoc-json/targets/x86_64_pc_windows_msvc.rs b/tests/rustdoc-json/targets/x86_64_pc_windows_msvc.rs new file mode 100644 index 000000000000..d55f5776e85e --- /dev/null +++ b/tests/rustdoc-json/targets/x86_64_pc_windows_msvc.rs @@ -0,0 +1,14 @@ +//@ only-x86_64-pc-windows-msvc + +//@ is "$.target.triple" \"x86_64-pc-windows-msvc\" +//@ is "$.target.target_features[?(@.name=='sse2')].globally_enabled" true +//@ is "$.target.target_features[?(@.name=='avx2')].globally_enabled" false +//@ has "$.target.target_features[?(@.name=='avx2')].implies_features" '["avx"]' +//@ is "$.target.target_features[?(@.name=='avx2')].unstable_feature_gate" null + +// If this breaks due to stabilization, check rustc_target::target_features for a replacement +//@ is "$.target.target_features[?(@.name=='amx-tile')].unstable_feature_gate" '"x86_amx_intrinsics"' +//@ is "$.target.target_features[?(@.name=='x87')].unstable_feature_gate" '"x87_target_feature"' + +// Ensure we don't look like aarch64 +//@ !has "$.target.target_features[?(@.name=='sve2')]" diff --git a/tests/rustdoc-json/targets/x86_64_reflects_compiler_options.rs b/tests/rustdoc-json/targets/x86_64_reflects_compiler_options.rs new file mode 100644 index 000000000000..ba029b099963 --- /dev/null +++ b/tests/rustdoc-json/targets/x86_64_reflects_compiler_options.rs @@ -0,0 +1,10 @@ +//@ only-x86_64 + +// If we enable AVX2, we should see that it is enabled +//@ compile-flags: -Ctarget-feature=+avx2 +//@ is "$.target.target_features[?(@.name=='avx2')].globally_enabled" true + +// As well as its dependency chain +//@ is "$.target.target_features[?(@.name=='avx')].globally_enabled" true +//@ is "$.target.target_features[?(@.name=='sse4.2')].globally_enabled" true +//@ is "$.target.target_features[?(@.name=='sse4.1')].globally_enabled" true diff --git a/tests/rustdoc-json/targets/x86_64_unknown_linux_gnu.rs b/tests/rustdoc-json/targets/x86_64_unknown_linux_gnu.rs new file mode 100644 index 000000000000..3372fe7eb9dd --- /dev/null +++ b/tests/rustdoc-json/targets/x86_64_unknown_linux_gnu.rs @@ -0,0 +1,14 @@ +//@ only-x86_64-unknown-linux-gnu + +//@ is "$.target.triple" \"x86_64-unknown-linux-gnu\" +//@ is "$.target.target_features[?(@.name=='sse2')].globally_enabled" true +//@ is "$.target.target_features[?(@.name=='avx2')].globally_enabled" false +//@ has "$.target.target_features[?(@.name=='avx2')].implies_features" '["avx"]' +//@ is "$.target.target_features[?(@.name=='avx2')].unstable_feature_gate" null + +// If this breaks due to stabilization, check rustc_target::target_features for a replacement +//@ is "$.target.target_features[?(@.name=='amx-tile')].unstable_feature_gate" '"x86_amx_intrinsics"' +//@ is "$.target.target_features[?(@.name=='x87')].unstable_feature_gate" '"x87_target_feature"' + +// Ensure we don't look like aarch64 +//@ !has "$.target.target_features[?(@.name=='sve2')]" diff --git a/tests/rustdoc-ui/cfg-boolean-literal.rs b/tests/rustdoc-ui/cfg-boolean-literal.rs index 4d4e599bfeef..74808d066c71 100644 --- a/tests/rustdoc-ui/cfg-boolean-literal.rs +++ b/tests/rustdoc-ui/cfg-boolean-literal.rs @@ -1,6 +1,5 @@ //@ check-pass -#![feature(cfg_boolean_literals)] #![feature(doc_cfg)] #[doc(cfg(false))] diff --git a/tests/rustdoc-ui/deprecated-attrs.rs b/tests/rustdoc-ui/deprecated-attrs.rs index 0ae65a5eaf7c..dcf8a52de41d 100644 --- a/tests/rustdoc-ui/deprecated-attrs.rs +++ b/tests/rustdoc-ui/deprecated-attrs.rs @@ -1,5 +1,4 @@ //@ compile-flags: --passes unknown-pass -//@ error-pattern: the `passes` flag no longer functions #![doc(no_default_passes)] //~^ ERROR unknown `doc` attribute `no_default_passes` diff --git a/tests/rustdoc-ui/deprecated-attrs.stderr b/tests/rustdoc-ui/deprecated-attrs.stderr index a30523e73297..3e9820522338 100644 --- a/tests/rustdoc-ui/deprecated-attrs.stderr +++ b/tests/rustdoc-ui/deprecated-attrs.stderr @@ -4,7 +4,7 @@ warning: the `passes` flag no longer functions = help: you may want to use --document-private-items error: unknown `doc` attribute `no_default_passes` - --> $DIR/deprecated-attrs.rs:4:8 + --> $DIR/deprecated-attrs.rs:3:8 | LL | #![doc(no_default_passes)] | ^^^^^^^^^^^^^^^^^ no longer functions @@ -15,7 +15,7 @@ LL | #![doc(no_default_passes)] = note: `#[deny(invalid_doc_attributes)]` on by default error: unknown `doc` attribute `passes` - --> $DIR/deprecated-attrs.rs:11:8 + --> $DIR/deprecated-attrs.rs:10:8 | LL | #![doc(passes = "collapse-docs unindent-comments")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no longer functions @@ -25,7 +25,7 @@ LL | #![doc(passes = "collapse-docs unindent-comments")] = note: `doc(passes)` is now a no-op error: unknown `doc` attribute `plugins` - --> $DIR/deprecated-attrs.rs:17:8 + --> $DIR/deprecated-attrs.rs:16:8 | LL | #![doc(plugins = "xxx")] | ^^^^^^^^^^^^^^^ no longer functions diff --git a/tests/rustdoc-ui/doc-cfg-unstable.rs b/tests/rustdoc-ui/doc-cfg-unstable.rs index 14c2e83ec854..b77c3654497d 100644 --- a/tests/rustdoc-ui/doc-cfg-unstable.rs +++ b/tests/rustdoc-ui/doc-cfg-unstable.rs @@ -1,10 +1,6 @@ // #138113: rustdoc didn't gate unstable predicates inside `doc(cfg(..))` #![feature(doc_cfg)] -// `cfg_boolean_literals` -#[doc(cfg(false))] //~ ERROR `cfg(false)` is experimental and subject to change -pub fn cfg_boolean_literals() {} - // `cfg_version` #[doc(cfg(sanitize = "thread"))] //~ ERROR `cfg(sanitize)` is experimental and subject to change pub fn cfg_sanitize() {} diff --git a/tests/rustdoc-ui/doc-cfg-unstable.stderr b/tests/rustdoc-ui/doc-cfg-unstable.stderr index 54de3b178edb..9651c5f1a0b0 100644 --- a/tests/rustdoc-ui/doc-cfg-unstable.stderr +++ b/tests/rustdoc-ui/doc-cfg-unstable.stderr @@ -1,15 +1,5 @@ -error[E0658]: `cfg(false)` is experimental and subject to change - --> $DIR/doc-cfg-unstable.rs:5:11 - | -LL | #[doc(cfg(false))] - | ^^^^^ - | - = note: see issue #131204 for more information - = help: add `#![feature(cfg_boolean_literals)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - error[E0658]: `cfg(sanitize)` is experimental and subject to change - --> $DIR/doc-cfg-unstable.rs:9:11 + --> $DIR/doc-cfg-unstable.rs:5:11 | LL | #[doc(cfg(sanitize = "thread"))] | ^^^^^^^^^^^^^^^^^^^ @@ -18,6 +8,6 @@ LL | #[doc(cfg(sanitize = "thread"))] = help: add `#![feature(cfg_sanitize)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0658`. diff --git a/tests/rustdoc-ui/doctest/failed-doctest-should-panic-2021.rs b/tests/rustdoc-ui/doctest/failed-doctest-should-panic-2021.rs index d8c43100d2fc..1ed67694a903 100644 --- a/tests/rustdoc-ui/doctest/failed-doctest-should-panic-2021.rs +++ b/tests/rustdoc-ui/doctest/failed-doctest-should-panic-2021.rs @@ -1,7 +1,8 @@ // FIXME: if/when the output of the test harness can be tested on its own, this test should be // adapted to use that, and that normalize line can go away -//@ compile-flags:--test --edition 2021 +//@ compile-flags: --test +//@ edition: 2021 //@ normalize-stdout: "tests/rustdoc-ui/doctest" -> "$$DIR" //@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME" //@ failure-status: 101 diff --git a/tests/rustdoc-ui/doctest/failed-doctest-should-panic-2021.stdout b/tests/rustdoc-ui/doctest/failed-doctest-should-panic-2021.stdout index 63d987de8a9f..9f4d60e6f4de 100644 --- a/tests/rustdoc-ui/doctest/failed-doctest-should-panic-2021.stdout +++ b/tests/rustdoc-ui/doctest/failed-doctest-should-panic-2021.stdout @@ -1,14 +1,14 @@ running 1 test -test $DIR/failed-doctest-should-panic-2021.rs - Foo (line 9) ... FAILED +test $DIR/failed-doctest-should-panic-2021.rs - Foo (line 10) ... FAILED failures: ----- $DIR/failed-doctest-should-panic-2021.rs - Foo (line 9) stdout ---- +---- $DIR/failed-doctest-should-panic-2021.rs - Foo (line 10) stdout ---- Test executable succeeded, but it's marked `should_panic`. failures: - $DIR/failed-doctest-should-panic-2021.rs - Foo (line 9) + $DIR/failed-doctest-should-panic-2021.rs - Foo (line 10) test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME diff --git a/tests/rustdoc-ui/doctest/failed-doctest-should-panic.stdout b/tests/rustdoc-ui/doctest/failed-doctest-should-panic.stdout index 90c0463d832e..2b04b77c9dc5 100644 --- a/tests/rustdoc-ui/doctest/failed-doctest-should-panic.stdout +++ b/tests/rustdoc-ui/doctest/failed-doctest-should-panic.stdout @@ -5,7 +5,7 @@ test $DIR/failed-doctest-should-panic.rs - Foo (line 10) - should panic ... FAIL failures: ---- $DIR/failed-doctest-should-panic.rs - Foo (line 10) stdout ---- -note: test did not panic as expected +note: test did not panic as expected at $DIR/failed-doctest-should-panic.rs:10:0 failures: $DIR/failed-doctest-should-panic.rs - Foo (line 10) diff --git a/tests/rustdoc-ui/intra-doc/import-inline-merge-module.rs b/tests/rustdoc-ui/intra-doc/import-inline-merge-module.rs index 636c3c8de42c..bcfb790e55f6 100644 --- a/tests/rustdoc-ui/intra-doc/import-inline-merge-module.rs +++ b/tests/rustdoc-ui/intra-doc/import-inline-merge-module.rs @@ -3,7 +3,8 @@ //@ check-pass //@ aux-build: inner-crate-doc.rs -//@ compile-flags: --extern inner_crate_doc --edition 2018 +//@ compile-flags: --extern inner_crate_doc +//@ edition: 2018 /// Import doc comment [inner_crate_doc] #[doc(inline)] diff --git a/tests/rustdoc-ui/invalid-syntax.rs b/tests/rustdoc-ui/invalid-syntax.rs index 42469da83761..3b60239df8dd 100644 --- a/tests/rustdoc-ui/invalid-syntax.rs +++ b/tests/rustdoc-ui/invalid-syntax.rs @@ -47,7 +47,7 @@ pub fn baz() {} /// /// Indented block end pub fn quux() {} -//~^^^^^ could not parse code block as Rust code +//~^^^^^ WARN could not parse code block as Rust code /// Unclosed fence /// diff --git a/tests/rustdoc-ui/invalid-theme-name.rs b/tests/rustdoc-ui/invalid-theme-name.rs index 7f1d191c89de..22b5e616a3d4 100644 --- a/tests/rustdoc-ui/invalid-theme-name.rs +++ b/tests/rustdoc-ui/invalid-theme-name.rs @@ -1,4 +1,4 @@ //@ compile-flags:--theme {{src-base}}/invalid-theme-name.rs -//@ error-pattern: must have a .css extension //~? ERROR invalid argument: "$DIR/invalid-theme-name.rs" +//~? HELP must have a .css extension diff --git a/tests/rustdoc-ui/issues/ice-generic-type-alias-105742.rs b/tests/rustdoc-ui/issues/ice-generic-type-alias-105742.rs index 89b55beaea18..73a68777c6d8 100644 --- a/tests/rustdoc-ui/issues/ice-generic-type-alias-105742.rs +++ b/tests/rustdoc-ui/issues/ice-generic-type-alias-105742.rs @@ -5,10 +5,10 @@ use std::ops::Index; pub fn next<'a, T>(s: &'a mut dyn SVec) { //~^ expected 1 lifetime argument //~| expected 1 generic argument - //~| the trait `SVec` is not dyn compatible + //~| ERROR the trait `SVec` is not dyn compatible //~| `SVec` is not dyn compatible - //~| missing generics for associated type `SVec::Item` - //~| missing generics for associated type `SVec::Item` + //~| ERROR missing generics for associated type `SVec::Item` + //~| ERROR missing generics for associated type `SVec::Item` let _ = s; } @@ -16,52 +16,52 @@ pub trait SVec: Index< ::Item, //~^ expected 1 lifetime argument //~| expected 1 generic argument - //~| missing generics for associated type `SVec::Item` - //~| missing generics for associated type `SVec::Item` - //~| missing generics for associated type `SVec::Item` - //~| missing generics for associated type `SVec::Item` - //~| missing generics for associated type `SVec::Item` - //~| missing generics for associated type `SVec::Item` - //~| missing generics for associated type `SVec::Item` - //~| missing generics for associated type `SVec::Item` + //~| ERROR missing generics for associated type `SVec::Item` + //~| ERROR missing generics for associated type `SVec::Item` + //~| ERROR missing generics for associated type `SVec::Item` + //~| ERROR missing generics for associated type `SVec::Item` + //~| ERROR missing generics for associated type `SVec::Item` + //~| ERROR missing generics for associated type `SVec::Item` + //~| ERROR missing generics for associated type `SVec::Item` + //~| ERROR missing generics for associated type `SVec::Item` Output = ::Item, //~^ expected 1 lifetime argument //~| expected 1 generic argument - //~| missing generics for associated type `SVec::Item` - //~| missing generics for associated type `SVec::Item` - //~| missing generics for associated type `SVec::Item` - //~| missing generics for associated type `SVec::Item` - //~| missing generics for associated type `SVec::Item` - //~| missing generics for associated type `SVec::Item` - //~| missing generics for associated type `SVec::Item` - //~| missing generics for associated type `SVec::Item` + //~| ERROR missing generics for associated type `SVec::Item` + //~| ERROR missing generics for associated type `SVec::Item` + //~| ERROR missing generics for associated type `SVec::Item` + //~| ERROR missing generics for associated type `SVec::Item` + //~| ERROR missing generics for associated type `SVec::Item` + //~| ERROR missing generics for associated type `SVec::Item` + //~| ERROR missing generics for associated type `SVec::Item` + //~| ERROR missing generics for associated type `SVec::Item` Output = ::Item> as SVec>::Item, //~^ expected 1 lifetime argument //~| expected 1 generic argument //~| expected 1 lifetime argument - //~| missing generics for associated type `SVec::Item` - //~| missing generics for associated type `SVec::Item` - //~| missing generics for associated type `SVec::Item` - //~| missing generics for associated type `SVec::Item` - //~| missing generics for associated type `SVec::Item` - //~| missing generics for associated type `SVec::Item` + //~| ERROR missing generics for associated type `SVec::Item` + //~| ERROR missing generics for associated type `SVec::Item` + //~| ERROR missing generics for associated type `SVec::Item` + //~| ERROR missing generics for associated type `SVec::Item` + //~| ERROR missing generics for associated type `SVec::Item` + //~| ERROR missing generics for associated type `SVec::Item` //~| expected 1 generic argument - //~| missing generics for associated type `SVec::Item` - //~| missing generics for associated type `SVec::Item` - //~| missing generics for associated type `SVec::Item` - //~| missing generics for associated type `SVec::Item` - //~| missing generics for associated type `SVec::Item` - //~| missing generics for associated type `SVec::Item` - //~| missing generics for associated type `SVec::Item` - //~| missing generics for associated type `SVec::Item` - //~| missing generics for associated type `SVec::Item` - //~| missing generics for associated type `SVec::Item` + //~| ERROR missing generics for associated type `SVec::Item` + //~| ERROR missing generics for associated type `SVec::Item` + //~| ERROR missing generics for associated type `SVec::Item` + //~| ERROR missing generics for associated type `SVec::Item` + //~| ERROR missing generics for associated type `SVec::Item` + //~| ERROR missing generics for associated type `SVec::Item` + //~| ERROR missing generics for associated type `SVec::Item` + //~| ERROR missing generics for associated type `SVec::Item` + //~| ERROR missing generics for associated type `SVec::Item` + //~| ERROR missing generics for associated type `SVec::Item` > { type Item<'a, T>; fn len(&self) -> ::Item; //~^ expected 1 lifetime argument - //~| missing generics for associated type `SVec::Item` + //~| ERROR missing generics for associated type `SVec::Item` //~| expected 1 generic argument - //~| missing generics for associated type `SVec::Item` + //~| ERROR missing generics for associated type `SVec::Item` } diff --git a/tests/rustdoc-ui/issues/ice-typeof-102986.rs b/tests/rustdoc-ui/issues/ice-typeof-102986.rs index 8fcbfffe1724..b1ad19cb9ff4 100644 --- a/tests/rustdoc-ui/issues/ice-typeof-102986.rs +++ b/tests/rustdoc-ui/issues/ice-typeof-102986.rs @@ -1,5 +1,5 @@ // https://github.com/rust-lang/rust/issues/102986 struct Struct { y: (typeof("hey"),), - //~^ `typeof` is a reserved keyword but unimplemented + //~^ ERROR `typeof` is a reserved keyword but unimplemented } diff --git a/tests/rustdoc-ui/multi-par-footnote.rs b/tests/rustdoc-ui/multi-par-footnote.rs new file mode 100644 index 000000000000..bb6a85db0dba --- /dev/null +++ b/tests/rustdoc-ui/multi-par-footnote.rs @@ -0,0 +1,18 @@ +//@ check-pass +//@ compile-flags:--test +//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME" +// Regression test for #139064. + +/// Example +/// +/// Footnote with multiple paragraphs[^multiple] +/// +/// [^multiple]: +/// One +/// +/// Two +/// +/// Three +pub fn add(left: u64, right: u64) -> u64 { + left + right +} diff --git a/tests/rustdoc-ui/multi-par-footnote.stdout b/tests/rustdoc-ui/multi-par-footnote.stdout new file mode 100644 index 000000000000..7326c0a25a06 --- /dev/null +++ b/tests/rustdoc-ui/multi-par-footnote.stdout @@ -0,0 +1,5 @@ + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/tests/rustdoc/anon-fn-params.rs b/tests/rustdoc/anon-fn-params.rs new file mode 100644 index 000000000000..9af1af3d3fa3 --- /dev/null +++ b/tests/rustdoc/anon-fn-params.rs @@ -0,0 +1,25 @@ +// Test that we render the deprecated anonymous trait function parameters from Rust 2015 as +// underscores in order not to perpetuate it and for legibility. + +//@ edition: 2015 +#![expect(anonymous_parameters)] + +// Check the "local case" (HIR cleaning) // + +//@ has anon_fn_params/trait.Trait.html +pub trait Trait { + //@ has - '//*[@id="tymethod.required"]' 'fn required(_: Option, _: impl Fn(&str) -> bool)' + fn required(Option, impl Fn(&str) -> bool); + //@ has - '//*[@id="method.provided"]' 'fn provided(_: [i32; 2])' + fn provided([i32; 2]) {} +} + +// Check the "extern case" (middle cleaning) // + +//@ aux-build: ext-anon-fn-params.rs +extern crate ext_anon_fn_params; + +//@ has anon_fn_params/trait.ExtTrait.html +//@ has - '//*[@id="tymethod.required"]' 'fn required(_: Option, _: impl Fn(&str) -> bool)' +//@ has - '//*[@id="method.provided"]' 'fn provided(_: [i32; 2])' +pub use ext_anon_fn_params::Trait as ExtTrait; diff --git a/tests/rustdoc/assoc-fns.rs b/tests/rustdoc/assoc-fns.rs new file mode 100644 index 000000000000..6ffbebc3d27e --- /dev/null +++ b/tests/rustdoc/assoc-fns.rs @@ -0,0 +1,13 @@ +// Basic testing for associated functions (in traits, trait impls & inherent impls). + +//@ has assoc_fns/trait.Trait.html +pub trait Trait { + //@ has - '//*[@id="tymethod.required"]' 'fn required(first: i32, second: &str)' + fn required(first: i32, second: &str); + + //@ has - '//*[@id="method.provided"]' 'fn provided(only: ())' + fn provided(only: ()) {} + + //@ has - '//*[@id="tymethod.params_are_unnamed"]' 'fn params_are_unnamed(_: i32, _: u32)' + fn params_are_unnamed(_: i32, _: u32); +} diff --git a/tests/rustdoc/auxiliary/ext-anon-fn-params.rs b/tests/rustdoc/auxiliary/ext-anon-fn-params.rs new file mode 100644 index 000000000000..1acb919ca64f --- /dev/null +++ b/tests/rustdoc/auxiliary/ext-anon-fn-params.rs @@ -0,0 +1,7 @@ +//@ edition: 2015 +#![expect(anonymous_parameters)] + +pub trait Trait { + fn required(Option, impl Fn(&str) -> bool); + fn provided([i32; 2]) {} +} diff --git a/tests/rustdoc/auxiliary/ext-trait-aliases.rs b/tests/rustdoc/auxiliary/ext-trait-aliases.rs new file mode 100644 index 000000000000..8454c04063c1 --- /dev/null +++ b/tests/rustdoc/auxiliary/ext-trait-aliases.rs @@ -0,0 +1,13 @@ +#![feature(trait_alias)] + +pub trait ExtAlias0 = Copy + Iterator; + +pub trait ExtAlias1<'a, T: 'a + Clone, const N: usize> = From<[&'a T; N]>; + +pub trait ExtAlias2 = where T: From, String: Into; + +pub trait ExtAlias3 = Sized; + +pub trait ExtAlias4 = where Self: Sized; + +pub trait ExtAlias5 = ; diff --git a/tests/rustdoc/auxiliary/primitive-doc.rs b/tests/rustdoc/auxiliary/primitive-doc.rs index a7253ed2450b..859716c38e46 100644 --- a/tests/rustdoc/auxiliary/primitive-doc.rs +++ b/tests/rustdoc/auxiliary/primitive-doc.rs @@ -1,4 +1,5 @@ -//@ compile-flags: --crate-type lib --edition 2018 +//@ compile-flags: --crate-type lib +//@ edition: 2018 #![feature(rustc_attrs)] #![feature(no_core)] diff --git a/tests/rustdoc/auxiliary/primitive-reexport.rs b/tests/rustdoc/auxiliary/primitive-reexport.rs index 18b57037634d..7c85038674b6 100644 --- a/tests/rustdoc/auxiliary/primitive-reexport.rs +++ b/tests/rustdoc/auxiliary/primitive-reexport.rs @@ -1,4 +1,5 @@ -//@ compile-flags: --emit metadata --crate-type lib --edition 2018 +//@ compile-flags: --emit metadata --crate-type lib +//@ edition: 2018 #![crate_name = "foo"] diff --git a/tests/rustdoc/auxiliary/trait-alias-mention.rs b/tests/rustdoc/auxiliary/trait-alias-mention.rs deleted file mode 100644 index 6df06c87a09d..000000000000 --- a/tests/rustdoc/auxiliary/trait-alias-mention.rs +++ /dev/null @@ -1,3 +0,0 @@ -#![feature(trait_alias)] - -pub trait SomeAlias = std::fmt::Debug + std::marker::Copy; diff --git a/tests/rustdoc/ffi.rs b/tests/rustdoc/ffi.rs index 5ba7cdba9109..524fb0edefb6 100644 --- a/tests/rustdoc/ffi.rs +++ b/tests/rustdoc/ffi.rs @@ -9,4 +9,8 @@ pub use lib::foreigner; extern "C" { //@ has ffi/fn.another.html //pre 'pub unsafe extern "C" fn another(cold_as_ice: u32)' pub fn another(cold_as_ice: u32); + + //@ has ffi/fn.params_are_unnamed.html //pre \ + // 'pub unsafe extern "C" fn params_are_unnamed(_: i32, _: u32)' + pub fn params_are_unnamed(_: i32, _: u32); } diff --git a/tests/rustdoc/inline_cross/auxiliary/fn-type.rs b/tests/rustdoc/inline_cross/auxiliary/fn-ptr-ty.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/fn-type.rs rename to tests/rustdoc/inline_cross/auxiliary/fn-ptr-ty.rs diff --git a/tests/rustdoc/inline_cross/default-generic-args.rs b/tests/rustdoc/inline_cross/default-generic-args.rs index 0469221b3d85..5124fbdf8dae 100644 --- a/tests/rustdoc/inline_cross/default-generic-args.rs +++ b/tests/rustdoc/inline_cross/default-generic-args.rs @@ -53,17 +53,17 @@ pub use default_generic_args::R2; //@ has user/type.H0.html // Check that we handle higher-ranked regions correctly: -//@ has - '//*[@class="rust item-decl"]//code' "fn(_: for<'a> fn(_: Re<'a>))" +//@ has - '//*[@class="rust item-decl"]//code' "fn(for<'a> fn(Re<'a>))" pub use default_generic_args::H0; //@ has user/type.H1.html // Check that we don't conflate distinct universially quantified regions (#1): -//@ has - '//*[@class="rust item-decl"]//code' "for<'b> fn(_: for<'a> fn(_: Re<'a, &'b ()>))" +//@ has - '//*[@class="rust item-decl"]//code' "for<'b> fn(for<'a> fn(Re<'a, &'b ()>))" pub use default_generic_args::H1; //@ has user/type.H2.html // Check that we don't conflate distinct universially quantified regions (#2): -//@ has - '//*[@class="rust item-decl"]//code' "for<'a> fn(_: for<'b> fn(_: Re<'a, &'b ()>))" +//@ has - '//*[@class="rust item-decl"]//code' "for<'a> fn(for<'b> fn(Re<'a, &'b ()>))" pub use default_generic_args::H2; //@ has user/type.P0.html @@ -86,7 +86,7 @@ pub use default_generic_args::A0; // Demonstrates that we currently don't elide generic arguments that are alpha-equivalent to their // respective generic parameter (after instantiation) for perf reasons (it would require us to // create an inference context). -//@ has - '//*[@class="rust item-decl"]//code' "Alpha fn(_: &'arbitrary ())>" +//@ has - '//*[@class="rust item-decl"]//code' "Alpha fn(&'arbitrary ())>" pub use default_generic_args::A1; //@ has user/type.M0.html diff --git a/tests/rustdoc/inline_cross/fn-type.rs b/tests/rustdoc/inline_cross/fn-ptr-ty.rs similarity index 71% rename from tests/rustdoc/inline_cross/fn-type.rs rename to tests/rustdoc/inline_cross/fn-ptr-ty.rs index 8db6f65f421f..010596225217 100644 --- a/tests/rustdoc/inline_cross/fn-type.rs +++ b/tests/rustdoc/inline_cross/fn-ptr-ty.rs @@ -2,11 +2,11 @@ // They should be rendered exactly as the user wrote it, i.e., in source order and with unused // parameters present, not stripped. -//@ aux-crate:fn_type=fn-type.rs +//@ aux-crate:fn_ptr_ty=fn-ptr-ty.rs //@ edition: 2021 #![crate_name = "user"] //@ has user/type.F.html //@ has - '//*[@class="rust item-decl"]//code' \ -// "for<'z, 'a, '_unused> fn(_: &'z for<'b> fn(_: &'b str), _: &'a ()) -> &'a ();" -pub use fn_type::F; +// "for<'z, 'a, '_unused> fn(&'z for<'b> fn(&'b str), &'a ()) -> &'a ();" +pub use fn_ptr_ty::F; diff --git a/tests/rustdoc/inline_cross/impl_trait.rs b/tests/rustdoc/inline_cross/impl_trait.rs index e6baf33660ac..468ac0830619 100644 --- a/tests/rustdoc/inline_cross/impl_trait.rs +++ b/tests/rustdoc/inline_cross/impl_trait.rs @@ -29,7 +29,7 @@ pub use impl_trait_aux::func4; //@ has impl_trait/fn.func5.html //@ has - '//pre[@class="rust item-decl"]' "func5(" //@ has - '//pre[@class="rust item-decl"]' "_f: impl for<'any> Fn(&'any str, &'any str) -> bool + for<'r> Other = ()>," -//@ has - '//pre[@class="rust item-decl"]' "_a: impl for<'beta, 'alpha, '_gamma> Auxiliary<'alpha, Item<'beta> = fn(_: &'beta ())>" +//@ has - '//pre[@class="rust item-decl"]' "_a: impl for<'beta, 'alpha, '_gamma> Auxiliary<'alpha, Item<'beta> = fn(&'beta ())>" //@ !has - '//pre[@class="rust item-decl"]' 'where' pub use impl_trait_aux::func5; diff --git a/tests/rustdoc/intra-doc/extern-crate-only-used-in-link.rs b/tests/rustdoc/intra-doc/extern-crate-only-used-in-link.rs index 7cec30c8b746..30834bd72104 100644 --- a/tests/rustdoc/intra-doc/extern-crate-only-used-in-link.rs +++ b/tests/rustdoc/intra-doc/extern-crate-only-used-in-link.rs @@ -6,7 +6,8 @@ //@ aux-build:empty2.rs //@ aux-crate:priv:empty2=empty2.rs //@ build-aux-docs -//@ compile-flags:-Z unstable-options --edition 2018 +//@ compile-flags:-Z unstable-options +//@ edition: 2018 //@ has extern_crate_only_used_in_link/index.html //@ has - '//a[@href="../issue_66159_1/struct.Something.html"]' 'issue_66159_1::Something' diff --git a/tests/rustdoc/primitive-reexport.rs b/tests/rustdoc/primitive-reexport.rs index eb255745392a..9b23b24fc93a 100644 --- a/tests/rustdoc/primitive-reexport.rs +++ b/tests/rustdoc/primitive-reexport.rs @@ -1,5 +1,6 @@ //@ aux-build: primitive-reexport.rs -//@ compile-flags:--extern foo --edition 2018 +//@ compile-flags: --extern foo +//@ edition: 2018 #![crate_name = "bar"] diff --git a/tests/rustdoc/primitive-slice-auto-trait.rs b/tests/rustdoc/primitive-slice-auto-trait.rs index e78d1d946142..647c1cca9481 100644 --- a/tests/rustdoc/primitive-slice-auto-trait.rs +++ b/tests/rustdoc/primitive-slice-auto-trait.rs @@ -1,4 +1,5 @@ -//@ compile-flags: --crate-type lib --edition 2018 +//@ compile-flags: --crate-type lib +//@ edition: 2018 #![crate_name = "foo"] #![feature(rustc_attrs)] diff --git a/tests/rustdoc/primitive-tuple-auto-trait.rs b/tests/rustdoc/primitive-tuple-auto-trait.rs index 045478e6b4f8..51300bd6b2fc 100644 --- a/tests/rustdoc/primitive-tuple-auto-trait.rs +++ b/tests/rustdoc/primitive-tuple-auto-trait.rs @@ -1,4 +1,5 @@ -//@ compile-flags: --crate-type lib --edition 2018 +//@ compile-flags: --crate-type lib +//@ edition: 2018 #![crate_name = "foo"] #![feature(rustc_attrs)] diff --git a/tests/rustdoc/primitive-tuple-variadic.rs b/tests/rustdoc/primitive-tuple-variadic.rs index d142729d2a8b..bab5eaae9a23 100644 --- a/tests/rustdoc/primitive-tuple-variadic.rs +++ b/tests/rustdoc/primitive-tuple-variadic.rs @@ -1,4 +1,5 @@ -//@ compile-flags: --crate-type lib --edition 2018 +//@ compile-flags: --crate-type lib +//@ edition: 2018 #![crate_name = "foo"] #![feature(rustdoc_internals)] diff --git a/tests/rustdoc/primitive-unit-auto-trait.rs b/tests/rustdoc/primitive-unit-auto-trait.rs index 6cae094c21c8..7dada1f9832e 100644 --- a/tests/rustdoc/primitive-unit-auto-trait.rs +++ b/tests/rustdoc/primitive-unit-auto-trait.rs @@ -1,4 +1,5 @@ -//@ compile-flags: --crate-type lib --edition 2018 +//@ compile-flags: --crate-type lib +//@ edition: 2018 #![crate_name = "foo"] #![feature(rustc_attrs)] diff --git a/tests/rustdoc/trait-alias-mention.rs b/tests/rustdoc/trait-alias-mention.rs deleted file mode 100644 index b6ef926e644e..000000000000 --- a/tests/rustdoc/trait-alias-mention.rs +++ /dev/null @@ -1,10 +0,0 @@ -//@ aux-build:trait-alias-mention.rs -//@ build-aux-docs - -#![crate_name = "foo"] - -extern crate trait_alias_mention; - -//@ has foo/fn.mention_alias_in_bounds.html '//a[@href="../trait_alias_mention/traitalias.SomeAlias.html"]' 'SomeAlias' -pub fn mention_alias_in_bounds() { -} diff --git a/tests/rustdoc/trait-aliases.rs b/tests/rustdoc/trait-aliases.rs new file mode 100644 index 000000000000..1be93f72042c --- /dev/null +++ b/tests/rustdoc/trait-aliases.rs @@ -0,0 +1,82 @@ +// Basic testing for trait aliases. +#![feature(trait_alias)] +#![crate_name = "it"] + +// Check the "local case" (HIR cleaning) // + +//@ has it/all.html '//a[@href="traitalias.Alias0.html"]' 'Alias0' +//@ has it/index.html '//h2[@id="trait-aliases"]' 'Trait Aliases' +//@ has it/index.html '//a[@class="traitalias"]' 'Alias0' +//@ has it/traitalias.Alias0.html +//@ has - '//*[@class="rust item-decl"]//code' 'trait Alias0 = Copy + Iterator;' +pub trait Alias0 = Copy + Iterator; + +//@ has it/traitalias.Alias1.html +//@ has - '//pre[@class="rust item-decl"]' \ +// "trait Alias1<'a, T: 'a + Clone, const N: usize> = From<[&'a T; N]>;" +pub trait Alias1<'a, T: 'a + Clone, const N: usize> = From<[&'a T; N]>; + +//@ has it/traitalias.Alias2.html +//@ has - '//pre[@class="rust item-decl"]' \ +// 'trait Alias2 = where T: From, String: Into;' +pub trait Alias2 = where T: From, String: Into; + +//@ has it/traitalias.Alias3.html +//@ has - '//pre[@class="rust item-decl"]' 'trait Alias3 = ;' +pub trait Alias3 =; + +//@ has it/traitalias.Alias4.html +//@ has - '//pre[@class="rust item-decl"]' 'trait Alias4 = ;' +pub trait Alias4 = where; + +//@ has it/fn.usage0.html +//@ has - '//pre[@class="rust item-decl"]' "pub fn usage0(_: impl Alias0)" +//@ has - '//a[@href="traitalias.Alias0.html"]' 'Alias0' +pub fn usage0(_: impl Alias0) {} + +// FIXME: One can only "disambiguate" intra-doc links to trait aliases with `type@` but not with +// `trait@` (fails to resolve) or `traitalias@` (doesn't exist). We should make at least one of +// the latter two work, right? + +//@ has it/link0/index.html +//@ has - '//a/@href' 'traitalias.Alias0.html' +//@ has - '//a/@href' 'traitalias.Alias1.html' +/// [Alias0], [type@Alias1] +pub mod link0 {} + +// Check the "extern case" (middle cleaning) // + +//@ aux-build: ext-trait-aliases.rs +extern crate ext_trait_aliases as ext; + +//@ has it/traitalias.ExtAlias0.html +//@ has - '//pre[@class="rust item-decl"]' 'trait ExtAlias0 = Copy + Iterator;' +pub use ext::ExtAlias0; + +//@ has it/traitalias.ExtAlias1.html +//@ has - '//pre[@class="rust item-decl"]' \ +// "trait ExtAlias1<'a, T, const N: usize> = From<[&'a T; N]> where T: 'a + Clone;" +pub use ext::ExtAlias1; + +//@ has it/traitalias.ExtAlias2.html +//@ has - '//pre[@class="rust item-decl"]' \ +// 'trait ExtAlias2 = where T: From, String: Into;' +pub use ext::ExtAlias2; + +//@ has it/traitalias.ExtAlias3.html +//@ has - '//pre[@class="rust item-decl"]' 'trait ExtAlias3 = Sized;' +pub use ext::ExtAlias3; + +// NOTE: Middle cleaning can't discern `= Sized` and `= where Self: Sized` and that's okay. +//@ has it/traitalias.ExtAlias4.html +//@ has - '//pre[@class="rust item-decl"]' 'trait ExtAlias4 = Sized;' +pub use ext::ExtAlias4; + +//@ has it/traitalias.ExtAlias5.html +//@ has - '//pre[@class="rust item-decl"]' 'trait ExtAlias5 = ;' +pub use ext::ExtAlias5; + +//@ has it/fn.usage1.html +//@ has - '//pre[@class="rust item-decl"]' "pub fn usage1(_: impl ExtAlias0)" +//@ has - '//a[@href="traitalias.ExtAlias0.html"]' 'ExtAlias0' +pub fn usage1(_: impl ExtAlias0) {} diff --git a/tests/rustdoc/trait_alias.rs b/tests/rustdoc/trait_alias.rs deleted file mode 100644 index bfdb9d40e2d2..000000000000 --- a/tests/rustdoc/trait_alias.rs +++ /dev/null @@ -1,26 +0,0 @@ -#![feature(trait_alias)] - -#![crate_name = "foo"] - -use std::fmt::Debug; - -//@ has foo/all.html '//a[@href="traitalias.CopyAlias.html"]' 'CopyAlias' -//@ has foo/all.html '//a[@href="traitalias.Alias2.html"]' 'Alias2' -//@ has foo/all.html '//a[@href="traitalias.Foo.html"]' 'Foo' - -//@ has foo/index.html '//h2[@id="trait-aliases"]' 'Trait Aliases' -//@ has foo/index.html '//a[@class="traitalias"]' 'CopyAlias' -//@ has foo/index.html '//a[@class="traitalias"]' 'Alias2' -//@ has foo/index.html '//a[@class="traitalias"]' 'Foo' - -//@ has foo/traitalias.CopyAlias.html -//@ has - '//section[@id="main-content"]/pre[@class="rust item-decl"]' 'trait CopyAlias = Copy;' -pub trait CopyAlias = Copy; -//@ has foo/traitalias.Alias2.html -//@ has - '//section[@id="main-content"]/pre[@class="rust item-decl"]' 'trait Alias2 = Copy + Debug;' -pub trait Alias2 = Copy + Debug; -//@ has foo/traitalias.Foo.html -//@ has - '//section[@id="main-content"]/pre[@class="rust item-decl"]' 'trait Foo = Into + Debug;' -pub trait Foo = Into + Debug; -//@ has foo/fn.bar.html '//a[@href="traitalias.Alias2.html"]' 'Alias2' -pub fn bar() where T: Alias2 {} diff --git a/tests/ui-fulldeps/hash-stable-is-unstable.rs b/tests/ui-fulldeps/hash-stable-is-unstable.rs index a4b8533eb045..7f62b6044104 100644 --- a/tests/ui-fulldeps/hash-stable-is-unstable.rs +++ b/tests/ui-fulldeps/hash-stable-is-unstable.rs @@ -1,24 +1,24 @@ //@ compile-flags: -Zdeduplicate-diagnostics=yes extern crate rustc_data_structures; -//~^ use of unstable library feature `rustc_private` +//~^ ERROR use of unstable library feature `rustc_private` //~| NOTE: issue #27812 for more information //~| NOTE: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date extern crate rustc_macros; -//~^ use of unstable library feature `rustc_private` +//~^ ERROR use of unstable library feature `rustc_private` //~| NOTE: see issue #27812 for more information //~| NOTE: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date extern crate rustc_query_system; -//~^ use of unstable library feature `rustc_private` +//~^ ERROR use of unstable library feature `rustc_private` //~| NOTE: see issue #27812 for more information //~| NOTE: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date use rustc_macros::HashStable; -//~^ use of unstable library feature `rustc_private` +//~^ ERROR use of unstable library feature `rustc_private` //~| NOTE: see issue #27812 for more information //~| NOTE: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date #[derive(HashStable)] -//~^ use of unstable library feature `rustc_private` +//~^ ERROR use of unstable library feature `rustc_private` //~| NOTE: in this expansion of #[derive(HashStable)] //~| NOTE: in this expansion of #[derive(HashStable)] //~| NOTE: in this expansion of #[derive(HashStable)] diff --git a/tests/ui-fulldeps/internal-lints/diagnostics.rs b/tests/ui-fulldeps/internal-lints/diagnostics.rs index 442f9d72c3f1..1238fefd5bc0 100644 --- a/tests/ui-fulldeps/internal-lints/diagnostics.rs +++ b/tests/ui-fulldeps/internal-lints/diagnostics.rs @@ -15,7 +15,7 @@ extern crate rustc_span; use rustc_errors::{ Diag, DiagCtxtHandle, DiagInner, DiagMessage, Diagnostic, EmissionGuarantee, Level, - LintDiagnostic, SubdiagMessage, SubdiagMessageOp, Subdiagnostic, + LintDiagnostic, SubdiagMessage, Subdiagnostic, }; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::Span; @@ -56,10 +56,9 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for TranslatableInDiagnostic { pub struct UntranslatableInAddtoDiag; impl Subdiagnostic for UntranslatableInAddtoDiag { - fn add_to_diag_with>( + fn add_to_diag( self, diag: &mut Diag<'_, G>, - f: &F, ) { diag.note("untranslatable diagnostic"); //~^ ERROR diagnostics should be created using translatable messages @@ -69,10 +68,9 @@ impl Subdiagnostic for UntranslatableInAddtoDiag { pub struct TranslatableInAddtoDiag; impl Subdiagnostic for TranslatableInAddtoDiag { - fn add_to_diag_with>( + fn add_to_diag( self, diag: &mut Diag<'_, G>, - f: &F, ) { diag.note(crate::fluent_generated::no_crate_note); } diff --git a/tests/ui-fulldeps/internal-lints/diagnostics.stderr b/tests/ui-fulldeps/internal-lints/diagnostics.stderr index 36dd3cf4be79..b260c4b7afef 100644 --- a/tests/ui-fulldeps/internal-lints/diagnostics.stderr +++ b/tests/ui-fulldeps/internal-lints/diagnostics.stderr @@ -11,19 +11,19 @@ LL | #![deny(rustc::untranslatable_diagnostic)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: diagnostics should be created using translatable messages - --> $DIR/diagnostics.rs:64:19 + --> $DIR/diagnostics.rs:63:19 | LL | diag.note("untranslatable diagnostic"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: diagnostics should be created using translatable messages - --> $DIR/diagnostics.rs:85:19 + --> $DIR/diagnostics.rs:83:19 | LL | diag.note("untranslatable diagnostic"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: diagnostics should only be created in `Diagnostic`/`Subdiagnostic`/`LintDiagnostic` impls - --> $DIR/diagnostics.rs:99:21 + --> $DIR/diagnostics.rs:97:21 | LL | let _diag = dcx.struct_err(crate::fluent_generated::no_crate_example); | ^^^^^^^^^^ @@ -35,37 +35,37 @@ LL | #![deny(rustc::diagnostic_outside_of_impl)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: diagnostics should only be created in `Diagnostic`/`Subdiagnostic`/`LintDiagnostic` impls - --> $DIR/diagnostics.rs:102:21 + --> $DIR/diagnostics.rs:100:21 | LL | let _diag = dcx.struct_err("untranslatable diagnostic"); | ^^^^^^^^^^ error: diagnostics should be created using translatable messages - --> $DIR/diagnostics.rs:102:32 + --> $DIR/diagnostics.rs:100:32 | LL | let _diag = dcx.struct_err("untranslatable diagnostic"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: diagnostics should be created using translatable messages - --> $DIR/diagnostics.rs:120:7 + --> $DIR/diagnostics.rs:118:7 | LL | f("untranslatable diagnostic", crate::fluent_generated::no_crate_example); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: diagnostics should be created using translatable messages - --> $DIR/diagnostics.rs:122:50 + --> $DIR/diagnostics.rs:120:50 | LL | f(crate::fluent_generated::no_crate_example, "untranslatable diagnostic"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: diagnostics should be created using translatable messages - --> $DIR/diagnostics.rs:124:7 + --> $DIR/diagnostics.rs:122:7 | LL | f("untranslatable diagnostic", "untranslatable diagnostic"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: diagnostics should be created using translatable messages - --> $DIR/diagnostics.rs:124:36 + --> $DIR/diagnostics.rs:122:36 | LL | f("untranslatable diagnostic", "untranslatable diagnostic"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui-fulldeps/missing-rustc-driver-error.rs b/tests/ui-fulldeps/missing-rustc-driver-error.rs index d582efada908..c6dff2d99dde 100644 --- a/tests/ui-fulldeps/missing-rustc-driver-error.rs +++ b/tests/ui-fulldeps/missing-rustc-driver-error.rs @@ -1,11 +1,15 @@ // Test that we get the following hint when trying to use a compiler crate without rustc_driver. -//@ error-pattern: try adding `extern crate rustc_driver;` at the top level of this crate -//@ compile-flags: --emit link --error-format=human +//@ compile-flags: --emit link //@ normalize-stderr: ".*crate .* required.*\n\n" -> "" //@ normalize-stderr: "aborting due to [0-9]+" -> "aborting due to NUMBER" +//@ dont-require-annotations: ERROR #![feature(rustc_private)] extern crate rustc_serialize; fn main() {} + +//~? HELP try adding `extern crate rustc_driver;` at the top level of this crate +//~? HELP try adding `extern crate rustc_driver;` at the top level of this crate +//~? HELP try adding `extern crate rustc_driver;` at the top level of this crate diff --git a/tests/ui-fulldeps/run-compiler-twice.rs b/tests/ui-fulldeps/run-compiler-twice.rs index ffc19b138a57..fa651baa7bc8 100644 --- a/tests/ui-fulldeps/run-compiler-twice.rs +++ b/tests/ui-fulldeps/run-compiler-twice.rs @@ -70,6 +70,7 @@ fn compile(code: String, output: PathBuf, sysroot: PathBuf, linker: Option<&Path hash_untracked_state: None, register_lints: None, override_queries: None, + extra_symbols: Vec::new(), make_codegen_backend: None, registry: rustc_driver::diagnostics_registry(), using_internal_features: &rustc_driver::USING_INTERNAL_FEATURES, diff --git a/tests/ui-fulldeps/stable-mir/check_abi.rs b/tests/ui-fulldeps/stable-mir/check_abi.rs index ef2d5b4854be..ebf2e333f085 100644 --- a/tests/ui-fulldeps/stable-mir/check_abi.rs +++ b/tests/ui-fulldeps/stable-mir/check_abi.rs @@ -17,7 +17,6 @@ extern crate rustc_driver; extern crate rustc_interface; extern crate stable_mir; -use rustc_smir::rustc_internal; use stable_mir::abi::{ ArgAbi, CallConvention, FieldsShape, IntegerLength, PassMode, Primitive, Scalar, ValueAbi, VariantsShape, diff --git a/tests/ui-fulldeps/stable-mir/check_allocation.rs b/tests/ui-fulldeps/stable-mir/check_allocation.rs index c102f86a2286..ae2609bbc122 100644 --- a/tests/ui-fulldeps/stable-mir/check_allocation.rs +++ b/tests/ui-fulldeps/stable-mir/check_allocation.rs @@ -19,7 +19,6 @@ extern crate rustc_driver; extern crate rustc_interface; extern crate stable_mir; -use rustc_smir::rustc_internal; use stable_mir::crate_def::CrateDef; use stable_mir::mir::alloc::GlobalAlloc; use stable_mir::mir::mono::{Instance, InstanceKind, StaticDef}; diff --git a/tests/ui-fulldeps/stable-mir/check_assoc_items.rs b/tests/ui-fulldeps/stable-mir/check_assoc_items.rs index f6f895588f27..9d611543b5aa 100644 --- a/tests/ui-fulldeps/stable-mir/check_assoc_items.rs +++ b/tests/ui-fulldeps/stable-mir/check_assoc_items.rs @@ -17,7 +17,6 @@ extern crate rustc_driver; extern crate rustc_interface; extern crate stable_mir; -use rustc_smir::rustc_internal; use std::io::Write; use std::collections::HashSet; use stable_mir::CrateDef; @@ -51,7 +50,7 @@ fn test_assoc_items() -> ControlFlow<()> { check_items( &trait_assoc_item_defs, &[ - "ATrait::{synthetic#0}", + "ATrait::{anon_assoc#0}", "ATrait::rpitit", "ATrait::Assoc", "ATrait::assoc_fn_no_self", @@ -64,7 +63,7 @@ fn test_assoc_items() -> ControlFlow<()> { check_items( &impl_assoc_item_defs, &[ - "::{synthetic#0}", + "::{anon_assoc#0}", "::rpitit", "::Assoc", "::assoc_fn_no_self", diff --git a/tests/ui-fulldeps/stable-mir/check_attribute.rs b/tests/ui-fulldeps/stable-mir/check_attribute.rs index de5ba15f6ea4..4148fc0cb6a0 100644 --- a/tests/ui-fulldeps/stable-mir/check_attribute.rs +++ b/tests/ui-fulldeps/stable-mir/check_attribute.rs @@ -15,7 +15,6 @@ extern crate rustc_driver; extern crate rustc_interface; extern crate stable_mir; -use rustc_smir::rustc_internal; use stable_mir::{CrateDef, CrateItems}; use std::io::Write; use std::ops::ControlFlow; diff --git a/tests/ui-fulldeps/stable-mir/check_binop.rs b/tests/ui-fulldeps/stable-mir/check_binop.rs index 65b3ffd27ab0..6a141e9c5775 100644 --- a/tests/ui-fulldeps/stable-mir/check_binop.rs +++ b/tests/ui-fulldeps/stable-mir/check_binop.rs @@ -15,7 +15,6 @@ extern crate rustc_driver; extern crate rustc_interface; extern crate stable_mir; -use rustc_smir::rustc_internal; use stable_mir::mir::mono::Instance; use stable_mir::mir::visit::{Location, MirVisitor}; use stable_mir::mir::{LocalDecl, Rvalue, Statement, StatementKind, Terminator, TerminatorKind}; diff --git a/tests/ui-fulldeps/stable-mir/check_crate_defs.rs b/tests/ui-fulldeps/stable-mir/check_crate_defs.rs index 71cca94c34f6..31c47192d090 100644 --- a/tests/ui-fulldeps/stable-mir/check_crate_defs.rs +++ b/tests/ui-fulldeps/stable-mir/check_crate_defs.rs @@ -16,7 +16,6 @@ extern crate rustc_driver; extern crate rustc_interface; extern crate stable_mir; -use rustc_smir::rustc_internal; use stable_mir::CrateDef; use std::collections::HashSet; use std::io::Write; diff --git a/tests/ui-fulldeps/stable-mir/check_def_ty.rs b/tests/ui-fulldeps/stable-mir/check_def_ty.rs index 37b9a83e33e7..00a34f138673 100644 --- a/tests/ui-fulldeps/stable-mir/check_def_ty.rs +++ b/tests/ui-fulldeps/stable-mir/check_def_ty.rs @@ -17,7 +17,6 @@ extern crate rustc_driver; extern crate rustc_interface; extern crate stable_mir; -use rustc_smir::rustc_internal; use stable_mir::ty::{Ty, ForeignItemKind}; use stable_mir::*; use std::io::Write; diff --git a/tests/ui-fulldeps/stable-mir/check_defs.rs b/tests/ui-fulldeps/stable-mir/check_defs.rs index cd3d76d87601..1ba73377d6e9 100644 --- a/tests/ui-fulldeps/stable-mir/check_defs.rs +++ b/tests/ui-fulldeps/stable-mir/check_defs.rs @@ -19,7 +19,6 @@ extern crate stable_mir; use std::assert_matches::assert_matches; use mir::{mono::Instance, TerminatorKind::*}; use stable_mir::mir::mono::InstanceKind; -use rustc_smir::rustc_internal; use stable_mir::ty::{RigidTy, TyKind, Ty, UintTy}; use stable_mir::*; use std::io::Write; diff --git a/tests/ui-fulldeps/stable-mir/check_foreign.rs b/tests/ui-fulldeps/stable-mir/check_foreign.rs index bc3956b30908..4419050ceb2c 100644 --- a/tests/ui-fulldeps/stable-mir/check_foreign.rs +++ b/tests/ui-fulldeps/stable-mir/check_foreign.rs @@ -17,7 +17,6 @@ extern crate rustc_interface; extern crate rustc_span; extern crate stable_mir; -use rustc_smir::rustc_internal; use stable_mir::{ ty::{Abi, ForeignItemKind}, *, diff --git a/tests/ui-fulldeps/stable-mir/check_instance.rs b/tests/ui-fulldeps/stable-mir/check_instance.rs index 72a138f907e7..1510a622cdfd 100644 --- a/tests/ui-fulldeps/stable-mir/check_instance.rs +++ b/tests/ui-fulldeps/stable-mir/check_instance.rs @@ -21,7 +21,6 @@ use std::ops::ControlFlow; use mir::mono::Instance; use mir::TerminatorKind::*; -use rustc_smir::rustc_internal; use stable_mir::ty::{RigidTy, TyKind}; use stable_mir::*; diff --git a/tests/ui-fulldeps/stable-mir/check_intrinsics.rs b/tests/ui-fulldeps/stable-mir/check_intrinsics.rs index 07a2a62e0668..3f04abbb9d76 100644 --- a/tests/ui-fulldeps/stable-mir/check_intrinsics.rs +++ b/tests/ui-fulldeps/stable-mir/check_intrinsics.rs @@ -20,7 +20,6 @@ extern crate rustc_driver; extern crate rustc_interface; extern crate stable_mir; -use rustc_smir::rustc_internal; use stable_mir::mir::mono::{Instance, InstanceKind}; use stable_mir::mir::visit::{Location, MirVisitor}; use stable_mir::mir::{LocalDecl, Terminator, TerminatorKind}; diff --git a/tests/ui-fulldeps/stable-mir/check_item_kind.rs b/tests/ui-fulldeps/stable-mir/check_item_kind.rs index 647ce534589e..bb8c00c64c95 100644 --- a/tests/ui-fulldeps/stable-mir/check_item_kind.rs +++ b/tests/ui-fulldeps/stable-mir/check_item_kind.rs @@ -16,7 +16,6 @@ extern crate rustc_driver; extern crate rustc_interface; extern crate stable_mir; -use rustc_smir::rustc_internal; use stable_mir::*; use std::io::Write; use std::ops::ControlFlow; diff --git a/tests/ui-fulldeps/stable-mir/check_normalization.rs b/tests/ui-fulldeps/stable-mir/check_normalization.rs index de14202adb9c..797cb4cd5d05 100644 --- a/tests/ui-fulldeps/stable-mir/check_normalization.rs +++ b/tests/ui-fulldeps/stable-mir/check_normalization.rs @@ -17,7 +17,6 @@ extern crate stable_mir; use mir::mono::Instance; use ty::{Ty, TyKind, RigidTy}; -use rustc_smir::rustc_internal; use stable_mir::*; use std::io::Write; use std::ops::ControlFlow; diff --git a/tests/ui-fulldeps/stable-mir/check_trait_queries.rs b/tests/ui-fulldeps/stable-mir/check_trait_queries.rs index 23c2844d3f16..d9170d0c4081 100644 --- a/tests/ui-fulldeps/stable-mir/check_trait_queries.rs +++ b/tests/ui-fulldeps/stable-mir/check_trait_queries.rs @@ -16,7 +16,6 @@ extern crate rustc_driver; extern crate rustc_interface; extern crate stable_mir; -use rustc_smir::rustc_internal; use stable_mir::CrateDef; use std::collections::HashSet; use std::io::Write; diff --git a/tests/ui-fulldeps/stable-mir/check_transform.rs b/tests/ui-fulldeps/stable-mir/check_transform.rs index d9fc924933fa..604cc72c3418 100644 --- a/tests/ui-fulldeps/stable-mir/check_transform.rs +++ b/tests/ui-fulldeps/stable-mir/check_transform.rs @@ -17,7 +17,6 @@ extern crate rustc_driver; extern crate rustc_interface; extern crate stable_mir; -use rustc_smir::rustc_internal; use stable_mir::mir::alloc::GlobalAlloc; use stable_mir::mir::mono::Instance; use stable_mir::mir::{Body, ConstOperand, Operand, Rvalue, StatementKind, TerminatorKind}; diff --git a/tests/ui-fulldeps/stable-mir/check_ty_fold.rs b/tests/ui-fulldeps/stable-mir/check_ty_fold.rs index 9d71697178e5..23233f8406cf 100644 --- a/tests/ui-fulldeps/stable-mir/check_ty_fold.rs +++ b/tests/ui-fulldeps/stable-mir/check_ty_fold.rs @@ -17,7 +17,6 @@ extern crate rustc_driver; extern crate rustc_interface; extern crate stable_mir; -use rustc_smir::rustc_internal; use stable_mir::mir::{ Body, FieldIdx, MirVisitor, Place, ProjectionElem, visit::{Location, PlaceContext}, diff --git a/tests/ui-fulldeps/stable-mir/compilation-result.rs b/tests/ui-fulldeps/stable-mir/compilation-result.rs index b8a9e720e546..39416636fd67 100644 --- a/tests/ui-fulldeps/stable-mir/compilation-result.rs +++ b/tests/ui-fulldeps/stable-mir/compilation-result.rs @@ -16,7 +16,6 @@ extern crate rustc_driver; extern crate rustc_interface; extern crate stable_mir; -use rustc_smir::rustc_internal; use std::io::Write; /// This test will generate and analyze a dummy crate using the stable mir. diff --git a/tests/ui-fulldeps/stable-mir/crate-info.rs b/tests/ui-fulldeps/stable-mir/crate-info.rs index 4d2d7e26276b..e2086d5e5790 100644 --- a/tests/ui-fulldeps/stable-mir/crate-info.rs +++ b/tests/ui-fulldeps/stable-mir/crate-info.rs @@ -18,7 +18,6 @@ extern crate rustc_interface; extern crate stable_mir; use rustc_hir::def::DefKind; -use rustc_smir::rustc_internal; use stable_mir::ItemKind; use stable_mir::crate_def::CrateDef; use stable_mir::mir::mono::Instance; diff --git a/tests/ui-fulldeps/stable-mir/projections.rs b/tests/ui-fulldeps/stable-mir/projections.rs index 6f82eba61fce..f3bd894ac690 100644 --- a/tests/ui-fulldeps/stable-mir/projections.rs +++ b/tests/ui-fulldeps/stable-mir/projections.rs @@ -17,7 +17,6 @@ extern crate rustc_driver; extern crate rustc_interface; extern crate stable_mir; -use rustc_smir::rustc_internal; use stable_mir::ItemKind; use stable_mir::crate_def::CrateDef; use stable_mir::mir::{ProjectionElem, Rvalue, StatementKind}; diff --git a/tests/ui-fulldeps/stable-mir/smir_serde.rs b/tests/ui-fulldeps/stable-mir/smir_serde.rs index 9b3638a9f2f4..3b3d743ad326 100644 --- a/tests/ui-fulldeps/stable-mir/smir_serde.rs +++ b/tests/ui-fulldeps/stable-mir/smir_serde.rs @@ -19,7 +19,6 @@ extern crate serde_json; extern crate stable_mir; use rustc_middle::ty::TyCtxt; -use rustc_smir::rustc_internal; use serde_json::to_string; use stable_mir::mir::Body; use std::io::{BufWriter, Write}; diff --git a/tests/ui-fulldeps/stable-mir/smir_visitor.rs b/tests/ui-fulldeps/stable-mir/smir_visitor.rs index 0a579a07cef1..d225d9773fe5 100644 --- a/tests/ui-fulldeps/stable-mir/smir_visitor.rs +++ b/tests/ui-fulldeps/stable-mir/smir_visitor.rs @@ -16,7 +16,6 @@ extern crate rustc_driver; extern crate rustc_interface; extern crate stable_mir; -use rustc_smir::rustc_internal; use stable_mir::mir::MirVisitor; use stable_mir::mir::MutMirVisitor; use stable_mir::*; diff --git a/tests/ui-fulldeps/try-from-u32/errors.rs b/tests/ui-fulldeps/try-from-u32/errors.rs index 0470063312cb..a25069c0a53c 100644 --- a/tests/ui-fulldeps/try-from-u32/errors.rs +++ b/tests/ui-fulldeps/try-from-u32/errors.rs @@ -8,17 +8,17 @@ extern crate rustc_macros; use rustc_macros::TryFromU32; #[derive(TryFromU32)] -struct MyStruct {} //~ type is not an enum +struct MyStruct {} //~ ERROR type is not an enum #[derive(TryFromU32)] enum NonTrivial { A, B(), C {}, - D(bool), //~ enum variant cannot have fields - E(bool, bool), //~ enum variant cannot have fields - F { x: bool }, //~ enum variant cannot have fields - G { x: bool, y: bool }, //~ enum variant cannot have fields + D(bool), //~ ERROR enum variant cannot have fields + E(bool, bool), //~ ERROR enum variant cannot have fields + F { x: bool }, //~ ERROR enum variant cannot have fields + G { x: bool, y: bool }, //~ ERROR enum variant cannot have fields } fn main() {} diff --git a/tests/ui/README.md b/tests/ui/README.md deleted file mode 100644 index aa36481ae06e..000000000000 --- a/tests/ui/README.md +++ /dev/null @@ -1,35 +0,0 @@ -# UI Tests - -This folder contains `rustc`'s -[UI tests](https://rustc-dev-guide.rust-lang.org/tests/ui.html). - -## Test Directives (Headers) - -Typically, a UI test will have some test directives / headers which are -special comments that tell compiletest how to build and interpret a test. - -As part of an ongoing effort to rewrite compiletest -(see ), a major -change proposal to change legacy compiletest-style headers `// ` -to [`ui_test`](https://github.com/oli-obk/ui_test)-style headers -`//@ ` was accepted (see -. - -An example directive is `ignore-test`. In legacy compiletest style, the header -would be written as - -```rs -// ignore-test -``` - -but in `ui_test` style, the header would be written as - -```rs -//@ ignore-test -``` - -compiletest is changed to accept only `//@` directives for UI tests -(currently), and will reject and report an error if it encounters any -comments `// ` that may be parsed as a legacy compiletest-style -test header. To fix this, you should migrate to the `ui_test`-style header -`//@ `. diff --git a/tests/ui/abi/abi-typo-unstable.stderr b/tests/ui/abi/abi-typo-unstable.feature_disabled.stderr similarity index 55% rename from tests/ui/abi/abi-typo-unstable.stderr rename to tests/ui/abi/abi-typo-unstable.feature_disabled.stderr index 9ba67ad7dbe4..1934b483c47a 100644 --- a/tests/ui/abi/abi-typo-unstable.stderr +++ b/tests/ui/abi/abi-typo-unstable.feature_disabled.stderr @@ -1,8 +1,8 @@ -error[E0703]: invalid ABI: found `rust-intrinsec` - --> $DIR/abi-typo-unstable.rs:2:8 +error[E0703]: invalid ABI: found `rust-cull` + --> $DIR/abi-typo-unstable.rs:5:8 | -LL | extern "rust-intrinsec" fn rust_intrinsic() {} - | ^^^^^^^^^^^^^^^^ invalid ABI +LL | extern "rust-cull" fn rust_call(_: ()) {} + | ^^^^^^^^^^^ invalid ABI | = note: invoke `rustc --print=calling-conventions` for a full list of supported calling conventions diff --git a/tests/ui/abi/abi-typo-unstable.feature_enabled.stderr b/tests/ui/abi/abi-typo-unstable.feature_enabled.stderr new file mode 100644 index 000000000000..868b9509830b --- /dev/null +++ b/tests/ui/abi/abi-typo-unstable.feature_enabled.stderr @@ -0,0 +1,16 @@ +error[E0703]: invalid ABI: found `rust-cull` + --> $DIR/abi-typo-unstable.rs:5:8 + | +LL | extern "rust-cull" fn rust_call(_: ()) {} + | ^^^^^^^^^^^ invalid ABI + | + = note: invoke `rustc --print=calling-conventions` for a full list of supported calling conventions +help: there's a similarly named valid ABI `rust-call` + | +LL - extern "rust-cull" fn rust_call(_: ()) {} +LL + extern "rust-call" fn rust_call(_: ()) {} + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0703`. diff --git a/tests/ui/abi/abi-typo-unstable.rs b/tests/ui/abi/abi-typo-unstable.rs index 94991a5eb17e..75366217fa26 100644 --- a/tests/ui/abi/abi-typo-unstable.rs +++ b/tests/ui/abi/abi-typo-unstable.rs @@ -1,6 +1,11 @@ -// rust-intrinsic is unstable and not enabled, so it should not be suggested as a fix -extern "rust-intrinsec" fn rust_intrinsic() {} //~ ERROR invalid ABI +//@ revisions: feature_disabled feature_enabled +#![cfg_attr(feature_enabled, feature(unboxed_closures))] + +// rust-call is unstable and not enabled, so it should not be suggested as a fix +extern "rust-cull" fn rust_call(_: ()) {} +//~^ ERROR invalid ABI +//[feature_enabled]~| HELP there's a similarly named valid ABI fn main() { - rust_intrinsic(); + rust_call(()); } diff --git a/tests/ui/abi/debug.rs b/tests/ui/abi/debug.rs index 6dbc31614641..c0d8de05fda5 100644 --- a/tests/ui/abi/debug.rs +++ b/tests/ui/abi/debug.rs @@ -52,3 +52,6 @@ type TestAbiNeSign = (fn(i32), fn(u32)); //~ ERROR: ABIs are not compatible #[rustc_abi(assert_eq)] type TestAbiEqNonsense = (fn((str, str)), fn((str, str))); //~ ERROR: cannot be known at compilation time + +#[rustc_abi("assert_eq")] //~ ERROR unrecognized argument +type Bad = u32; diff --git a/tests/ui/abi/debug.stderr b/tests/ui/abi/debug.stderr index 2239ba0e5880..480f3f04215e 100644 --- a/tests/ui/abi/debug.stderr +++ b/tests/ui/abi/debug.stderr @@ -906,6 +906,12 @@ LL | type TestAbiEqNonsense = (fn((str, str)), fn((str, str))); = help: the trait `Sized` is not implemented for `str` = note: only the last element of a tuple may have a dynamically sized type +error: unrecognized argument + --> $DIR/debug.rs:56:13 + | +LL | #[rustc_abi("assert_eq")] + | ^^^^^^^^^^^ + error: `#[rustc_abi]` can only be applied to function items, type aliases, and associated functions --> $DIR/debug.rs:29:5 | @@ -1004,6 +1010,6 @@ error: fn_abi_of(assoc_test) = FnAbi { LL | fn assoc_test(&self) { } | ^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 11 previous errors +error: aborting due to 12 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/abi/fixed_x18.rs b/tests/ui/abi/fixed_x18.rs index d373468f68fe..d64b845e5bd1 100644 --- a/tests/ui/abi/fixed_x18.rs +++ b/tests/ui/abi/fixed_x18.rs @@ -2,7 +2,6 @@ // Behavior on aarch64 is tested by tests/codegen/fixed-x18.rs. // //@ revisions: x64 i686 arm riscv32 riscv64 -//@ error-pattern: the `-Zfixed-x18` flag is not supported //@ dont-check-compiler-stderr // //@ compile-flags: -Zfixed-x18 diff --git a/tests/ui/abi/simd-abi-checks-avx.rs b/tests/ui/abi/simd-abi-checks-avx.rs index fa4b3ba3054f..c31af6460fc8 100644 --- a/tests/ui/abi/simd-abi-checks-avx.rs +++ b/tests/ui/abi/simd-abi-checks-avx.rs @@ -14,19 +14,19 @@ use std::arch::x86_64::*; struct Wrapper(__m256); unsafe extern "C" fn w(_: Wrapper) { - //~^ requires the `avx` target feature, which is not enabled + //~^ WARN requires the `avx` target feature, which is not enabled //~| WARNING this was previously accepted by the compiler todo!() } unsafe extern "C" fn f(_: __m256) { - //~^ requires the `avx` target feature, which is not enabled + //~^ WARN requires the `avx` target feature, which is not enabled //~| WARNING this was previously accepted by the compiler todo!() } unsafe extern "C" fn g() -> __m256 { - //~^ requires the `avx` target feature, which is not enabled + //~^ WARN requires the `avx` target feature, which is not enabled //~| WARNING this was previously accepted by the compiler todo!() } diff --git a/tests/ui/abi/simd-abi-checks-empty-list.rs b/tests/ui/abi/simd-abi-checks-empty-list.rs index ca0889364fc3..ba1b38af5b34 100644 --- a/tests/ui/abi/simd-abi-checks-empty-list.rs +++ b/tests/ui/abi/simd-abi-checks-empty-list.rs @@ -14,5 +14,5 @@ use minicore::*; pub struct SimdVec([i32; 4]); pub extern "C" fn pass_by_vec(_: SimdVec) {} -//~^ this function definition uses SIMD vector type `SimdVec` which is not currently supported with the chosen ABI +//~^ WARN this function definition uses SIMD vector type `SimdVec` which is not currently supported with the chosen ABI //~| WARNING this was previously accepted by the compiler diff --git a/tests/ui/abi/simd-abi-checks-sse.rs b/tests/ui/abi/simd-abi-checks-sse.rs index cb708bea3cae..d5fa9c0c0a3c 100644 --- a/tests/ui/abi/simd-abi-checks-sse.rs +++ b/tests/ui/abi/simd-abi-checks-sse.rs @@ -18,6 +18,6 @@ pub struct SseVector([i64; 2]); #[no_mangle] pub unsafe extern "C" fn f(_: SseVector) { - //~^ this function definition uses SIMD vector type `SseVector` which (with the chosen ABI) requires the `sse` target feature, which is not enabled + //~^ WARN this function definition uses SIMD vector type `SseVector` which (with the chosen ABI) requires the `sse` target feature, which is not enabled //~| WARNING this was previously accepted by the compiler } diff --git a/tests/ui/abi/vectorcall-abi-checks.rs b/tests/ui/abi/vectorcall-abi-checks.rs index d83bbffa745f..f3f399e0e313 100644 --- a/tests/ui/abi/vectorcall-abi-checks.rs +++ b/tests/ui/abi/vectorcall-abi-checks.rs @@ -11,11 +11,11 @@ use minicore::*; #[no_mangle] pub extern "vectorcall" fn f() { - //~^ ABI "vectorcall" which requires the `sse2` target feature + //~^ ERROR ABI "vectorcall" which requires the `sse2` target feature } #[no_mangle] pub fn call_site() { f(); - //~^ ABI "vectorcall" which requires the `sse2` target feature + //~^ ERROR ABI "vectorcall" which requires the `sse2` target feature } diff --git a/tests/ui/anon-params/anon-params-denied-2018.rs b/tests/ui/anon-params/anon-params-denied-2018.rs index 3602b401f857..d9d4363a6816 100644 --- a/tests/ui/anon-params/anon-params-denied-2018.rs +++ b/tests/ui/anon-params/anon-params-denied-2018.rs @@ -3,7 +3,7 @@ //@ edition:2018 trait T { - fn foo(i32); //~ expected one of `:`, `@`, or `|`, found `)` + fn foo(i32); //~ ERROR expected one of `:`, `@`, or `|`, found `)` // Also checks with `&` fn foo_with_ref(&mut i32); diff --git a/tests/ui/argument-suggestions/issue-100478.rs b/tests/ui/argument-suggestions/issue-100478.rs index fb50fa115376..b0a9703112e3 100644 --- a/tests/ui/argument-suggestions/issue-100478.rs +++ b/tests/ui/argument-suggestions/issue-100478.rs @@ -45,7 +45,7 @@ fn main() { let p8 = Arc::default(); foo( - //~^ 47:5: 47:8: this function takes 8 arguments but 7 arguments were supplied [E0061] + //~^ ERROR this function takes 8 arguments but 7 arguments were supplied [E0061] p1, //p2, p3, p4, p5, p6, p7, p8, ); diff --git a/tests/ui/argument-suggestions/issue-101097.rs b/tests/ui/argument-suggestions/issue-101097.rs index 25f7f5837992..9b1565fef6ff 100644 --- a/tests/ui/argument-suggestions/issue-101097.rs +++ b/tests/ui/argument-suggestions/issue-101097.rs @@ -15,7 +15,7 @@ fn f( fn main() { f(C, A, A, A, B, B, C); //~ ERROR function takes 6 arguments but 7 arguments were supplied [E0061] f(C, C, A, A, B, B); //~ ERROR arguments to this function are incorrect [E0308] - f(A, A, D, D, B, B); //~ arguments to this function are incorrect [E0308] - f(C, C, B, B, A, A); //~ arguments to this function are incorrect [E0308] - f(C, C, A, B, A, A); //~ arguments to this function are incorrect [E0308] + f(A, A, D, D, B, B); //~ ERROR arguments to this function are incorrect [E0308] + f(C, C, B, B, A, A); //~ ERROR arguments to this function are incorrect [E0308] + f(C, C, A, B, A, A); //~ ERROR arguments to this function are incorrect [E0308] } diff --git a/tests/ui/array-slice-vec/array_const_index-0.rs b/tests/ui/array-slice-vec/array_const_index-0.rs index 96755802ec7f..f4fe89a50c25 100644 --- a/tests/ui/array-slice-vec/array_const_index-0.rs +++ b/tests/ui/array-slice-vec/array_const_index-0.rs @@ -1,6 +1,6 @@ const A: &'static [i32] = &[]; const B: i32 = (&A)[1]; -//~^ index out of bounds: the length is 0 but the index is 1 +//~^ NOTE index out of bounds: the length is 0 but the index is 1 //~| ERROR evaluation of constant value failed fn main() { diff --git a/tests/ui/array-slice-vec/array_const_index-1.rs b/tests/ui/array-slice-vec/array_const_index-1.rs index 625bf06a745e..0d4de137a6e0 100644 --- a/tests/ui/array-slice-vec/array_const_index-1.rs +++ b/tests/ui/array-slice-vec/array_const_index-1.rs @@ -1,6 +1,6 @@ const A: [i32; 0] = []; const B: i32 = A[1]; -//~^ index out of bounds: the length is 0 but the index is 1 +//~^ NOTE index out of bounds: the length is 0 but the index is 1 //~| ERROR evaluation of constant value failed fn main() { diff --git a/tests/ui/asm/issue-85247.rs b/tests/ui/asm/issue-85247.rs index 47bfda14092d..f54c868dd561 100644 --- a/tests/ui/asm/issue-85247.rs +++ b/tests/ui/asm/issue-85247.rs @@ -18,6 +18,6 @@ use minicore::*; fn main() { unsafe { asm!("", out("r9") _); - //[rwpi]~^ cannot use register `r9` + //[rwpi]~^ ERROR cannot use register `r9` } } diff --git a/tests/ui/asm/issue-99071.rs b/tests/ui/asm/issue-99071.rs index 6a00fce7de46..522ac1fe8877 100644 --- a/tests/ui/asm/issue-99071.rs +++ b/tests/ui/asm/issue-99071.rs @@ -13,6 +13,6 @@ use minicore::*; 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 + //~^ ERROR cannot use register `r8`: high registers (r8+) can only be used as clobbers in Thumb-1 code } } diff --git a/tests/ui/asm/naked-functions-rustic-abi.rs b/tests/ui/asm/naked-functions-rustic-abi.rs new file mode 100644 index 000000000000..b654d38ccc1a --- /dev/null +++ b/tests/ui/asm/naked-functions-rustic-abi.rs @@ -0,0 +1,27 @@ +//@ revisions: x86_64 aarch64 +// +//@[aarch64] only-aarch64 +//@[x86_64] only-x86_64 +// +//@ build-pass +//@ needs-asm-support + +#![feature(naked_functions, naked_functions_rustic_abi, rust_cold_cc)] +#![crate_type = "lib"] + +use std::arch::{asm, naked_asm}; + +#[naked] +pub unsafe fn rust_implicit() { + naked_asm!("ret"); +} + +#[naked] +pub unsafe extern "Rust" fn rust_explicit() { + naked_asm!("ret"); +} + +#[naked] +pub unsafe extern "rust-cold" fn rust_cold() { + naked_asm!("ret"); +} diff --git a/tests/ui/asm/naked-functions-testattrs.rs b/tests/ui/asm/naked-functions-testattrs.rs index 7e373270e9fc..ad31876a77a5 100644 --- a/tests/ui/asm/naked-functions-testattrs.rs +++ b/tests/ui/asm/naked-functions-testattrs.rs @@ -1,7 +1,6 @@ //@ needs-asm-support //@ compile-flags: --test -#![allow(undefined_naked_function_abi)] #![feature(naked_functions)] #![feature(test)] #![crate_type = "lib"] @@ -11,7 +10,7 @@ use std::arch::naked_asm; #[test] #[naked] //~^ ERROR [E0736] -fn test_naked() { +extern "C" fn test_naked() { unsafe { naked_asm!("") }; } @@ -19,7 +18,7 @@ fn test_naked() { #[test] #[naked] //~^ ERROR [E0736] -fn test_naked_should_panic() { +extern "C" fn test_naked_should_panic() { unsafe { naked_asm!("") }; } @@ -27,13 +26,13 @@ fn test_naked_should_panic() { #[test] #[naked] //~^ ERROR [E0736] -fn test_naked_ignore() { +extern "C" fn test_naked_ignore() { unsafe { naked_asm!("") }; } #[bench] #[naked] //~^ ERROR [E0736] -fn bench_naked() { +extern "C" fn bench_naked() { unsafe { naked_asm!("") }; } diff --git a/tests/ui/asm/naked-functions-testattrs.stderr b/tests/ui/asm/naked-functions-testattrs.stderr index 4dabe41964a5..0f0bb91b9541 100644 --- a/tests/ui/asm/naked-functions-testattrs.stderr +++ b/tests/ui/asm/naked-functions-testattrs.stderr @@ -1,5 +1,5 @@ error[E0736]: cannot use `#[naked]` with testing attributes - --> $DIR/naked-functions-testattrs.rs:12:1 + --> $DIR/naked-functions-testattrs.rs:11:1 | LL | #[test] | ------- function marked with testing attribute here @@ -7,7 +7,7 @@ LL | #[naked] | ^^^^^^^^ `#[naked]` is incompatible with testing attributes error[E0736]: cannot use `#[naked]` with testing attributes - --> $DIR/naked-functions-testattrs.rs:20:1 + --> $DIR/naked-functions-testattrs.rs:19:1 | LL | #[test] | ------- function marked with testing attribute here @@ -15,7 +15,7 @@ LL | #[naked] | ^^^^^^^^ `#[naked]` is incompatible with testing attributes error[E0736]: cannot use `#[naked]` with testing attributes - --> $DIR/naked-functions-testattrs.rs:28:1 + --> $DIR/naked-functions-testattrs.rs:27:1 | LL | #[test] | ------- function marked with testing attribute here @@ -23,7 +23,7 @@ LL | #[naked] | ^^^^^^^^ `#[naked]` is incompatible with testing attributes error[E0736]: cannot use `#[naked]` with testing attributes - --> $DIR/naked-functions-testattrs.rs:35:1 + --> $DIR/naked-functions-testattrs.rs:34:1 | LL | #[bench] | -------- function marked with testing attribute here diff --git a/tests/ui/asm/naked-functions.rs b/tests/ui/asm/naked-functions.rs index 3d4d414539c1..8ba0eecb7b5c 100644 --- a/tests/ui/asm/naked-functions.rs +++ b/tests/ui/asm/naked-functions.rs @@ -8,7 +8,7 @@ use std::arch::{asm, naked_asm}; -#[naked] +#[unsafe(naked)] pub unsafe extern "C" fn inline_asm_macro() { asm!("", options(raw)); //~^ERROR the `asm!` macro is not allowed in naked functions @@ -20,7 +20,7 @@ pub struct P { y: u16, } -#[naked] +#[unsafe(naked)] pub unsafe extern "C" fn patterns( mut a: u32, //~^ ERROR patterns not allowed in naked function parameters @@ -34,27 +34,27 @@ pub unsafe extern "C" fn patterns( naked_asm!("") } -#[naked] +#[unsafe(naked)] pub unsafe extern "C" fn inc(a: u32) -> u32 { //~^ ERROR naked functions must contain a single `naked_asm!` invocation a + 1 //~^ ERROR referencing function parameters is not allowed in naked functions } -#[naked] +#[unsafe(naked)] #[allow(asm_sub_register)] pub unsafe extern "C" fn inc_asm(a: u32) -> u32 { naked_asm!("/* {0} */", in(reg) a) //~^ ERROR the `in` operand cannot be used with `naked_asm!` } -#[naked] +#[unsafe(naked)] pub unsafe extern "C" fn inc_closure(a: u32) -> u32 { //~^ ERROR naked functions must contain a single `naked_asm!` invocation (|| a + 1)() } -#[naked] +#[unsafe(naked)] pub unsafe extern "C" fn unsupported_operands() { //~^ ERROR naked functions must contain a single `naked_asm!` invocation let mut a = 0usize; @@ -76,12 +76,12 @@ pub unsafe extern "C" fn unsupported_operands() { ); } -#[naked] +#[unsafe(naked)] pub extern "C" fn missing_assembly() { //~^ ERROR naked functions must contain a single `naked_asm!` invocation } -#[naked] +#[unsafe(naked)] pub extern "C" fn too_many_asm_blocks() { //~^ ERROR naked functions must contain a single `naked_asm!` invocation unsafe { @@ -92,7 +92,7 @@ pub extern "C" fn too_many_asm_blocks() { } pub fn outer(x: u32) -> extern "C" fn(usize) -> usize { - #[naked] + #[unsafe(naked)] pub extern "C" fn inner(y: usize) -> usize { //~^ ERROR naked functions must contain a single `naked_asm!` invocation *&y @@ -101,14 +101,14 @@ pub fn outer(x: u32) -> extern "C" fn(usize) -> usize { inner } -#[naked] +#[unsafe(naked)] unsafe extern "C" fn invalid_options() { naked_asm!("", options(nomem, preserves_flags)); //~^ ERROR the `nomem` option cannot be used with `naked_asm!` //~| ERROR the `preserves_flags` option cannot be used with `naked_asm!` } -#[naked] +#[unsafe(naked)] unsafe extern "C" fn invalid_options_continued() { naked_asm!("", options(readonly, nostack), options(pure)); //~^ ERROR the `readonly` option cannot be used with `naked_asm!` @@ -116,32 +116,20 @@ unsafe extern "C" fn invalid_options_continued() { //~| ERROR the `pure` option cannot be used with `naked_asm!` } -#[naked] +#[unsafe(naked)] unsafe extern "C" fn invalid_may_unwind() { naked_asm!("", options(may_unwind)); //~^ ERROR the `may_unwind` option cannot be used with `naked_asm!` } -#[naked] -pub unsafe fn default_abi() { - //~^ WARN Rust ABI is unsupported in naked functions - naked_asm!(""); -} - -#[naked] -pub unsafe fn rust_abi() { - //~^ WARN Rust ABI is unsupported in naked functions - naked_asm!(""); -} - -#[naked] +#[unsafe(naked)] pub extern "C" fn valid_a() -> T { unsafe { naked_asm!(""); } } -#[naked] +#[unsafe(naked)] pub extern "C" fn valid_b() { unsafe { { @@ -152,32 +140,32 @@ pub extern "C" fn valid_b() { } } -#[naked] +#[unsafe(naked)] pub unsafe extern "C" fn valid_c() { naked_asm!(""); } #[cfg(target_arch = "x86_64")] -#[naked] +#[unsafe(naked)] pub unsafe extern "C" fn valid_att_syntax() { naked_asm!("", options(att_syntax)); } -#[naked] -#[naked] +#[unsafe(naked)] +#[unsafe(naked)] pub unsafe extern "C" fn allow_compile_error(a: u32) -> u32 { compile_error!("this is a user specified error") //~^ ERROR this is a user specified error } -#[naked] +#[unsafe(naked)] pub unsafe extern "C" fn allow_compile_error_and_asm(a: u32) -> u32 { compile_error!("this is a user specified error"); //~^ ERROR this is a user specified error naked_asm!("") } -#[naked] +#[unsafe(naked)] pub unsafe extern "C" fn invalid_asm_syntax(a: u32) -> u32 { naked_asm!(invalid_syntax) //~^ ERROR asm template must be a string literal @@ -185,7 +173,7 @@ pub unsafe extern "C" fn invalid_asm_syntax(a: u32) -> u32 { #[cfg(target_arch = "x86_64")] #[cfg_attr(target_pointer_width = "64", no_mangle)] -#[naked] +#[unsafe(naked)] pub unsafe extern "C" fn compatible_cfg_attributes() { naked_asm!("", options(att_syntax)); } @@ -194,20 +182,20 @@ pub unsafe extern "C" fn compatible_cfg_attributes() { #[warn(dead_code)] #[deny(dead_code)] #[forbid(dead_code)] -#[naked] +#[unsafe(naked)] pub unsafe extern "C" fn compatible_diagnostic_attributes() { naked_asm!("", options(raw)); } #[deprecated = "test"] -#[naked] +#[unsafe(naked)] pub unsafe extern "C" fn compatible_deprecated_attributes() { naked_asm!("", options(raw)); } #[cfg(target_arch = "x86_64")] #[must_use] -#[naked] +#[unsafe(naked)] pub unsafe extern "C" fn compatible_must_use_attributes() -> u64 { naked_asm!( " @@ -219,13 +207,13 @@ pub unsafe extern "C" fn compatible_must_use_attributes() -> u64 { #[export_name = "exported_function_name"] #[link_section = ".custom_section"] -#[naked] +#[unsafe(naked)] pub unsafe extern "C" fn compatible_ffi_attributes_1() { naked_asm!("", options(raw)); } #[cold] -#[naked] +#[unsafe(naked)] pub unsafe extern "C" fn compatible_codegen_attributes() { naked_asm!("", options(raw)); } @@ -234,13 +222,13 @@ pub unsafe extern "C" fn compatible_codegen_attributes() { /// a doc comment // a normal comment #[doc(alias = "ADocAlias")] -#[naked] +#[unsafe(naked)] pub unsafe extern "C" fn compatible_doc_attributes() { naked_asm!("", options(raw)); } #[linkage = "external"] -#[naked] +#[unsafe(naked)] pub unsafe extern "C" fn compatible_linkage() { naked_asm!("", options(raw)); } diff --git a/tests/ui/asm/naked-functions.stderr b/tests/ui/asm/naked-functions.stderr index 0898f3620f24..0a55bb9cd837 100644 --- a/tests/ui/asm/naked-functions.stderr +++ b/tests/ui/asm/naked-functions.stderr @@ -53,19 +53,19 @@ LL | naked_asm!("", options(may_unwind)); | ^^^^^^^^^^ the `may_unwind` option is not meaningful for global-scoped inline assembly error: this is a user specified error - --> $DIR/naked-functions.rs:169:5 + --> $DIR/naked-functions.rs:157:5 | LL | compile_error!("this is a user specified error") | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this is a user specified error - --> $DIR/naked-functions.rs:175:5 + --> $DIR/naked-functions.rs:163:5 | LL | compile_error!("this is a user specified error"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: asm template must be a string literal - --> $DIR/naked-functions.rs:182:16 + --> $DIR/naked-functions.rs:170:16 | LL | naked_asm!(invalid_syntax) | ^^^^^^^^^^^^^^ @@ -175,20 +175,6 @@ LL | LL | *&y | --- not allowed in naked functions -warning: Rust ABI is unsupported in naked functions - --> $DIR/naked-functions.rs:126:1 - | -LL | pub unsafe fn default_abi() { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `#[warn(undefined_naked_function_abi)]` on by default - -warning: Rust ABI is unsupported in naked functions - --> $DIR/naked-functions.rs:132:1 - | -LL | pub unsafe fn rust_abi() { - | ^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 25 previous errors; 2 warnings emitted +error: aborting due to 25 previous errors For more information about this error, try `rustc --explain E0787`. diff --git a/tests/ui/asm/type-check-4.rs b/tests/ui/asm/type-check-4.rs index a5b5e29294bb..97b1ab74a7ec 100644 --- a/tests/ui/asm/type-check-4.rs +++ b/tests/ui/asm/type-check-4.rs @@ -11,7 +11,7 @@ fn main() { let mut a = 0isize; let p = &a; asm!("{}", out(reg) a); - //~^ cannot assign to `a` because it is borrowed + //~^ ERROR cannot assign to `a` because it is borrowed println!("{}", p); // Can't read from mutable borrowed values. @@ -19,7 +19,7 @@ fn main() { let mut a = 0isize; let p = &mut a; asm!("{}", in(reg) a); - //~^ cannot use `a` because it was mutably borrowed + //~^ ERROR cannot use `a` because it was mutably borrowed println!("{}", p); } } diff --git a/tests/ui/asm/unpretty-expanded.rs b/tests/ui/asm/unpretty-expanded.rs index 1da2c7704f41..3eb46fe4889c 100644 --- a/tests/ui/asm/unpretty-expanded.rs +++ b/tests/ui/asm/unpretty-expanded.rs @@ -1,4 +1,5 @@ //@ needs-asm-support //@ check-pass //@ compile-flags: -Zunpretty=expanded +//@ edition: 2015 core::arch::global_asm!("x: .byte 42"); diff --git a/tests/ui/asm/unpretty-expanded.stdout b/tests/ui/asm/unpretty-expanded.stdout index 80ccd127d506..7ba1702dfed8 100644 --- a/tests/ui/asm/unpretty-expanded.stdout +++ b/tests/ui/asm/unpretty-expanded.stdout @@ -7,4 +7,5 @@ extern crate std; //@ needs-asm-support //@ check-pass //@ compile-flags: -Zunpretty=expanded +//@ edition: 2015 global_asm! ("x: .byte 42"); diff --git a/tests/ui/asm/x86_64/issue-82869.rs b/tests/ui/asm/x86_64/issue-82869.rs index 5d3f417f7337..448ebd9c99f4 100644 --- a/tests/ui/asm/x86_64/issue-82869.rs +++ b/tests/ui/asm/x86_64/issue-82869.rs @@ -12,9 +12,9 @@ pub unsafe fn aarch64(a: f64, b: f64) -> f64 { || {}; b }); - //~^^^^ invalid register class - //~^^^^^ invalid register class - //~^^^^^^ invalid register + //~^^^^ ERROR invalid register class + //~^^^^^ ERROR invalid register class + //~^^^^^^ ERROR invalid register c } diff --git a/tests/ui/associated-consts/defaults-cyclic-fail.rs b/tests/ui/associated-consts/defaults-cyclic-fail.rs index b868ef310041..cc3b60b30e5d 100644 --- a/tests/ui/associated-consts/defaults-cyclic-fail.rs +++ b/tests/ui/associated-consts/defaults-cyclic-fail.rs @@ -3,7 +3,7 @@ // Cyclic assoc. const defaults don't error unless *used* trait Tr { const A: u8 = Self::B; - //~^ cycle detected + //~^ ERROR cycle detected const B: u8 = Self::A; } diff --git a/tests/ui/associated-inherent-types/generic-associated-types-bad.rs b/tests/ui/associated-inherent-types/generic-associated-types-bad.rs index fdc2a0f64e49..fd3281cefeef 100644 --- a/tests/ui/associated-inherent-types/generic-associated-types-bad.rs +++ b/tests/ui/associated-inherent-types/generic-associated-types-bad.rs @@ -13,8 +13,8 @@ impl Ty { } #[cfg(item)] -const _: Ty::Pr = String::new(); //[item]~ the trait bound `String: Copy` is not satisfied -//[item]~^ the trait bound `String: Copy` is not satisfied +const _: Ty::Pr = String::new(); //[item]~ ERROR the trait bound `String: Copy` is not satisfied +//[item]~^ ERROR the trait bound `String: Copy` is not satisfied fn main() { #[cfg(local)] diff --git a/tests/ui/associated-type-bounds/return-type-notation/path-missing.rs b/tests/ui/associated-type-bounds/return-type-notation/path-missing.rs index 8cab48bd0c45..1ad02f754db5 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/path-missing.rs +++ b/tests/ui/associated-type-bounds/return-type-notation/path-missing.rs @@ -17,7 +17,7 @@ where fn type_dependent() where T::method(..): Send, - //~^ associated function `method` not found for `T` + //~^ ERROR associated function `method` not found for `T` { } diff --git a/tests/ui/associated-types/associated-type-macro.rs b/tests/ui/associated-types/associated-type-macro.rs index 22b5bca40103..8586dc172764 100644 --- a/tests/ui/associated-types/associated-type-macro.rs +++ b/tests/ui/associated-types/associated-type-macro.rs @@ -1,4 +1,4 @@ fn main() { - #[cfg(FALSE)] + #[cfg(false)] <() as module>::mac!(); //~ ERROR macros cannot use qualified paths } diff --git a/tests/ui/associated-types/associated-types-in-ambiguous-context.stderr b/tests/ui/associated-types/associated-types-in-ambiguous-context.stderr index d7d2161e7ad9..1be8db5ddf44 100644 --- a/tests/ui/associated-types/associated-types-in-ambiguous-context.stderr +++ b/tests/ui/associated-types/associated-types-in-ambiguous-context.stderr @@ -10,24 +10,6 @@ LL - fn get(x: T, y: U) -> Get::Value {} LL + fn get(x: T, y: U) -> ::Value {} | -error[E0223]: ambiguous associated type - --> $DIR/associated-types-in-ambiguous-context.rs:13:23 - | -LL | fn grab(&self) -> Grab::Value; - | ^^^^^^^^^^^ help: use fully-qualified syntax: `::Value` - -error[E0223]: ambiguous associated type - --> $DIR/associated-types-in-ambiguous-context.rs:16:22 - | -LL | fn get(&self) -> Get::Value; - | ^^^^^^^^^^ - | -help: if there were a type named `Example` that implemented `Get`, you could use the fully-qualified path - | -LL - fn get(&self) -> Get::Value; -LL + fn get(&self) -> ::Value; - | - error[E0223]: ambiguous associated type --> $DIR/associated-types-in-ambiguous-context.rs:22:17 | @@ -56,6 +38,24 @@ LL + type X = as Deref>::Target; | and N other candidates +error[E0223]: ambiguous associated type + --> $DIR/associated-types-in-ambiguous-context.rs:13:23 + | +LL | fn grab(&self) -> Grab::Value; + | ^^^^^^^^^^^ help: use fully-qualified syntax: `::Value` + +error[E0223]: ambiguous associated type + --> $DIR/associated-types-in-ambiguous-context.rs:16:22 + | +LL | fn get(&self) -> Get::Value; + | ^^^^^^^^^^ + | +help: if there were a type named `Example` that implemented `Get`, you could use the fully-qualified path + | +LL - fn get(&self) -> Get::Value; +LL + fn get(&self) -> ::Value; + | + error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0223`. diff --git a/tests/ui/associated-types/hr-associated-type-bound-2.rs b/tests/ui/associated-types/hr-associated-type-bound-2.rs index a89f61a81a57..467400f4b800 100644 --- a/tests/ui/associated-types/hr-associated-type-bound-2.rs +++ b/tests/ui/associated-types/hr-associated-type-bound-2.rs @@ -8,7 +8,7 @@ where } } -impl X<'_> for u32 //~ overflow evaluating the requirement `for<'b> u32: X<'b>` +impl X<'_> for u32 //~ ERROR overflow evaluating the requirement `for<'b> u32: X<'b>` where for<'b> >::U: Clone, { diff --git a/tests/ui/associated-types/hr-associated-type-bound-param-2.rs b/tests/ui/associated-types/hr-associated-type-bound-param-2.rs index 673f02c7cd0e..d6546c24dc50 100644 --- a/tests/ui/associated-types/hr-associated-type-bound-param-2.rs +++ b/tests/ui/associated-types/hr-associated-type-bound-param-2.rs @@ -1,16 +1,16 @@ trait Z<'a, T: ?Sized> where T: Z<'a, u16>, - //~^ the trait bound `str: Clone` is not satisfied - //~| the trait bound `str: Clone` is not satisfied + //~^ ERROR the trait bound `str: Clone` is not satisfied + //~| ERROR the trait bound `str: Clone` is not satisfied for<'b> >::W: Clone, { type W: ?Sized; fn h(&self, x: &T::W) { ::clone(x); - //~^ the trait bound `str: Clone` is not satisfied - //~| the trait bound `str: Clone` is not satisfied - //~| the trait bound `str: Clone` is not satisfied + //~^ ERROR the trait bound `str: Clone` is not satisfied + //~| ERROR the trait bound `str: Clone` is not satisfied + //~| ERROR the trait bound `str: Clone` is not satisfied } } diff --git a/tests/ui/associated-types/hr-associated-type-projection-1.rs b/tests/ui/associated-types/hr-associated-type-projection-1.rs index d7fc5d122c3e..1d272a660446 100644 --- a/tests/ui/associated-types/hr-associated-type-projection-1.rs +++ b/tests/ui/associated-types/hr-associated-type-projection-1.rs @@ -12,10 +12,10 @@ where impl UnsafeCopy<'_, T> for T { type Item = T; - //~^ type mismatch resolving `::Target == T` + //~^ ERROR type mismatch resolving `::Target == T` } pub fn main() { <&'static str>::bug(&""); - //~^ type mismatch resolving `<&str as Deref>::Target == &str` + //~^ ERROR type mismatch resolving `<&str as Deref>::Target == &str` } diff --git a/tests/ui/associated-types/impl-wf-cycle-4.rs b/tests/ui/associated-types/impl-wf-cycle-4.rs index bfa8adc71a11..1c1b3991d32a 100644 --- a/tests/ui/associated-types/impl-wf-cycle-4.rs +++ b/tests/ui/associated-types/impl-wf-cycle-4.rs @@ -2,7 +2,7 @@ trait Filter { type ToMatch; } -impl Filter for T //~ ERROR overflow evaluating the requirement +impl Filter for T //~ ERROR cycle detected when where T: Fn(Self::ToMatch), { diff --git a/tests/ui/associated-types/impl-wf-cycle-4.stderr b/tests/ui/associated-types/impl-wf-cycle-4.stderr index cdbac267d34d..c966579aecf1 100644 --- a/tests/ui/associated-types/impl-wf-cycle-4.stderr +++ b/tests/ui/associated-types/impl-wf-cycle-4.stderr @@ -1,4 +1,4 @@ -error[E0275]: overflow evaluating the requirement `::ToMatch == ::ToMatch` +error[E0391]: cycle detected when computing normalized predicates of `` --> $DIR/impl-wf-cycle-4.rs:5:1 | LL | / impl Filter for T @@ -6,20 +6,23 @@ LL | | where LL | | T: Fn(Self::ToMatch), | |_________________________^ | -note: required for `T` to implement `Filter` - --> $DIR/impl-wf-cycle-4.rs:5:9 +note: ...which requires computing whether `` has a guaranteed unsized self type... + --> $DIR/impl-wf-cycle-4.rs:5:1 | -LL | impl Filter for T - | ^^^^^^ ^ -LL | where -LL | T: Fn(Self::ToMatch), - | ----------------- unsatisfied trait bound introduced here -note: associated types for the current `impl` cannot be restricted in `where` clauses - --> $DIR/impl-wf-cycle-4.rs:7:11 +LL | / impl Filter for T +LL | | where +LL | | T: Fn(Self::ToMatch), + | |_________________________^ + = note: ...which again requires computing normalized predicates of ``, completing the cycle +note: cycle used when checking that `` is well-formed + --> $DIR/impl-wf-cycle-4.rs:5:1 | -LL | T: Fn(Self::ToMatch), - | ^^^^^^^^^^^^^ +LL | / impl Filter for T +LL | | where +LL | | T: Fn(Self::ToMatch), + | |_________________________^ + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0275`. +For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/associated-types/issue-36499.rs b/tests/ui/associated-types/issue-36499.rs index 606918b40b70..941b1aaa0d54 100644 --- a/tests/ui/associated-types/issue-36499.rs +++ b/tests/ui/associated-types/issue-36499.rs @@ -1,5 +1,3 @@ -//@ error-pattern: aborting due to 1 previous error - fn main() { 2 + +2; //~ ERROR leading `+` is not supported } diff --git a/tests/ui/associated-types/issue-36499.stderr b/tests/ui/associated-types/issue-36499.stderr index dd91bac81586..aebf0faae2dc 100644 --- a/tests/ui/associated-types/issue-36499.stderr +++ b/tests/ui/associated-types/issue-36499.stderr @@ -1,5 +1,5 @@ error: leading `+` is not supported - --> $DIR/issue-36499.rs:4:9 + --> $DIR/issue-36499.rs:2:9 | LL | 2 + +2; | ^ unexpected `+` diff --git a/tests/ui/associated-types/issue-85103-layout-debug.rs b/tests/ui/associated-types/issue-85103-layout-debug.rs index 77c9876ffa57..29a59924ef08 100644 --- a/tests/ui/associated-types/issue-85103-layout-debug.rs +++ b/tests/ui/associated-types/issue-85103-layout-debug.rs @@ -4,6 +4,6 @@ use std::borrow::Cow; #[rustc_layout(debug)] type Edges<'a, E> = Cow<'a, [E]>; -//~^ the trait bound `[E]: ToOwned` is not satisfied +//~^ ERROR the trait bound `[E]: ToOwned` is not satisfied fn main() {} diff --git a/tests/ui/associated-types/remove-invalid-type-bound-suggest-issue-127555.rs b/tests/ui/associated-types/remove-invalid-type-bound-suggest-issue-127555.rs index 4dfeab9e8c3f..70685504cccc 100644 --- a/tests/ui/associated-types/remove-invalid-type-bound-suggest-issue-127555.rs +++ b/tests/ui/associated-types/remove-invalid-type-bound-suggest-issue-127555.rs @@ -13,7 +13,7 @@ impl Foo for Baz { async fn bar(&mut self, _func: F) -> () where F: FnMut() + Send, - //~^ impl has stricter requirements than trait + //~^ ERROR impl has stricter requirements than trait { () } diff --git a/tests/ui/async-await/async-closures/closure-shim-borrowck-error.rs b/tests/ui/async-await/async-closures/closure-shim-borrowck-error.rs index 069744a3282d..12dca587e07d 100644 --- a/tests/ui/async-await/async-closures/closure-shim-borrowck-error.rs +++ b/tests/ui/async-await/async-closures/closure-shim-borrowck-error.rs @@ -1,4 +1,5 @@ -//@ compile-flags: -Zvalidate-mir --edition=2018 --crate-type=lib -Copt-level=3 +//@ compile-flags: -Zvalidate-mir --crate-type=lib -Copt-level=3 +//@ edition: 2018 fn main() {} diff --git a/tests/ui/async-await/async-closures/closure-shim-borrowck-error.stderr b/tests/ui/async-await/async-closures/closure-shim-borrowck-error.stderr index 52697bac5098..03fa220b0bfa 100644 --- a/tests/ui/async-await/async-closures/closure-shim-borrowck-error.stderr +++ b/tests/ui/async-await/async-closures/closure-shim-borrowck-error.stderr @@ -1,5 +1,5 @@ error[E0507]: cannot move out of `x` which is behind a mutable reference - --> $DIR/closure-shim-borrowck-error.rs:10:18 + --> $DIR/closure-shim-borrowck-error.rs:11:18 | LL | needs_fn_mut(async || { | ^^^^^^^^ `x` is moved here @@ -11,7 +11,7 @@ LL | x.hello(); | move occurs because `x` has type `Ty`, which does not implement the `Copy` trait | note: if `Ty` implemented `Clone`, you could clone the value - --> $DIR/closure-shim-borrowck-error.rs:16:1 + --> $DIR/closure-shim-borrowck-error.rs:17:1 | LL | x.hello(); | - you could clone this value diff --git a/tests/ui/async-await/async-gen-move-suggestion.fixed b/tests/ui/async-await/async-gen-move-suggestion.fixed new file mode 100644 index 000000000000..d80207655289 --- /dev/null +++ b/tests/ui/async-await/async-gen-move-suggestion.fixed @@ -0,0 +1,35 @@ +// This is a regression test for . +// It ensures that the "add `move` keyword" suggestion is valid. + +//@ run-rustfix +//@ edition:2024 + +#![feature(coroutines)] +#![feature(gen_blocks)] +#![feature(async_iterator)] + +use std::async_iter::AsyncIterator; + +#[allow(dead_code)] +fn moved() -> impl AsyncIterator { + let mut x = "foo".to_string(); + + async gen move { //~ ERROR + x.clear(); + for x in 3..6 { yield x } + } +} + +#[allow(dead_code)] +fn check_with_whitespace_chars() -> impl AsyncIterator { + let mut x = "foo".to_string(); + + async // Just to check that whitespace characters are correctly handled + gen move { //~^ ERROR + x.clear(); + for x in 3..6 { yield x } + } +} + +fn main() { +} diff --git a/tests/ui/async-await/async-gen-move-suggestion.rs b/tests/ui/async-await/async-gen-move-suggestion.rs new file mode 100644 index 000000000000..825fb0fd1898 --- /dev/null +++ b/tests/ui/async-await/async-gen-move-suggestion.rs @@ -0,0 +1,35 @@ +// This is a regression test for . +// It ensures that the "add `move` keyword" suggestion is valid. + +//@ run-rustfix +//@ edition:2024 + +#![feature(coroutines)] +#![feature(gen_blocks)] +#![feature(async_iterator)] + +use std::async_iter::AsyncIterator; + +#[allow(dead_code)] +fn moved() -> impl AsyncIterator { + let mut x = "foo".to_string(); + + async gen { //~ ERROR + x.clear(); + for x in 3..6 { yield x } + } +} + +#[allow(dead_code)] +fn check_with_whitespace_chars() -> impl AsyncIterator { + let mut x = "foo".to_string(); + + async // Just to check that whitespace characters are correctly handled + gen { //~^ ERROR + x.clear(); + for x in 3..6 { yield x } + } +} + +fn main() { +} diff --git a/tests/ui/async-await/async-gen-move-suggestion.stderr b/tests/ui/async-await/async-gen-move-suggestion.stderr new file mode 100644 index 000000000000..b8cdb8be7a4a --- /dev/null +++ b/tests/ui/async-await/async-gen-move-suggestion.stderr @@ -0,0 +1,47 @@ +error[E0373]: async gen block may outlive the current function, but it borrows `x`, which is owned by the current function + --> $DIR/async-gen-move-suggestion.rs:17:5 + | +LL | async gen { + | ^^^^^^^^^ may outlive borrowed value `x` +LL | x.clear(); + | - `x` is borrowed here + | +note: async gen block is returned here + --> $DIR/async-gen-move-suggestion.rs:17:5 + | +LL | / async gen { +LL | | x.clear(); +LL | | for x in 3..6 { yield x } +LL | | } + | |_____^ +help: to force the async gen block to take ownership of `x` (and any other referenced variables), use the `move` keyword + | +LL | async gen move { + | ++++ + +error[E0373]: async gen block may outlive the current function, but it borrows `x`, which is owned by the current function + --> $DIR/async-gen-move-suggestion.rs:27:5 + | +LL | / async // Just to check that whitespace characters are correctly handled +LL | | gen { + | |_______^ may outlive borrowed value `x` +LL | x.clear(); + | - `x` is borrowed here + | +note: async gen block is returned here + --> $DIR/async-gen-move-suggestion.rs:27:5 + | +LL | / async // Just to check that whitespace characters are correctly handled +LL | | gen { +LL | | x.clear(); +LL | | for x in 3..6 { yield x } +LL | | } + | |_____^ +help: to force the async gen block to take ownership of `x` (and any other referenced variables), use the `move` keyword + | +LL | gen move { + | ++++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0373`. diff --git a/tests/ui/async-await/drop-track-field-assign-nonsend.rs b/tests/ui/async-await/drop-track-field-assign-nonsend.rs index 7002836ee47f..2b93f9013767 100644 --- a/tests/ui/async-await/drop-track-field-assign-nonsend.rs +++ b/tests/ui/async-await/drop-track-field-assign-nonsend.rs @@ -40,5 +40,5 @@ fn main() { let agent = Agent { info_result: InfoResult { node: None } }; // FIXME: It would be nice for this to work. See #94067. assert_send(agent.handle()); - //~^ cannot be sent between threads safely + //~^ ERROR cannot be sent between threads safely } diff --git a/tests/ui/async-await/feature-async-for-loop.rs b/tests/ui/async-await/feature-async-for-loop.rs index 67817cbfa5f3..22d32907e0e7 100644 --- a/tests/ui/async-await/feature-async-for-loop.rs +++ b/tests/ui/async-await/feature-async-for-loop.rs @@ -11,7 +11,7 @@ fn f() { }; } -#[cfg(FALSE)] +#[cfg(false)] fn g() { let _ = async { for await _i in core::async_iter::from_iter(0..3) { diff --git a/tests/ui/async-await/field-assign-nonsend.rs b/tests/ui/async-await/field-assign-nonsend.rs index 7002836ee47f..2b93f9013767 100644 --- a/tests/ui/async-await/field-assign-nonsend.rs +++ b/tests/ui/async-await/field-assign-nonsend.rs @@ -40,5 +40,5 @@ fn main() { let agent = Agent { info_result: InfoResult { node: None } }; // FIXME: It would be nice for this to work. See #94067. assert_send(agent.handle()); - //~^ cannot be sent between threads safely + //~^ ERROR cannot be sent between threads safely } diff --git a/tests/ui/async-await/issue-60709.rs b/tests/ui/async-await/issue-60709.rs index 8634d6f7768b..a3f54d70316c 100644 --- a/tests/ui/async-await/issue-60709.rs +++ b/tests/ui/async-await/issue-60709.rs @@ -1,6 +1,7 @@ // This used to compile the future down to ud2, due to uninhabited types being // handled incorrectly in coroutines. -//@ compile-flags: -Copt-level=z -Cdebuginfo=2 --edition=2018 +//@ compile-flags: -Copt-level=z -Cdebuginfo=2 +//@ edition: 2018 //@ run-pass diff --git a/tests/ui/async-await/issue-70818.rs b/tests/ui/async-await/issue-70818.rs index 36295a84e7ad..bc181de8d925 100644 --- a/tests/ui/async-await/issue-70818.rs +++ b/tests/ui/async-await/issue-70818.rs @@ -2,7 +2,7 @@ use std::future::Future; fn foo(ty: T, ty1: U) -> impl Future + Send { - //~^ Error future cannot be sent between threads safely + //~^ ERROR future cannot be sent between threads safely async { (ty, ty1) } } diff --git a/tests/ui/async-await/issue-71137.rs b/tests/ui/async-await/issue-71137.rs index 551cf85047ca..6fbf17ccf0d0 100644 --- a/tests/ui/async-await/issue-71137.rs +++ b/tests/ui/async-await/issue-71137.rs @@ -19,5 +19,5 @@ async fn wrong_mutex() { } fn main() { - fake_spawn(wrong_mutex()); //~ Error future cannot be sent between threads safely + fake_spawn(wrong_mutex()); //~ ERROR future cannot be sent between threads safely } diff --git a/tests/ui/async-await/issues/issue-59972.rs b/tests/ui/async-await/issues/issue-59972.rs index c30477fcd30c..e64a856fab30 100644 --- a/tests/ui/async-await/issues/issue-59972.rs +++ b/tests/ui/async-await/issues/issue-59972.rs @@ -4,7 +4,8 @@ //@ run-pass -//@ compile-flags: --edition=2018 -Aunused +//@ compile-flags: -Aunused +//@ edition: 2018 pub enum Uninhabited { } diff --git a/tests/ui/async-await/no-unsafe-async.rs b/tests/ui/async-await/no-unsafe-async.rs index e58d878c3db0..cc7e89e16cb2 100644 --- a/tests/ui/async-await/no-unsafe-async.rs +++ b/tests/ui/async-await/no-unsafe-async.rs @@ -3,11 +3,11 @@ struct S; impl S { - #[cfg(FALSE)] + #[cfg(false)] unsafe async fn g() {} //~ ERROR expected one of `extern` or `fn`, found keyword `async` } -#[cfg(FALSE)] +#[cfg(false)] unsafe async fn f() {} //~ ERROR expected one of `extern` or `fn`, found keyword `async` fn main() {} diff --git a/tests/ui/async-await/pin-ergonomics/reborrow-once.stderr b/tests/ui/async-await/pin-ergonomics/reborrow-once.stderr index a1ea2b4a57a7..dc8e424ad2a4 100644 --- a/tests/ui/async-await/pin-ergonomics/reborrow-once.stderr +++ b/tests/ui/async-await/pin-ergonomics/reborrow-once.stderr @@ -1,4 +1,4 @@ -error[E0499]: cannot borrow `*x.__pointer` as mutable more than once at a time +error[E0499]: cannot borrow `*x.pointer` as mutable more than once at a time --> $DIR/reborrow-once.rs:12:14 | LL | twice(x, x); diff --git a/tests/ui/async-await/post-cleanup-phase-validation.rs b/tests/ui/async-await/post-cleanup-phase-validation.rs new file mode 100644 index 000000000000..a347e35c26db --- /dev/null +++ b/tests/ui/async-await/post-cleanup-phase-validation.rs @@ -0,0 +1,19 @@ +//@ compile-flags: -Zvalidate-mir +//@ edition: 2024 +//@ build-pass + +// Regression test that we don't ICE when encountering a transmute in a coroutine's +// drop shim body, which is conceptually in the Runtime phase but wasn't having the +// phase updated b/c the pass manager neither optimizes nor updates the phase for +// drop shim bodies. + +struct HasDrop; +impl Drop for HasDrop { + fn drop(&mut self) {} +} + +fn main() { + async { + vec![async { HasDrop }.await]; + }; +} diff --git a/tests/ui/async-await/suggest-missing-await.rs b/tests/ui/async-await/suggest-missing-await.rs index 0bd67cec335b..de0b2ce52b69 100644 --- a/tests/ui/async-await/suggest-missing-await.rs +++ b/tests/ui/async-await/suggest-missing-await.rs @@ -1,4 +1,5 @@ //@ edition:2018 +//@ dont-require-annotations: SUGGESTION fn take_u32(_x: u32) {} @@ -43,7 +44,7 @@ async fn suggest_await_on_previous_match_arms() { 0 => dummy(), //~ HELP consider `await`ing on the `Future` 1 => dummy(), 2 => dummy().await, - //~^ `match` arms have incompatible types [E0308] + //~^ ERROR `match` arms have incompatible types [E0308] }; } diff --git a/tests/ui/async-await/suggest-missing-await.stderr b/tests/ui/async-await/suggest-missing-await.stderr index f9db86ea40a9..9db7eb980eff 100644 --- a/tests/ui/async-await/suggest-missing-await.stderr +++ b/tests/ui/async-await/suggest-missing-await.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/suggest-missing-await.rs:12:14 + --> $DIR/suggest-missing-await.rs:13:14 | LL | take_u32(x) | -------- ^ expected `u32`, found future @@ -7,12 +7,12 @@ LL | take_u32(x) | arguments to this function are incorrect | note: calling an async function returns a future - --> $DIR/suggest-missing-await.rs:12:14 + --> $DIR/suggest-missing-await.rs:13:14 | LL | take_u32(x) | ^ note: function defined here - --> $DIR/suggest-missing-await.rs:3:4 + --> $DIR/suggest-missing-await.rs:4:4 | LL | fn take_u32(_x: u32) {} | ^^^^^^^^ ------- @@ -22,13 +22,13 @@ LL | take_u32(x.await) | ++++++ error[E0308]: mismatched types - --> $DIR/suggest-missing-await.rs:22:5 + --> $DIR/suggest-missing-await.rs:23:5 | LL | dummy() | ^^^^^^^ expected `()`, found future | note: calling an async function returns a future - --> $DIR/suggest-missing-await.rs:22:5 + --> $DIR/suggest-missing-await.rs:23:5 | LL | dummy() | ^^^^^^^ @@ -42,7 +42,7 @@ LL | dummy(); | + error[E0308]: `if` and `else` have incompatible types - --> $DIR/suggest-missing-await.rs:35:9 + --> $DIR/suggest-missing-await.rs:36:9 | LL | let _x = if true { | ______________- @@ -64,7 +64,7 @@ LL | dummy().await | ++++++ error[E0308]: `match` arms have incompatible types - --> $DIR/suggest-missing-await.rs:45:14 + --> $DIR/suggest-missing-await.rs:46:14 | LL | let _x = match 0usize { | ______________- @@ -87,7 +87,7 @@ LL ~ 1 => dummy().await, | error[E0308]: mismatched types - --> $DIR/suggest-missing-await.rs:53:9 + --> $DIR/suggest-missing-await.rs:54:9 | LL | let _x = match dummy() { | ------- this expression has type `impl Future` @@ -102,7 +102,7 @@ LL | let _x = match dummy().await { | ++++++ error[E0308]: mismatched types - --> $DIR/suggest-missing-await.rs:67:9 + --> $DIR/suggest-missing-await.rs:68:9 | LL | match dummy_result() { | -------------- this expression has type `impl Future>` @@ -118,7 +118,7 @@ LL | match dummy_result().await { | ++++++ error[E0308]: mismatched types - --> $DIR/suggest-missing-await.rs:69:9 + --> $DIR/suggest-missing-await.rs:70:9 | LL | match dummy_result() { | -------------- this expression has type `impl Future>` @@ -134,7 +134,7 @@ LL | match dummy_result().await { | ++++++ error[E0308]: mismatched types - --> $DIR/suggest-missing-await.rs:77:27 + --> $DIR/suggest-missing-await.rs:78:27 | LL | Some(do_async()).map(|()| {}); | ^^ diff --git a/tests/ui/attributes/check-builtin-attr-ice.rs b/tests/ui/attributes/check-builtin-attr-ice.rs index 9ef5890601f6..7745849acd0b 100644 --- a/tests/ui/attributes/check-builtin-attr-ice.rs +++ b/tests/ui/attributes/check-builtin-attr-ice.rs @@ -39,13 +39,17 @@ // Notably, `should_panic` is a `AttributeType::Normal` attribute that is checked separately. +#![deny(unused_attributes)] + struct Foo { #[should_panic::skip] //~^ ERROR failed to resolve + //~| ERROR `#[should_panic::skip]` only has an effect on functions pub field: u8, #[should_panic::a::b::c] //~^ ERROR failed to resolve + //~| ERROR `#[should_panic::a::b::c]` only has an effect on functions pub field2: u8, } diff --git a/tests/ui/attributes/check-builtin-attr-ice.stderr b/tests/ui/attributes/check-builtin-attr-ice.stderr index 06a4769b2b42..4f26f71efb7e 100644 --- a/tests/ui/attributes/check-builtin-attr-ice.stderr +++ b/tests/ui/attributes/check-builtin-attr-ice.stderr @@ -1,21 +1,39 @@ error[E0433]: failed to resolve: use of unresolved module or unlinked crate `should_panic` - --> $DIR/check-builtin-attr-ice.rs:43:7 + --> $DIR/check-builtin-attr-ice.rs:45:7 | LL | #[should_panic::skip] | ^^^^^^^^^^^^ use of unresolved module or unlinked crate `should_panic` error[E0433]: failed to resolve: use of unresolved module or unlinked crate `should_panic` - --> $DIR/check-builtin-attr-ice.rs:47:7 + --> $DIR/check-builtin-attr-ice.rs:50:7 | LL | #[should_panic::a::b::c] | ^^^^^^^^^^^^ use of unresolved module or unlinked crate `should_panic` error[E0433]: failed to resolve: use of unresolved module or unlinked crate `deny` - --> $DIR/check-builtin-attr-ice.rs:55:7 + --> $DIR/check-builtin-attr-ice.rs:59:7 | LL | #[deny::skip] | ^^^^ use of unresolved module or unlinked crate `deny` -error: aborting due to 3 previous errors +error: `#[should_panic::skip]` only has an effect on functions + --> $DIR/check-builtin-attr-ice.rs:45:5 + | +LL | #[should_panic::skip] + | ^^^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/check-builtin-attr-ice.rs:42:9 + | +LL | #![deny(unused_attributes)] + | ^^^^^^^^^^^^^^^^^ + +error: `#[should_panic::a::b::c]` only has an effect on functions + --> $DIR/check-builtin-attr-ice.rs:50:5 + | +LL | #[should_panic::a::b::c] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0433`. diff --git a/tests/ui/attributes/invalid_macro_export_argument.deny.stderr b/tests/ui/attributes/invalid_macro_export_argument.deny.stderr index 644acc27b58e..9d44bd162c7b 100644 --- a/tests/ui/attributes/invalid_macro_export_argument.deny.stderr +++ b/tests/ui/attributes/invalid_macro_export_argument.deny.stderr @@ -10,11 +10,17 @@ note: the lint level is defined here LL | #![cfg_attr(deny, deny(invalid_macro_export_arguments))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: `not_local_inner_macros` isn't a valid `#[macro_export]` argument +error: invalid `#[macro_export]` argument --> $DIR/invalid_macro_export_argument.rs:13:16 | LL | #[macro_export(not_local_inner_macros)] | ^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 2 previous errors +error: invalid `#[macro_export]` argument + --> $DIR/invalid_macro_export_argument.rs:33:16 + | +LL | #[macro_export("blah")] + | ^^^^^^ + +error: aborting due to 3 previous errors diff --git a/tests/ui/attributes/invalid_macro_export_argument.rs b/tests/ui/attributes/invalid_macro_export_argument.rs index 96f66991e041..c5fe39d062a4 100644 --- a/tests/ui/attributes/invalid_macro_export_argument.rs +++ b/tests/ui/attributes/invalid_macro_export_argument.rs @@ -11,7 +11,7 @@ macro_rules! a { } #[macro_export(not_local_inner_macros)] -//[deny]~^ ERROR `not_local_inner_macros` isn't a valid `#[macro_export]` argument +//[deny]~^ ERROR invalid `#[macro_export]` argument macro_rules! b { () => () } @@ -30,4 +30,10 @@ macro_rules! e { () => () } +#[macro_export("blah")] +//[deny]~^ ERROR invalid `#[macro_export]` argument +macro_rules! f { + () => () +} + fn main() {} diff --git a/tests/ui/attributes/issue-90873.rs b/tests/ui/attributes/issue-90873.rs index 53339ce7e28f..50336e04c888 100644 --- a/tests/ui/attributes/issue-90873.rs +++ b/tests/ui/attributes/issue-90873.rs @@ -1,7 +1,7 @@ #![u=||{static d=||1;}] -//~^ attribute value must be a literal -//~| cannot find attribute `u` in this scope -//~| missing type for `static` item +//~^ ERROR attribute value must be a literal +//~| ERROR cannot find attribute `u` in this scope +//~| ERROR missing type for `static` item #![a={impl std::ops::Neg for i8 {}}] //~^ ERROR attribute value must be a literal diff --git a/tests/ui/attributes/no-sanitize.rs b/tests/ui/attributes/no-sanitize.rs index 8c79866d5aa3..ddf909be63a8 100644 --- a/tests/ui/attributes/no-sanitize.rs +++ b/tests/ui/attributes/no-sanitize.rs @@ -38,3 +38,8 @@ fn valid() {} #[no_sanitize(address)] static VALID : i32 = 0; + +#[no_sanitize("address")] +//~^ ERROR `#[no_sanitize(...)]` should be applied to a function +//~| ERROR invalid argument for `no_sanitize` +static VALID2 : i32 = 0; diff --git a/tests/ui/attributes/no-sanitize.stderr b/tests/ui/attributes/no-sanitize.stderr index 9b0b76e3f4eb..8d5fbb109ead 100644 --- a/tests/ui/attributes/no-sanitize.stderr +++ b/tests/ui/attributes/no-sanitize.stderr @@ -59,5 +59,22 @@ LL | #[no_sanitize(address, memory)] LL | static INVALID : i32 = 0; | ------------------------- not a function -error: aborting due to 7 previous errors +error: `#[no_sanitize(...)]` should be applied to a function + --> $DIR/no-sanitize.rs:42:15 + | +LL | #[no_sanitize("address")] + | ^^^^^^^^^ +... +LL | static VALID2 : i32 = 0; + | ------------------------ not a function + +error: invalid argument for `no_sanitize` + --> $DIR/no-sanitize.rs:42:15 + | +LL | #[no_sanitize("address")] + | ^^^^^^^^^ + | + = note: expected one of: `address`, `cfi`, `hwaddress`, `kcfi`, `memory`, `memtag`, `shadow-call-stack`, or `thread` + +error: aborting due to 9 previous errors diff --git a/tests/ui/attributes/unsafe/proc-unsafe-attributes.rs b/tests/ui/attributes/unsafe/proc-unsafe-attributes.rs index eaf8706369a5..2f17d9620b41 100644 --- a/tests/ui/attributes/unsafe/proc-unsafe-attributes.rs +++ b/tests/ui/attributes/unsafe/proc-unsafe-attributes.rs @@ -30,6 +30,8 @@ pub fn e() {} //~| ERROR: expected identifier, found keyword `unsafe` //~| ERROR: malformed lint attribute input //~| ERROR: malformed lint attribute input +//~| ERROR: malformed lint attribute input +//~| ERROR: malformed lint attribute input pub fn f() {} fn main() {} diff --git a/tests/ui/attributes/unsafe/proc-unsafe-attributes.stderr b/tests/ui/attributes/unsafe/proc-unsafe-attributes.stderr index 9c5751c82e4c..25b83a26e170 100644 --- a/tests/ui/attributes/unsafe/proc-unsafe-attributes.stderr +++ b/tests/ui/attributes/unsafe/proc-unsafe-attributes.stderr @@ -114,6 +114,22 @@ LL | #[unsafe(allow(unsafe(dead_code)))] | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: aborting due to 15 previous errors +error[E0452]: malformed lint attribute input + --> $DIR/proc-unsafe-attributes.rs:26:16 + | +LL | #[unsafe(allow(unsafe(dead_code)))] + | ^^^^^^^^^^^^^^^^^ bad attribute argument + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0452]: malformed lint attribute input + --> $DIR/proc-unsafe-attributes.rs:26:16 + | +LL | #[unsafe(allow(unsafe(dead_code)))] + | ^^^^^^^^^^^^^^^^^ bad attribute argument + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 17 previous errors For more information about this error, try `rustc --explain E0452`. diff --git a/tests/ui/attributes/used_with_multi_args.rs b/tests/ui/attributes/used_with_multi_args.rs index 2e17fcfd7a49..d3109cc64442 100644 --- a/tests/ui/attributes/used_with_multi_args.rs +++ b/tests/ui/attributes/used_with_multi_args.rs @@ -1,6 +1,6 @@ #![feature(used_with_arg)] -#[used(compiler, linker)] //~ expected `used`, `used(compiler)` or `used(linker)` +#[used(compiler, linker)] //~ ERROR expected `used`, `used(compiler)` or `used(linker)` static mut USED_COMPILER_LINKER: [usize; 1] = [0]; fn main() {} diff --git a/tests/ui/attributes/z-crate-attr/cfg-false.rs b/tests/ui/attributes/z-crate-attr/cfg-false.rs index db37cfdd0863..5e5662c74385 100644 --- a/tests/ui/attributes/z-crate-attr/cfg-false.rs +++ b/tests/ui/attributes/z-crate-attr/cfg-false.rs @@ -1,5 +1,5 @@ -// Ensure that `-Z crate-attr=cfg(FALSE)` can comment out the whole crate -//@ compile-flags: --crate-type=lib -Zcrate-attr=cfg(FALSE) +// Ensure that `-Z crate-attr=cfg(false)` can comment out the whole crate +//@ compile-flags: --crate-type=lib -Zcrate-attr=cfg(false) //@ check-pass // NOTE: duplicate items are load-bearing diff --git a/tests/ui/attributes/z-crate-attr/garbage.stderr b/tests/ui/attributes/z-crate-attr/garbage.stderr index 082046e31f8c..12d18b0845fc 100644 --- a/tests/ui/attributes/z-crate-attr/garbage.stderr +++ b/tests/ui/attributes/z-crate-attr/garbage.stderr @@ -1,20 +1,20 @@ error: unknown start of token: ` - --> :1:1 + --> :1:4 | -LL | `%~@$# - | ^ +LL | #![`%~@$#] + | ^ | help: Unicode character '`' (Grave Accent) looks like ''' (Single Quote), but it is not | -LL - `%~@$# -LL + '%~@$# +LL - #![`%~@$#] +LL + #!['%~@$#] | error: expected identifier, found `%` - --> :1:2 + --> :1:5 | -LL | `%~@$# - | ^ expected identifier +LL | #![`%~@$#] + | ^ expected identifier error: aborting due to 2 previous errors diff --git a/tests/ui/attributes/z-crate-attr/injection.rs b/tests/ui/attributes/z-crate-attr/injection.rs index a91f9d2886e3..ee7a27c7490c 100644 --- a/tests/ui/attributes/z-crate-attr/injection.rs +++ b/tests/ui/attributes/z-crate-attr/injection.rs @@ -1,5 +1,3 @@ //@ compile-flags: '-Zcrate-attr=feature(yeet_expr)]fn main(){}#[inline' - -fn foo() {} - -//~? ERROR unexpected closing delimiter: `]` +//~? ERROR unexpected token +fn foo() {} //~ ERROR `main` function not found diff --git a/tests/ui/attributes/z-crate-attr/injection.stderr b/tests/ui/attributes/z-crate-attr/injection.stderr index 6fec98baf8df..899dad07e604 100644 --- a/tests/ui/attributes/z-crate-attr/injection.stderr +++ b/tests/ui/attributes/z-crate-attr/injection.stderr @@ -1,8 +1,15 @@ -error: unexpected closing delimiter: `]` - --> :1:19 +error: unexpected token: keyword `fn` + --> :1:23 | -LL | feature(yeet_expr)]fn main(){}#[inline - | ^ unexpected closing delimiter +LL | #![feature(yeet_expr)]fn main(){}#[inline] + | ^^ unexpected token after this -error: aborting due to 1 previous error +error[E0601]: `main` function not found in crate `injection` + --> $DIR/injection.rs:3:12 + | +LL | fn foo() {} + | ^ consider adding a `main` function to `$DIR/injection.rs` +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0601`. diff --git a/tests/ui/attributes/z-crate-attr/injection2.rs b/tests/ui/attributes/z-crate-attr/injection2.rs new file mode 100644 index 000000000000..67ae3d17f3e7 --- /dev/null +++ b/tests/ui/attributes/z-crate-attr/injection2.rs @@ -0,0 +1,3 @@ +//@ compile-flags: -Zcrate-attr=feature(yeet_expr)]#![allow(warnings) +//~? ERROR unexpected token +fn foo() {} //~ ERROR `main` function not found diff --git a/tests/ui/attributes/z-crate-attr/injection2.stderr b/tests/ui/attributes/z-crate-attr/injection2.stderr new file mode 100644 index 000000000000..51f54f900a19 --- /dev/null +++ b/tests/ui/attributes/z-crate-attr/injection2.stderr @@ -0,0 +1,15 @@ +error: unexpected token: `#` + --> :1:23 + | +LL | #![feature(yeet_expr)]#![allow(warnings)] + | ^ unexpected token after this + +error[E0601]: `main` function not found in crate `injection2` + --> $DIR/injection2.rs:3:12 + | +LL | fn foo() {} + | ^ consider adding a `main` function to `$DIR/injection2.rs` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0601`. diff --git a/tests/ui/attributes/z-crate-attr/inner-attr.stderr b/tests/ui/attributes/z-crate-attr/inner-attr.stderr index 06a063d310b6..1acb8c2e750b 100644 --- a/tests/ui/attributes/z-crate-attr/inner-attr.stderr +++ b/tests/ui/attributes/z-crate-attr/inner-attr.stderr @@ -1,8 +1,8 @@ error: expected identifier, found `#` - --> :1:1 + --> :1:4 | -LL | #![feature(foo)] - | ^ expected identifier +LL | #![#![feature(foo)]] + | ^ expected identifier error: aborting due to 1 previous error diff --git a/tests/ui/attributes/z-crate-attr/multiple.rs b/tests/ui/attributes/z-crate-attr/multiple.rs index 47d35d2c3fdf..8c60ea64feca 100644 --- a/tests/ui/attributes/z-crate-attr/multiple.rs +++ b/tests/ui/attributes/z-crate-attr/multiple.rs @@ -1,5 +1,3 @@ //@ compile-flags: -Zcrate-attr=feature(foo),feature(bar) - +//~? ERROR expected `]` fn main() {} - -//~? ERROR invalid crate attribute diff --git a/tests/ui/attributes/z-crate-attr/multiple.stderr b/tests/ui/attributes/z-crate-attr/multiple.stderr index 9f968a7e1346..b95c95dcd739 100644 --- a/tests/ui/attributes/z-crate-attr/multiple.stderr +++ b/tests/ui/attributes/z-crate-attr/multiple.stderr @@ -1,8 +1,8 @@ -error: invalid crate attribute - --> :1:1 +error: expected `]`, found `,` + --> :1:16 | -LL | feature(foo),feature(bar) - | ^^^^^^^^^^^^^ +LL | #![feature(foo),feature(bar)] + | ^ expected `]` error: aborting due to 1 previous error diff --git a/tests/ui/attributes/z-crate-attr/unbalanced-paren.rs b/tests/ui/attributes/z-crate-attr/unbalanced-paren.rs index 77d5d698f659..5ef0a75a3a87 100644 --- a/tests/ui/attributes/z-crate-attr/unbalanced-paren.rs +++ b/tests/ui/attributes/z-crate-attr/unbalanced-paren.rs @@ -1,6 +1,4 @@ // Show diagnostics for unbalanced parens. //@ compile-flags: -Zcrate-attr=( - +//~? ERROR mismatched closing delimiter fn main() {} - -//~? ERROR this file contains an unclosed delimiter diff --git a/tests/ui/attributes/z-crate-attr/unbalanced-paren.stderr b/tests/ui/attributes/z-crate-attr/unbalanced-paren.stderr index 47b1b764ba9a..f6545d1db8bc 100644 --- a/tests/ui/attributes/z-crate-attr/unbalanced-paren.stderr +++ b/tests/ui/attributes/z-crate-attr/unbalanced-paren.stderr @@ -1,10 +1,11 @@ -error: this file contains an unclosed delimiter - --> :1:2 +error: mismatched closing delimiter: `]` + --> :1:4 | -LL | ( - | -^ - | | - | unclosed delimiter +LL | #![(] + | -^^ mismatched closing delimiter + | || + | |unclosed delimiter + | closing delimiter possibly meant for this error: aborting due to 1 previous error diff --git a/tests/ui/augmented-assignments.rs b/tests/ui/augmented-assignments.rs index 440a4a7fd650..35ab2d454f7b 100644 --- a/tests/ui/augmented-assignments.rs +++ b/tests/ui/augmented-assignments.rs @@ -16,13 +16,13 @@ fn main() { += x; //~^ ERROR cannot move out of `x` because it is borrowed - //~| move out of `x` occurs here + //~| NOTE move out of `x` occurs here let y = Int(2); //~^ HELP consider changing this to be mutable //~| SUGGESTION mut y //~ ERROR cannot borrow `y` as mutable, as it is not declared as mutable - //~| cannot borrow as mutable + //~| NOTE cannot borrow as mutable += Int(1); } diff --git a/tests/ui/auto-traits/auto-trait-validation.fixed b/tests/ui/auto-traits/auto-trait-validation.fixed index f65952e00f58..8a445448c858 100644 --- a/tests/ui/auto-traits/auto-trait-validation.fixed +++ b/tests/ui/auto-traits/auto-trait-validation.fixed @@ -4,11 +4,11 @@ //@ run-rustfix auto trait Generic {} -//~^ auto traits cannot have generic parameters [E0567] +//~^ ERROR auto traits cannot have generic parameters [E0567] auto trait Bound {} -//~^ auto traits cannot have super traits or lifetime bounds [E0568] +//~^ ERROR auto traits cannot have super traits or lifetime bounds [E0568] auto trait LifetimeBound {} -//~^ auto traits cannot have super traits or lifetime bounds [E0568] +//~^ ERROR auto traits cannot have super traits or lifetime bounds [E0568] auto trait MyTrait { } -//~^ auto traits cannot have associated items [E0380] +//~^ ERROR auto traits cannot have associated items [E0380] fn main() {} diff --git a/tests/ui/auto-traits/auto-trait-validation.rs b/tests/ui/auto-traits/auto-trait-validation.rs index c83d7426e47c..b5e7505d86a2 100644 --- a/tests/ui/auto-traits/auto-trait-validation.rs +++ b/tests/ui/auto-traits/auto-trait-validation.rs @@ -4,11 +4,11 @@ //@ run-rustfix auto trait Generic {} -//~^ auto traits cannot have generic parameters [E0567] +//~^ ERROR auto traits cannot have generic parameters [E0567] auto trait Bound : Copy {} -//~^ auto traits cannot have super traits or lifetime bounds [E0568] +//~^ ERROR auto traits cannot have super traits or lifetime bounds [E0568] auto trait LifetimeBound : 'static {} -//~^ auto traits cannot have super traits or lifetime bounds [E0568] +//~^ ERROR auto traits cannot have super traits or lifetime bounds [E0568] auto trait MyTrait { fn foo() {} } -//~^ auto traits cannot have associated items [E0380] +//~^ ERROR auto traits cannot have associated items [E0380] fn main() {} diff --git a/tests/ui/auto-traits/pre-cfg.rs b/tests/ui/auto-traits/pre-cfg.rs index e806686f965c..4820a5353580 100644 --- a/tests/ui/auto-traits/pre-cfg.rs +++ b/tests/ui/auto-traits/pre-cfg.rs @@ -1,6 +1,6 @@ //@ check-pass -#[cfg(FALSE)] +#[cfg(false)] auto trait Foo {} //~^ WARN `auto` traits are unstable //~| WARN unstable syntax can change at any point in the future, causing a hard error! diff --git a/tests/ui/autodiff/autodiff_illegal.rs b/tests/ui/autodiff/autodiff_illegal.rs index 2f2cd8d93532..a916bd8b857b 100644 --- a/tests/ui/autodiff/autodiff_illegal.rs +++ b/tests/ui/autodiff/autodiff_illegal.rs @@ -63,7 +63,7 @@ fn dummy() { // Malformed, where args? #[autodiff] pub fn f7(x: f64) { - //~^ ERROR autodiff must be applied to function + //~^ ERROR autodiff requires at least a name and mode unimplemented!() } @@ -77,7 +77,7 @@ pub fn f8(x: f64) { // Invalid attribute syntax #[autodiff = ""] pub fn f9(x: f64) { - //~^ ERROR autodiff must be applied to function + //~^ ERROR autodiff requires at least a name and mode unimplemented!() } diff --git a/tests/ui/autodiff/autodiff_illegal.stderr b/tests/ui/autodiff/autodiff_illegal.stderr index 3752b27e7dd1..b119f61b8ae6 100644 --- a/tests/ui/autodiff/autodiff_illegal.stderr +++ b/tests/ui/autodiff/autodiff_illegal.stderr @@ -62,7 +62,7 @@ error: autodiff must be applied to function LL | let add_one_v2 = |x: u32| -> u32 { x + 1 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: autodiff must be applied to function +error: autodiff requires at least a name and mode --> $DIR/autodiff_illegal.rs:65:1 | LL | / pub fn f7(x: f64) { @@ -80,7 +80,7 @@ LL | | unimplemented!() LL | | } | |_^ -error: autodiff must be applied to function +error: autodiff requires at least a name and mode --> $DIR/autodiff_illegal.rs:79:1 | LL | / pub fn f9(x: f64) { diff --git a/tests/ui/bootstrap/self-test/a.rs b/tests/ui/bootstrap/self-test/a.rs index 64d2d6f11bbd..0818665af9f2 100644 --- a/tests/ui/bootstrap/self-test/a.rs +++ b/tests/ui/bootstrap/self-test/a.rs @@ -1,2 +1 @@ //! Not used by compiler, this is used by bootstrap cli self-test. -//@ ignore-test diff --git a/tests/ui/bootstrap/self-test/b.rs b/tests/ui/bootstrap/self-test/b.rs index 91f92f67910b..aeb4688830db 100644 --- a/tests/ui/bootstrap/self-test/b.rs +++ b/tests/ui/bootstrap/self-test/b.rs @@ -1,2 +1 @@ //! Not used by compiler, used by bootstrap cli self-test. -//@ ignore-test diff --git a/src/tools/miri/test-cargo-miri/test.stdout-empty.ref b/tests/ui/bootstrap/self-test/compiletest-ignore-dir similarity index 100% rename from src/tools/miri/test-cargo-miri/test.stdout-empty.ref rename to tests/ui/bootstrap/self-test/compiletest-ignore-dir diff --git a/tests/ui/borrowck/borrowck-fn-in-const-c.rs b/tests/ui/borrowck/borrowck-fn-in-const-c.rs index c638cd08bc9a..3cabedfe994c 100644 --- a/tests/ui/borrowck/borrowck-fn-in-const-c.rs +++ b/tests/ui/borrowck/borrowck-fn-in-const-c.rs @@ -14,7 +14,7 @@ impl Drop for DropString { const LOCAL_REF: fn() -> &'static str = { fn broken() -> &'static str { let local = DropString { inner: format!("Some local string") }; - return &local.inner; //~ borrow may still be in use when destructor runs + return &local.inner; //~ ERROR borrow may still be in use when destructor runs } broken }; diff --git a/tests/ui/borrowck/borrowck-vec-pattern-nesting.rs b/tests/ui/borrowck/borrowck-vec-pattern-nesting.rs index ec074d2cf1c9..400e5f010ecb 100644 --- a/tests/ui/borrowck/borrowck-vec-pattern-nesting.rs +++ b/tests/ui/borrowck/borrowck-vec-pattern-nesting.rs @@ -19,7 +19,7 @@ fn b() { let vec: &mut [Box] = &mut vec; match vec { &mut [ref _b @ ..] => { - //~^ `vec[_]` is borrowed here + //~^ NOTE `vec[_]` is borrowed here vec[0] = Box::new(4); //~ ERROR cannot assign //~^ NOTE `vec[_]` is assigned to here _b.use_ref(); diff --git a/tests/ui/borrowck/ice-mutability-error-slicing-121807.stderr b/tests/ui/borrowck/ice-mutability-error-slicing-121807.stderr index 3a6b8008fceb..02d5231f7134 100644 --- a/tests/ui/borrowck/ice-mutability-error-slicing-121807.stderr +++ b/tests/ui/borrowck/ice-mutability-error-slicing-121807.stderr @@ -23,12 +23,6 @@ LL | extern "C" fn read_dword(Self::Assoc<'_>) -> u16; = note: for more information, see issue #41686 = note: `#[warn(anonymous_parameters)]` on by default -error[E0220]: associated type `Assoc` not found for `Self` - --> $DIR/ice-mutability-error-slicing-121807.rs:7:36 - | -LL | extern "C" fn read_dword(Self::Assoc<'_>) -> u16; - | ^^^^^ associated type `Assoc` not found - error[E0185]: method `read_dword` has a `&self` declaration in the impl, but not in the trait --> $DIR/ice-mutability-error-slicing-121807.rs:17:5 | @@ -47,6 +41,12 @@ LL | extern "C" fn read_word(&mut self) -> u8; LL | impl MemoryUnit for ROM { | ^^^^^^^^^^^^^^^^^^^^^^^ missing `read_word` in implementation +error[E0220]: associated type `Assoc` not found for `Self` + --> $DIR/ice-mutability-error-slicing-121807.rs:7:36 + | +LL | extern "C" fn read_dword(Self::Assoc<'_>) -> u16; + | ^^^^^ associated type `Assoc` not found + error: aborting due to 4 previous errors; 1 warning emitted Some errors have detailed explanations: E0046, E0185, E0220, E0261. diff --git a/tests/ui/borrowck/issue-36082.fixed b/tests/ui/borrowck/issue-36082.fixed index 2209c56048e4..9ac89b016071 100644 --- a/tests/ui/borrowck/issue-36082.fixed +++ b/tests/ui/borrowck/issue-36082.fixed @@ -13,5 +13,5 @@ fn main() { //~| NOTE creates a temporary value 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 + //~^ NOTE borrow later used here } diff --git a/tests/ui/borrowck/issue-36082.rs b/tests/ui/borrowck/issue-36082.rs index da8b0068882b..f2f769ea1c3a 100644 --- a/tests/ui/borrowck/issue-36082.rs +++ b/tests/ui/borrowck/issue-36082.rs @@ -12,5 +12,5 @@ fn main() { //~| NOTE creates a temporary value 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 + //~^ NOTE borrow later used here } diff --git a/tests/ui/borrowck/move-error-snippets-ext.rs b/tests/ui/borrowck/move-error-snippets-ext.rs index f8103228cf81..6dd68438f179 100644 --- a/tests/ui/borrowck/move-error-snippets-ext.rs +++ b/tests/ui/borrowck/move-error-snippets-ext.rs @@ -1,4 +1,4 @@ -//@ ignore-test (auxiliary, used by other tests) +//@ ignore-auxiliary (used by `./move-error-snippets.rs`) macro_rules! aaa { ($c:ident) => {{ diff --git a/tests/ui/borrowck/trait-impl-argument-difference-ice.stderr b/tests/ui/borrowck/trait-impl-argument-difference-ice.stderr index 190ddeaa8f28..a656bb67bcba 100644 --- a/tests/ui/borrowck/trait-impl-argument-difference-ice.stderr +++ b/tests/ui/borrowck/trait-impl-argument-difference-ice.stderr @@ -8,12 +8,6 @@ LL | extern "C" fn read_dword(Self::Assoc<'_>) -> u16; = note: for more information, see issue #41686 = note: `#[warn(anonymous_parameters)]` on by default -error[E0220]: associated type `Assoc` not found for `Self` - --> $DIR/trait-impl-argument-difference-ice.rs:4:36 - | -LL | extern "C" fn read_dword(Self::Assoc<'_>) -> u16; - | ^^^^^ associated type `Assoc` not found - error[E0185]: method `read_dword` has a `&self` declaration in the impl, but not in the trait --> $DIR/trait-impl-argument-difference-ice.rs:14:5 | @@ -32,6 +26,12 @@ LL | extern "C" fn read_word(&mut self) -> u8; LL | impl MemoryUnit for ROM { | ^^^^^^^^^^^^^^^^^^^^^^^ missing `read_word` in implementation +error[E0220]: associated type `Assoc` not found for `Self` + --> $DIR/trait-impl-argument-difference-ice.rs:4:36 + | +LL | extern "C" fn read_dword(Self::Assoc<'_>) -> u16; + | ^^^^^ associated type `Assoc` not found + error[E0596]: cannot borrow `*self` as mutable, as it is behind a `&` reference --> $DIR/trait-impl-argument-difference-ice.rs:16:19 | diff --git a/tests/ui/borrowck/two-phase-multi-mut.rs b/tests/ui/borrowck/two-phase-multi-mut.rs index bb646d7caf1e..8ff924ccc2a8 100644 --- a/tests/ui/borrowck/two-phase-multi-mut.rs +++ b/tests/ui/borrowck/two-phase-multi-mut.rs @@ -9,6 +9,6 @@ impl Foo { fn main() { let mut foo = Foo { }; foo.method(&mut foo); - //~^ cannot borrow `foo` as mutable more than once at a time - //~^^ cannot borrow `foo` as mutable more than once at a time + //~^ ERROR cannot borrow `foo` as mutable more than once at a time + //~^^ ERROR cannot borrow `foo` as mutable more than once at a time } diff --git a/tests/ui/cast/cast-array-issue-138836.rs b/tests/ui/cast/cast-array-issue-138836.rs new file mode 100644 index 000000000000..3f8098e76fd2 --- /dev/null +++ b/tests/ui/cast/cast-array-issue-138836.rs @@ -0,0 +1,5 @@ +fn main() { + let a: [u8; 3] = [1,2,3]; + let b = &a; + let c = b as *const [u32; 3]; //~ ERROR casting `&[u8; 3]` as `*const [u32; 3]` is invalid +} diff --git a/tests/ui/cast/cast-array-issue-138836.stderr b/tests/ui/cast/cast-array-issue-138836.stderr new file mode 100644 index 000000000000..309474c29f93 --- /dev/null +++ b/tests/ui/cast/cast-array-issue-138836.stderr @@ -0,0 +1,9 @@ +error[E0606]: casting `&[u8; 3]` as `*const [u32; 3]` is invalid + --> $DIR/cast-array-issue-138836.rs:4:13 + | +LL | let c = b as *const [u32; 3]; + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0606`. diff --git a/tests/ui/cast/cast-as-bool.rs b/tests/ui/cast/cast-as-bool.rs index 511a02718fe2..fa9664e572c0 100644 --- a/tests/ui/cast/cast-as-bool.rs +++ b/tests/ui/cast/cast-as-bool.rs @@ -1,3 +1,5 @@ +//@ dont-require-annotations: SUGGESTION + fn main() { let u = 5 as bool; //~ ERROR cannot cast `i32` as `bool` //~| HELP compare with zero instead diff --git a/tests/ui/cast/cast-as-bool.stderr b/tests/ui/cast/cast-as-bool.stderr index b2c9ae5c6ad6..25377ebebe2b 100644 --- a/tests/ui/cast/cast-as-bool.stderr +++ b/tests/ui/cast/cast-as-bool.stderr @@ -1,5 +1,5 @@ error[E0054]: cannot cast `i32` as `bool` - --> $DIR/cast-as-bool.rs:2:13 + --> $DIR/cast-as-bool.rs:4:13 | LL | let u = 5 as bool; | ^^^^^^^^^ @@ -11,7 +11,7 @@ LL + let u = 5 != 0; | error[E0054]: cannot cast `i32` as `bool` - --> $DIR/cast-as-bool.rs:6:13 + --> $DIR/cast-as-bool.rs:8:13 | LL | let t = (1 + 2) as bool; | ^^^^^^^^^^^^^^^ @@ -23,7 +23,7 @@ LL + let t = (1 + 2) != 0; | error[E0054]: cannot cast `u32` as `bool` - --> $DIR/cast-as-bool.rs:10:13 + --> $DIR/cast-as-bool.rs:12:13 | LL | let _ = 5_u32 as bool; | ^^^^^^^^^^^^^ @@ -35,7 +35,7 @@ LL + let _ = 5_u32 != 0; | error[E0054]: cannot cast `f64` as `bool` - --> $DIR/cast-as-bool.rs:13:13 + --> $DIR/cast-as-bool.rs:15:13 | LL | let _ = 64.0_f64 as bool; | ^^^^^^^^^^^^^^^^ @@ -47,43 +47,43 @@ LL + let _ = 64.0_f64 != 0; | error[E0054]: cannot cast `IntEnum` as `bool` - --> $DIR/cast-as-bool.rs:24:13 + --> $DIR/cast-as-bool.rs:26:13 | LL | let _ = IntEnum::One as bool; | ^^^^^^^^^^^^^^^^^^^^ unsupported cast error[E0054]: cannot cast `fn(u8) -> String {uwu}` as `bool` - --> $DIR/cast-as-bool.rs:33:13 + --> $DIR/cast-as-bool.rs:35:13 | LL | let _ = uwu as bool; | ^^^^^^^^^^^ unsupported cast error[E0054]: cannot cast `unsafe fn() {owo}` as `bool` - --> $DIR/cast-as-bool.rs:35:13 + --> $DIR/cast-as-bool.rs:37:13 | LL | let _ = owo as bool; | ^^^^^^^^^^^ unsupported cast error[E0054]: cannot cast `fn(u8) -> String` as `bool` - --> $DIR/cast-as-bool.rs:38:13 + --> $DIR/cast-as-bool.rs:40:13 | LL | let _ = uwu as fn(u8) -> String as bool; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unsupported cast error[E0054]: cannot cast `char` as `bool` - --> $DIR/cast-as-bool.rs:40:13 + --> $DIR/cast-as-bool.rs:42:13 | LL | let _ = 'x' as bool; | ^^^^^^^^^^^ unsupported cast error[E0054]: cannot cast `*const ()` as `bool` - --> $DIR/cast-as-bool.rs:44:13 + --> $DIR/cast-as-bool.rs:46:13 | LL | let _ = ptr as bool; | ^^^^^^^^^^^ unsupported cast error[E0606]: casting `&'static str` as `bool` is invalid - --> $DIR/cast-as-bool.rs:46:13 + --> $DIR/cast-as-bool.rs:48:13 | LL | let v = "hello" as bool; | ^^^^^^^^^^^^^^^ diff --git a/tests/ui/cfg/auxiliary/cfg_false_lib.rs b/tests/ui/cfg/auxiliary/cfg_false_lib.rs index 6c2dbb44d2a4..d1768e69b0d5 100644 --- a/tests/ui/cfg/auxiliary/cfg_false_lib.rs +++ b/tests/ui/cfg/auxiliary/cfg_false_lib.rs @@ -1,4 +1,4 @@ -// `#![no_std]` on a fully unconfigured crate is respected if it's placed before `cfg(FALSE)`. +// `#![no_std]` on a fully unconfigured crate is respected if it's placed before `cfg(false)`. // This crate has no such attribute, therefore this crate does link to libstd. -#![cfg(FALSE)] +#![cfg(false)] diff --git a/tests/ui/cfg/auxiliary/cfg_false_lib_no_std_after.rs b/tests/ui/cfg/auxiliary/cfg_false_lib_no_std_after.rs index 3cfa6c510d02..cd3170f3fb33 100644 --- a/tests/ui/cfg/auxiliary/cfg_false_lib_no_std_after.rs +++ b/tests/ui/cfg/auxiliary/cfg_false_lib_no_std_after.rs @@ -1,5 +1,5 @@ -// `#![no_std]` on a fully unconfigured crate is respected if it's placed before `cfg(FALSE)`. +// `#![no_std]` on a fully unconfigured crate is respected if it's placed before `cfg(false)`. // Therefore this crate does link to libstd. -#![cfg(FALSE)] +#![cfg(false)] #![no_std] diff --git a/tests/ui/cfg/auxiliary/cfg_false_lib_no_std_before.rs b/tests/ui/cfg/auxiliary/cfg_false_lib_no_std_before.rs index a5c14be4c29d..ce4e1690996b 100644 --- a/tests/ui/cfg/auxiliary/cfg_false_lib_no_std_before.rs +++ b/tests/ui/cfg/auxiliary/cfg_false_lib_no_std_before.rs @@ -1,8 +1,8 @@ -// `#![no_std]` on a fully unconfigured crate is respected if it's placed before `cfg(FALSE)`. +// `#![no_std]` on a fully unconfigured crate is respected if it's placed before `cfg(false)`. // Therefore this crate doesn't link to libstd. //@ no-prefer-dynamic #![no_std] #![crate_type = "lib"] -#![cfg(FALSE)] +#![cfg(false)] diff --git a/tests/ui/cfg/auxiliary/cfged_out.rs b/tests/ui/cfg/auxiliary/cfged_out.rs index f6a9089cf29d..564280b24f59 100644 --- a/tests/ui/cfg/auxiliary/cfged_out.rs +++ b/tests/ui/cfg/auxiliary/cfged_out.rs @@ -1,8 +1,8 @@ pub mod inner { - #[cfg(FALSE)] + #[cfg(false)] pub fn uwu() {} - #[cfg(FALSE)] + #[cfg(false)] pub mod doesnt_exist { pub fn hello() {} } diff --git a/tests/ui/cfg/both-true-false.rs b/tests/ui/cfg/both-true-false.rs new file mode 100644 index 000000000000..5fca8f654ad8 --- /dev/null +++ b/tests/ui/cfg/both-true-false.rs @@ -0,0 +1,14 @@ +/// Test that placing a `cfg(true)` and `cfg(false)` on the same item result in +//. it being disabled.` + +#[cfg(false)] +#[cfg(true)] +fn foo() {} + +#[cfg(true)] +#[cfg(false)] +fn foo() {} + +fn main() { + foo(); //~ ERROR cannot find function `foo` in this scope +} diff --git a/tests/ui/cfg/both-true-false.stderr b/tests/ui/cfg/both-true-false.stderr new file mode 100644 index 000000000000..1526cc2b707b --- /dev/null +++ b/tests/ui/cfg/both-true-false.stderr @@ -0,0 +1,9 @@ +error[E0425]: cannot find function `foo` in this scope + --> $DIR/both-true-false.rs:13:5 + | +LL | foo(); + | ^^^ not found in this scope + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/cfg/cfg-false-feature.rs b/tests/ui/cfg/cfg-false-feature.rs index 716b18492c73..f66e4722440c 100644 --- a/tests/ui/cfg/cfg-false-feature.rs +++ b/tests/ui/cfg/cfg-false-feature.rs @@ -1,10 +1,10 @@ -// Features above `cfg(FALSE)` are in effect in a fully unconfigured crate (issue #104633). +// Features above `cfg(false)` are in effect in a fully unconfigured crate (issue #104633). //@ check-pass //@ compile-flags: --crate-type lib #![feature(decl_macro)] -#![cfg(FALSE)] +#![cfg(false)] #![feature(box_patterns)] macro mac() {} // OK diff --git a/tests/ui/cfg/cfg-macros-notfoo.rs b/tests/ui/cfg/cfg-macros-notfoo.rs index 9feb06be73e9..c25cf1c39bf5 100644 --- a/tests/ui/cfg/cfg-macros-notfoo.rs +++ b/tests/ui/cfg/cfg-macros-notfoo.rs @@ -3,7 +3,7 @@ // check that cfg correctly chooses between the macro impls (see also // cfg-macros-foo.rs) -#[cfg(FALSE)] +#[cfg(false)] #[macro_use] mod foo { macro_rules! bar { diff --git a/tests/ui/cfg/cfg-match-arm.rs b/tests/ui/cfg/cfg-match-arm.rs index f6cd52c475cf..cb5bf0ab0653 100644 --- a/tests/ui/cfg/cfg-match-arm.rs +++ b/tests/ui/cfg/cfg-match-arm.rs @@ -11,7 +11,7 @@ fn foo(f: Foo) { Foo::Bar => {}, #[cfg(not(FALSE))] Foo::Baz => {}, - #[cfg(FALSE)] + #[cfg(false)] Basdfwe => {} } } diff --git a/tests/ui/cfg/cfg-stmt-recovery.rs b/tests/ui/cfg/cfg-stmt-recovery.rs index 2e0839d2a153..f0f9a649165b 100644 --- a/tests/ui/cfg/cfg-stmt-recovery.rs +++ b/tests/ui/cfg/cfg-stmt-recovery.rs @@ -6,7 +6,7 @@ #[cfg_eval] fn main() { #[cfg_eval] - let _ = #[cfg(FALSE)] 0; + let _ = #[cfg(false)] 0; //~^ ERROR removing an expression is not supported in this position //~| ERROR expected expression, found `;` //~| ERROR removing an expression is not supported in this position diff --git a/tests/ui/cfg/cfg-stmt-recovery.stderr b/tests/ui/cfg/cfg-stmt-recovery.stderr index cb15e21fac69..e34da72afd93 100644 --- a/tests/ui/cfg/cfg-stmt-recovery.stderr +++ b/tests/ui/cfg/cfg-stmt-recovery.stderr @@ -1,19 +1,19 @@ error: removing an expression is not supported in this position --> $DIR/cfg-stmt-recovery.rs:9:13 | -LL | let _ = #[cfg(FALSE)] 0; +LL | let _ = #[cfg(false)] 0; | ^^^^^^^^^^^^^ error: expected expression, found `;` --> $DIR/cfg-stmt-recovery.rs:9:28 | -LL | let _ = #[cfg(FALSE)] 0; +LL | let _ = #[cfg(false)] 0; | ^ expected expression error: removing an expression is not supported in this position --> $DIR/cfg-stmt-recovery.rs:9:13 | -LL | let _ = #[cfg(FALSE)] 0; +LL | let _ = #[cfg(false)] 0; | ^^^^^^^^^^^^^ error: aborting due to 3 previous errors diff --git a/tests/ui/cfg/cfg_false_no_std-2.rs b/tests/ui/cfg/cfg_false_no_std-2.rs index 35e545aae34b..18b2c699fd7a 100644 --- a/tests/ui/cfg/cfg_false_no_std-2.rs +++ b/tests/ui/cfg/cfg_false_no_std-2.rs @@ -1,7 +1,6 @@ // Error, the linked empty library is `no_std` and doesn't provide a panic handler. -//@ compile-flags: --error-format=human -//@ error-pattern: `#[panic_handler]` function required, but not found +//@ dont-require-annotations: ERROR //@ dont-check-compiler-stderr //@ aux-build: cfg_false_lib_no_std_before.rs @@ -11,6 +10,7 @@ extern crate cfg_false_lib_no_std_before as _; fn main() {} -// FIXME: The second error is target-dependent. -//FIXME~? ERROR `#[panic_handler]` function required, but not found +//~? ERROR `#[panic_handler]` function required, but not found +// FIXME: This error is target-dependent, could be served by some "optional error" annotation +// instead of `dont-require-annotations`. //FIXME~? ERROR unwinding panics are not supported without std diff --git a/tests/ui/cfg/cfg_stmt_expr.rs b/tests/ui/cfg/cfg_stmt_expr.rs index 9245f6d97576..361b159a354f 100644 --- a/tests/ui/cfg/cfg_stmt_expr.rs +++ b/tests/ui/cfg/cfg_stmt_expr.rs @@ -7,47 +7,47 @@ fn main() { let a = 413; - #[cfg(FALSE)] + #[cfg(false)] let a = (); assert_eq!(a, 413); let mut b = 612; - #[cfg(FALSE)] + #[cfg(false)] { b = 1111; } assert_eq!(b, 612); - #[cfg(FALSE)] + #[cfg(false)] undefined_fn(); - #[cfg(FALSE)] + #[cfg(false)] undefined_macro!(); - #[cfg(FALSE)] + #[cfg(false)] undefined_macro![]; - #[cfg(FALSE)] + #[cfg(false)] undefined_macro!{}; // pretty printer bug... - // #[cfg(FALSE)] + // #[cfg(false)] // undefined_macro!{} - let () = (#[cfg(FALSE)] 341,); // Should this also work on parens? - let t = (1, #[cfg(FALSE)] 3, 4); + let () = (#[cfg(false)] 341,); // Should this also work on parens? + let t = (1, #[cfg(false)] 3, 4); assert_eq!(t, (1, 4)); let f = |_: u32, _: u32| (); - f(2, 1, #[cfg(FALSE)] 6); + f(2, 1, #[cfg(false)] 6); - let _: u32 = a.clone(#[cfg(FALSE)] undefined); + let _: u32 = a.clone(#[cfg(false)] undefined); - let _: [(); 0] = [#[cfg(FALSE)] 126]; - let t = [#[cfg(FALSE)] 1, 2, 6]; + let _: [(); 0] = [#[cfg(false)] 126]; + let t = [#[cfg(false)] 1, 2, 6]; assert_eq!(t, [2, 6]); { let r; - #[cfg(FALSE)] + #[cfg(false)] (r = 5); #[cfg(not(FALSE))] (r = 10); @@ -75,7 +75,7 @@ fn main() { 612 }); - assert_eq!((#[cfg(FALSE)] 1, #[cfg(not(FALSE))] 2), (2,)); + assert_eq!((#[cfg(false)] 1, #[cfg(not(FALSE))] 2), (2,)); assert_eq!(n, 612); // check that lints work diff --git a/tests/ui/cfg/cmdline-false.rs b/tests/ui/cfg/cmdline-false.rs new file mode 100644 index 000000000000..d4b7d3bbfdca --- /dev/null +++ b/tests/ui/cfg/cmdline-false.rs @@ -0,0 +1,9 @@ +/// Test that `--cfg false` doesn't cause `cfg(false)` to evaluate to `true` +//@ compile-flags: --cfg false + +#[cfg(false)] +fn foo() {} + +fn main() { + foo(); //~ ERROR cannot find function `foo` in this scope +} diff --git a/tests/ui/cfg/cmdline-false.stderr b/tests/ui/cfg/cmdline-false.stderr new file mode 100644 index 000000000000..5f57c754c403 --- /dev/null +++ b/tests/ui/cfg/cmdline-false.stderr @@ -0,0 +1,9 @@ +error[E0425]: cannot find function `foo` in this scope + --> $DIR/cmdline-false.rs:8:5 + | +LL | foo(); + | ^^^ not found in this scope + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/cfg/conditional-compile.rs b/tests/ui/cfg/conditional-compile.rs index dff280054d65..0739e877bfd1 100644 --- a/tests/ui/cfg/conditional-compile.rs +++ b/tests/ui/cfg/conditional-compile.rs @@ -6,16 +6,16 @@ // Crate use statements -#[cfg(FALSE)] +#[cfg(false)] use flippity; -#[cfg(FALSE)] +#[cfg(false)] static b: bool = false; static b: bool = true; mod rustrt { - #[cfg(FALSE)] + #[cfg(false)] extern "C" { // This symbol doesn't exist and would be a link error if this // module was codegened @@ -25,12 +25,12 @@ mod rustrt { extern "C" {} } -#[cfg(FALSE)] +#[cfg(false)] type t = isize; type t = bool; -#[cfg(FALSE)] +#[cfg(false)] enum tg { foo, } @@ -39,12 +39,12 @@ enum tg { bar, } -#[cfg(FALSE)] +#[cfg(false)] struct r { i: isize, } -#[cfg(FALSE)] +#[cfg(false)] fn r(i: isize) -> r { r { i: i } } @@ -57,7 +57,7 @@ fn r(i: isize) -> r { r { i: i } } -#[cfg(FALSE)] +#[cfg(false)] mod m { // This needs to parse but would fail in typeck. Since it's not in // the current config it should not be typechecked. @@ -69,7 +69,7 @@ mod m { mod m { // Submodules have slightly different code paths than the top-level // module, so let's make sure this jazz works here as well - #[cfg(FALSE)] + #[cfg(false)] pub fn f() {} pub fn f() {} @@ -77,7 +77,7 @@ mod m { // Since the FALSE configuration isn't defined main will just be // parsed, but nothing further will be done with it -#[cfg(FALSE)] +#[cfg(false)] pub fn main() { panic!() } @@ -93,14 +93,14 @@ pub fn main() { } fn test_in_fn_ctxt() { - #[cfg(FALSE)] + #[cfg(false)] fn f() { panic!() } fn f() {} f(); - #[cfg(FALSE)] + #[cfg(false)] static i: isize = 0; static i: isize = 1; assert_eq!(i, 1); @@ -109,7 +109,7 @@ fn test_in_fn_ctxt() { mod test_foreign_items { pub mod rustrt { extern "C" { - #[cfg(FALSE)] + #[cfg(false)] pub fn write() -> String; pub fn write() -> String; } @@ -117,7 +117,7 @@ mod test_foreign_items { } mod test_use_statements { - #[cfg(FALSE)] + #[cfg(false)] use flippity_foo; } @@ -127,24 +127,24 @@ mod test_methods { } impl Fooable for Foo { - #[cfg(FALSE)] + #[cfg(false)] fn what(&self) {} fn what(&self) {} - #[cfg(FALSE)] + #[cfg(false)] fn the(&self) {} fn the(&self) {} } trait Fooable { - #[cfg(FALSE)] + #[cfg(false)] fn what(&self); fn what(&self); - #[cfg(FALSE)] + #[cfg(false)] fn the(&self); fn the(&self); diff --git a/tests/ui/cfg/diagnostics-cross-crate.stderr b/tests/ui/cfg/diagnostics-cross-crate.stderr index 07ad4e3272d1..3e32a856e954 100644 --- a/tests/ui/cfg/diagnostics-cross-crate.stderr +++ b/tests/ui/cfg/diagnostics-cross-crate.stderr @@ -12,7 +12,7 @@ LL | pub mod doesnt_exist { note: the item is gated here --> $DIR/auxiliary/cfged_out.rs:5:5 | -LL | #[cfg(FALSE)] +LL | #[cfg(false)] | ^^^^^^^^^^^^^ error[E0425]: cannot find function `uwu` in crate `cfged_out` @@ -35,7 +35,7 @@ LL | pub fn uwu() {} note: the item is gated here --> $DIR/auxiliary/cfged_out.rs:2:5 | -LL | #[cfg(FALSE)] +LL | #[cfg(false)] | ^^^^^^^^^^^^^ error[E0425]: cannot find function `meow` in module `cfged_out::inner::right` diff --git a/tests/ui/cfg/diagnostics-reexport.rs b/tests/ui/cfg/diagnostics-reexport.rs index 9ae7d931fcb8..56fac5622382 100644 --- a/tests/ui/cfg/diagnostics-reexport.rs +++ b/tests/ui/cfg/diagnostics-reexport.rs @@ -1,10 +1,10 @@ pub mod inner { - #[cfg(FALSE)] + #[cfg(false)] mod gone { pub fn uwu() {} } - #[cfg(FALSE)] //~ NOTE the item is gated here + #[cfg(false)] //~ NOTE the item is gated here pub use super::uwu; //~^ NOTE found an item that was configured out } @@ -14,7 +14,7 @@ pub use a::x; //~| NOTE no `x` in `a` mod a { - #[cfg(FALSE)] //~ NOTE the item is gated here + #[cfg(false)] //~ NOTE the item is gated here pub fn x() {} //~^ NOTE found an item that was configured out } @@ -25,10 +25,10 @@ pub use b::{x, y}; //~| NOTE no `y` in `b` mod b { - #[cfg(FALSE)] //~ NOTE the item is gated here + #[cfg(false)] //~ NOTE the item is gated here pub fn x() {} //~^ NOTE found an item that was configured out - #[cfg(FALSE)] //~ NOTE the item is gated here + #[cfg(false)] //~ NOTE the item is gated here pub fn y() {} //~^ NOTE found an item that was configured out } diff --git a/tests/ui/cfg/diagnostics-reexport.stderr b/tests/ui/cfg/diagnostics-reexport.stderr index 737202fdf9ad..95dc4fac945e 100644 --- a/tests/ui/cfg/diagnostics-reexport.stderr +++ b/tests/ui/cfg/diagnostics-reexport.stderr @@ -12,7 +12,7 @@ LL | pub fn x() {} note: the item is gated here --> $DIR/diagnostics-reexport.rs:17:5 | -LL | #[cfg(FALSE)] +LL | #[cfg(false)] | ^^^^^^^^^^^^^ error[E0432]: unresolved imports `b::x`, `b::y` @@ -31,7 +31,7 @@ LL | pub fn x() {} note: the item is gated here --> $DIR/diagnostics-reexport.rs:28:5 | -LL | #[cfg(FALSE)] +LL | #[cfg(false)] | ^^^^^^^^^^^^^ note: found an item that was configured out --> $DIR/diagnostics-reexport.rs:32:12 @@ -41,7 +41,7 @@ LL | pub fn y() {} note: the item is gated here --> $DIR/diagnostics-reexport.rs:31:5 | -LL | #[cfg(FALSE)] +LL | #[cfg(false)] | ^^^^^^^^^^^^^ error[E0425]: cannot find function `uwu` in module `inner` @@ -58,7 +58,7 @@ LL | pub use super::uwu; note: the item is gated here --> $DIR/diagnostics-reexport.rs:7:5 | -LL | #[cfg(FALSE)] +LL | #[cfg(false)] | ^^^^^^^^^^^^^ error: aborting due to 3 previous errors diff --git a/tests/ui/cfg/diagnostics-same-crate.rs b/tests/ui/cfg/diagnostics-same-crate.rs index d6f8dd21a922..9153f20b2964 100644 --- a/tests/ui/cfg/diagnostics-same-crate.rs +++ b/tests/ui/cfg/diagnostics-same-crate.rs @@ -1,11 +1,11 @@ #![allow(unexpected_cfgs)] // since we want to recognize them as unexpected pub mod inner { - #[cfg(FALSE)] //~ NOTE the item is gated here + #[cfg(false)] //~ NOTE the item is gated here pub fn uwu() {} //~^ NOTE found an item that was configured out - #[cfg(FALSE)] //~ NOTE the item is gated here + #[cfg(false)] //~ NOTE the item is gated here //~^ NOTE the item is gated here //~| NOTE the item is gated here pub mod doesnt_exist { diff --git a/tests/ui/cfg/diagnostics-same-crate.stderr b/tests/ui/cfg/diagnostics-same-crate.stderr index dd0d10c6567e..75a1bc39a013 100644 --- a/tests/ui/cfg/diagnostics-same-crate.stderr +++ b/tests/ui/cfg/diagnostics-same-crate.stderr @@ -12,7 +12,7 @@ LL | pub mod doesnt_exist { note: the item is gated here --> $DIR/diagnostics-same-crate.rs:8:5 | -LL | #[cfg(FALSE)] +LL | #[cfg(false)] | ^^^^^^^^^^^^^ error[E0432]: unresolved import `super::inner::doesnt_exist` @@ -29,7 +29,7 @@ LL | pub mod doesnt_exist { note: the item is gated here --> $DIR/diagnostics-same-crate.rs:8:5 | -LL | #[cfg(FALSE)] +LL | #[cfg(false)] | ^^^^^^^^^^^^^ error[E0433]: failed to resolve: could not find `doesnt_exist` in `inner` @@ -46,7 +46,7 @@ LL | pub mod doesnt_exist { note: the item is gated here --> $DIR/diagnostics-same-crate.rs:8:5 | -LL | #[cfg(FALSE)] +LL | #[cfg(false)] | ^^^^^^^^^^^^^ error[E0425]: cannot find function `uwu` in module `inner` @@ -63,7 +63,7 @@ LL | pub fn uwu() {} note: the item is gated here --> $DIR/diagnostics-same-crate.rs:4:5 | -LL | #[cfg(FALSE)] +LL | #[cfg(false)] | ^^^^^^^^^^^^^ error[E0425]: cannot find function `meow` in module `inner::right` diff --git a/tests/ui/cfg/true-false.rs b/tests/ui/cfg/true-false.rs index 03d96fbafecb..0bd1cf427faf 100644 --- a/tests/ui/cfg/true-false.rs +++ b/tests/ui/cfg/true-false.rs @@ -1,7 +1,6 @@ //@ run-pass #![feature(link_cfg)] -#![feature(cfg_boolean_literals)] #[cfg(true)] fn foo() -> bool { diff --git a/tests/ui/check-cfg/allow-same-level.rs b/tests/ui/check-cfg/allow-same-level.rs index 8260b57bad4d..3f673cb88447 100644 --- a/tests/ui/check-cfg/allow-same-level.rs +++ b/tests/ui/check-cfg/allow-same-level.rs @@ -12,7 +12,7 @@ //@ compile-flags: --check-cfg=cfg() --cfg=unknown_but_active_cfg #[allow(unexpected_cfgs)] -#[cfg(FALSE)] +#[cfg(unknown_and_inactive_cfg)] //~^ WARNING unexpected `cfg` condition name fn bar() {} diff --git a/tests/ui/check-cfg/allow-same-level.stderr b/tests/ui/check-cfg/allow-same-level.stderr index a705cd4e5f01..cfff03048b53 100644 --- a/tests/ui/check-cfg/allow-same-level.stderr +++ b/tests/ui/check-cfg/allow-same-level.stderr @@ -1,10 +1,10 @@ -warning: unexpected `cfg` condition name: `FALSE` +warning: unexpected `cfg` condition name: `unknown_and_inactive_cfg` --> $DIR/allow-same-level.rs:15:7 | -LL | #[cfg(FALSE)] - | ^^^^^ +LL | #[cfg(unknown_and_inactive_cfg)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: to expect this configuration use `--check-cfg=cfg(FALSE)` + = help: to expect this configuration use `--check-cfg=cfg(unknown_and_inactive_cfg)` = note: see for more information about checking conditional configuration = note: `#[warn(unexpected_cfgs)]` on by default diff --git a/tests/ui/check-cfg/allow-top-level.rs b/tests/ui/check-cfg/allow-top-level.rs index cf94ed5da428..7ccecd2360e8 100644 --- a/tests/ui/check-cfg/allow-top-level.rs +++ b/tests/ui/check-cfg/allow-top-level.rs @@ -6,7 +6,7 @@ #![allow(unexpected_cfgs)] -#[cfg(FALSE)] +#[cfg(false)] fn bar() {} fn foo() { diff --git a/tests/ui/check-cfg/allow-upper-level.rs b/tests/ui/check-cfg/allow-upper-level.rs index 2e6664c30d39..657a4768f952 100644 --- a/tests/ui/check-cfg/allow-upper-level.rs +++ b/tests/ui/check-cfg/allow-upper-level.rs @@ -6,7 +6,7 @@ #[allow(unexpected_cfgs)] mod aa { - #[cfg(FALSE)] + #[cfg(false)] fn bar() {} } diff --git a/tests/ui/check-cfg/cargo-feature.rs b/tests/ui/check-cfg/cargo-feature.rs index a9380ddae1a9..a02b0437057f 100644 --- a/tests/ui/check-cfg/cargo-feature.rs +++ b/tests/ui/check-cfg/cargo-feature.rs @@ -10,7 +10,7 @@ //@ [none]compile-flags: --check-cfg=cfg(feature,values()) //@ [some]compile-flags: --check-cfg=cfg(feature,values("bitcode")) //@ [some]compile-flags: --check-cfg=cfg(CONFIG_NVME,values("y")) -//@ [none]error-pattern:Cargo.toml +//@ dont-require-annotations: HELP #[cfg(feature = "serde")] //~^ WARNING unexpected `cfg` condition value @@ -27,6 +27,7 @@ fn tokio() {} #[cfg(CONFIG_NVME = "m")] //[none]~^ WARNING unexpected `cfg` condition name //[some]~^^ WARNING unexpected `cfg` condition value +//[none]~| HELP Cargo.toml fn tokio() {} fn main() {} diff --git a/tests/ui/check-cfg/raw-keywords.edition2015.stderr b/tests/ui/check-cfg/raw-keywords.edition2015.stderr index 8ca33e088fc9..29c1a71c0b7a 100644 --- a/tests/ui/check-cfg/raw-keywords.edition2015.stderr +++ b/tests/ui/check-cfg/raw-keywords.edition2015.stderr @@ -1,5 +1,5 @@ warning: unexpected `cfg` condition name: `tru` - --> $DIR/raw-keywords.rs:14:7 + --> $DIR/raw-keywords.rs:15:7 | LL | #[cfg(tru)] | ^^^ help: there is a config with a similar name: `r#true` @@ -9,7 +9,7 @@ LL | #[cfg(tru)] = note: `#[warn(unexpected_cfgs)]` on by default warning: unexpected `cfg` condition name: `r#false` - --> $DIR/raw-keywords.rs:19:7 + --> $DIR/raw-keywords.rs:20:7 | LL | #[cfg(r#false)] | ^^^^^^^ @@ -19,7 +19,7 @@ LL | #[cfg(r#false)] = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition name: `await` - --> $DIR/raw-keywords.rs:27:29 + --> $DIR/raw-keywords.rs:28:29 | LL | #[cfg_attr(edition2015, cfg(await))] | ^^^^^ @@ -28,7 +28,7 @@ LL | #[cfg_attr(edition2015, cfg(await))] = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition name: `raw` - --> $DIR/raw-keywords.rs:33:7 + --> $DIR/raw-keywords.rs:34:7 | LL | #[cfg(r#raw)] | ^^^^^ diff --git a/tests/ui/check-cfg/raw-keywords.edition2021.stderr b/tests/ui/check-cfg/raw-keywords.edition2021.stderr index cce55720bdd1..cc3702685fd2 100644 --- a/tests/ui/check-cfg/raw-keywords.edition2021.stderr +++ b/tests/ui/check-cfg/raw-keywords.edition2021.stderr @@ -1,5 +1,5 @@ warning: unexpected `cfg` condition name: `tru` - --> $DIR/raw-keywords.rs:14:7 + --> $DIR/raw-keywords.rs:15:7 | LL | #[cfg(tru)] | ^^^ help: there is a config with a similar name: `r#true` @@ -9,7 +9,7 @@ LL | #[cfg(tru)] = note: `#[warn(unexpected_cfgs)]` on by default warning: unexpected `cfg` condition name: `r#false` - --> $DIR/raw-keywords.rs:19:7 + --> $DIR/raw-keywords.rs:20:7 | LL | #[cfg(r#false)] | ^^^^^^^ @@ -19,7 +19,7 @@ LL | #[cfg(r#false)] = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition name: `r#await` - --> $DIR/raw-keywords.rs:28:29 + --> $DIR/raw-keywords.rs:29:29 | LL | #[cfg_attr(edition2021, cfg(r#await))] | ^^^^^^^ @@ -28,7 +28,7 @@ LL | #[cfg_attr(edition2021, cfg(r#await))] = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition name: `raw` - --> $DIR/raw-keywords.rs:33:7 + --> $DIR/raw-keywords.rs:34:7 | LL | #[cfg(r#raw)] | ^^^^^ diff --git a/tests/ui/check-cfg/raw-keywords.rs b/tests/ui/check-cfg/raw-keywords.rs index 5de13240d7ed..b82eb5a64e9a 100644 --- a/tests/ui/check-cfg/raw-keywords.rs +++ b/tests/ui/check-cfg/raw-keywords.rs @@ -6,7 +6,8 @@ //@ compile-flags: --cfg=true --cfg=async --check-cfg=cfg(r#true,r#async,edition2015,edition2021) // //@ revisions: edition2015 edition2021 -//@ [edition2021] compile-flags: --edition 2021 +//@ [edition2015] edition: 2015 +//@ [edition2021] edition: 2021 #[cfg(r#true)] fn foo() {} diff --git a/tests/ui/check-cfg/target_feature.stderr b/tests/ui/check-cfg/target_feature.stderr index aa5fd09c0c7b..4f7b8345e86a 100644 --- a/tests/ui/check-cfg/target_feature.stderr +++ b/tests/ui/check-cfg/target_feature.stderr @@ -49,6 +49,7 @@ LL | cfg!(target_feature = "_UNEXPECTED_VALUE"); `avxvnni` `avxvnniint16` `avxvnniint8` +`b` `backchain` `bf16` `bmi1` @@ -318,17 +319,25 @@ LL | cfg!(target_feature = "_UNEXPECTED_VALUE"); `zbkc` `zbkx` `zbs` +`zca` +`zcb` +`zcmop` `zdinx` +`zfa` `zfh` `zfhmin` `zfinx` `zhinx` `zhinxmin` +`zicboz` `zicntr` +`zicond` `zicsr` `zifencei` +`zihintntl` `zihintpause` `zihpm` +`zimop` `zk` `zkn` `zknd` @@ -339,6 +348,7 @@ LL | cfg!(target_feature = "_UNEXPECTED_VALUE"); `zksed` `zksh` `zkt` +`ztso` `zvbb` `zvbc` `zve32f` diff --git a/tests/ui/check-cfg/well-known-values.stderr b/tests/ui/check-cfg/well-known-values.stderr index 4636b6945d06..7cda6c2eaa52 100644 --- a/tests/ui/check-cfg/well-known-values.stderr +++ b/tests/ui/check-cfg/well-known-values.stderr @@ -201,7 +201,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` LL | target_os = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_os` are: `aix`, `amdhsa`, `android`, `cuda`, `cygwin`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `macos`, `netbsd`, `none`, `nto`, `nuttx`, `openbsd`, `psp`, `psx`, `redox`, `rtems`, `solaris`, `solid_asp3`, `teeos`, `trusty`, `tvos`, `uefi`, `unknown`, `visionos`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`, and `zkvm` + = note: expected values for `target_os` are: `aix`, `amdhsa`, `android`, `cuda`, `cygwin`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `lynxos178`, `macos`, `netbsd`, `none`, `nto`, `nuttx`, `openbsd`, `psp`, `psx`, `redox`, `rtems`, `solaris`, `solid_asp3`, `teeos`, `trusty`, `tvos`, `uefi`, `unknown`, `visionos`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`, and `zkvm` = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` @@ -274,7 +274,7 @@ LL | #[cfg(target_os = "linuz")] // testing that we suggest `linux` | | | help: there is a expected value with a similar name: `"linux"` | - = note: expected values for `target_os` are: `aix`, `amdhsa`, `android`, `cuda`, `cygwin`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `macos`, `netbsd`, `none`, `nto`, `nuttx`, `openbsd`, `psp`, `psx`, `redox`, `rtems`, `solaris`, `solid_asp3`, `teeos`, `trusty`, `tvos`, `uefi`, `unknown`, `visionos`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`, and `zkvm` + = note: expected values for `target_os` are: `aix`, `amdhsa`, `android`, `cuda`, `cygwin`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `lynxos178`, `macos`, `netbsd`, `none`, `nto`, `nuttx`, `openbsd`, `psp`, `psx`, `redox`, `rtems`, `solaris`, `solid_asp3`, `teeos`, `trusty`, `tvos`, `uefi`, `unknown`, `visionos`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`, and `zkvm` = note: see for more information about checking conditional configuration warning: 28 warnings emitted diff --git a/tests/ui/closures/2229_closure_analysis/by_value.rs b/tests/ui/closures/2229_closure_analysis/by_value.rs index 2c9202fd6172..605b8ea35e51 100644 --- a/tests/ui/closures/2229_closure_analysis/by_value.rs +++ b/tests/ui/closures/2229_closure_analysis/by_value.rs @@ -20,8 +20,8 @@ fn big_box() { //~| NOTE: see issue #15701 //~| NOTE: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date || { - //~^ First Pass analysis includes: - //~| Min Capture analysis includes: + //~^ ERROR First Pass analysis includes: + //~| ERROR Min Capture analysis includes: let p = t.0.0; //~^ NOTE: Capturing t[(0, 0),Deref,(0, 0)] -> ByValue //~| NOTE: Min Capture t[(0, 0)] -> ByValue diff --git a/tests/ui/closures/2229_closure_analysis/capture-analysis-1.rs b/tests/ui/closures/2229_closure_analysis/capture-analysis-1.rs index 0c42e66a2faf..3eb5cef30056 100644 --- a/tests/ui/closures/2229_closure_analysis/capture-analysis-1.rs +++ b/tests/ui/closures/2229_closure_analysis/capture-analysis-1.rs @@ -17,8 +17,8 @@ fn main() { //~| NOTE: see issue #15701 //~| NOTE: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date || { - //~^ First Pass analysis includes: - //~| Min Capture analysis includes: + //~^ ERROR First Pass analysis includes: + //~| ERROR Min Capture analysis includes: println!("{:?}", p); //~^ NOTE: Capturing p[] -> Immutable //~| NOTE: Min Capture p[] -> Immutable diff --git a/tests/ui/closures/2229_closure_analysis/capture-analysis-2.rs b/tests/ui/closures/2229_closure_analysis/capture-analysis-2.rs index adb618d1771e..e6cda8248093 100644 --- a/tests/ui/closures/2229_closure_analysis/capture-analysis-2.rs +++ b/tests/ui/closures/2229_closure_analysis/capture-analysis-2.rs @@ -16,8 +16,8 @@ fn main() { //~| NOTE: see issue #15701 //~| NOTE: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date || { - //~^ First Pass analysis includes: - //~| Min Capture analysis includes: + //~^ ERROR First Pass analysis includes: + //~| ERROR Min Capture analysis includes: let _x = p.x; //~^ NOTE: Capturing p[(0, 0)] -> ByValue //~| NOTE: p[] captured as ByValue here diff --git a/tests/ui/closures/2229_closure_analysis/capture-analysis-3.rs b/tests/ui/closures/2229_closure_analysis/capture-analysis-3.rs index 0a21eaaaa121..b25b613b61c0 100644 --- a/tests/ui/closures/2229_closure_analysis/capture-analysis-3.rs +++ b/tests/ui/closures/2229_closure_analysis/capture-analysis-3.rs @@ -21,8 +21,8 @@ fn main() { //~| NOTE: see issue #15701 //~| NOTE: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date || { - //~^ First Pass analysis includes: - //~| Min Capture analysis includes: + //~^ ERROR First Pass analysis includes: + //~| ERROR Min Capture analysis includes: let _x = a.b.c; //~^ NOTE: Capturing a[(0, 0),(0, 0)] -> ByValue //~| NOTE: a[(0, 0)] captured as ByValue here diff --git a/tests/ui/closures/2229_closure_analysis/capture-analysis-4.rs b/tests/ui/closures/2229_closure_analysis/capture-analysis-4.rs index 790dad0710bc..355e36c1463b 100644 --- a/tests/ui/closures/2229_closure_analysis/capture-analysis-4.rs +++ b/tests/ui/closures/2229_closure_analysis/capture-analysis-4.rs @@ -21,8 +21,8 @@ fn main() { //~| NOTE: see issue #15701 //~| NOTE: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date || { - //~^ First Pass analysis includes: - //~| Min Capture analysis includes: + //~^ ERROR First Pass analysis includes: + //~| ERROR Min Capture analysis includes: let _x = a.b; //~^ NOTE: Capturing a[(0, 0)] -> ByValue //~| NOTE: Min Capture a[(0, 0)] -> ByValue diff --git a/tests/ui/closures/2229_closure_analysis/capture-disjoint-field-struct.rs b/tests/ui/closures/2229_closure_analysis/capture-disjoint-field-struct.rs index af12e0b259d9..52f0dcba6bee 100644 --- a/tests/ui/closures/2229_closure_analysis/capture-disjoint-field-struct.rs +++ b/tests/ui/closures/2229_closure_analysis/capture-disjoint-field-struct.rs @@ -15,8 +15,8 @@ fn main() { //~| NOTE: see issue #15701 //~| NOTE: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date || { - //~^ First Pass analysis includes: - //~| Min Capture analysis includes: + //~^ ERROR First Pass analysis includes: + //~| ERROR Min Capture analysis includes: println!("{}", p.x); //~^ NOTE: Capturing p[(0, 0)] -> Immutable //~| NOTE: Min Capture p[(0, 0)] -> Immutable diff --git a/tests/ui/closures/2229_closure_analysis/capture-disjoint-field-tuple.rs b/tests/ui/closures/2229_closure_analysis/capture-disjoint-field-tuple.rs index ccd260492643..bac79ad2860f 100644 --- a/tests/ui/closures/2229_closure_analysis/capture-disjoint-field-tuple.rs +++ b/tests/ui/closures/2229_closure_analysis/capture-disjoint-field-tuple.rs @@ -10,8 +10,8 @@ fn main() { //~| NOTE: see issue #15701 //~| NOTE: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date || { - //~^ First Pass analysis includes: - //~| Min Capture analysis includes: + //~^ ERROR First Pass analysis includes: + //~| ERROR Min Capture analysis includes: println!("{}", t.0); //~^ NOTE: Capturing t[(0, 0)] -> Immutable //~| NOTE: Min Capture t[(0, 0)] -> Immutable diff --git a/tests/ui/closures/2229_closure_analysis/capture-enums.rs b/tests/ui/closures/2229_closure_analysis/capture-enums.rs index b1e21bd0f8d6..d9c06a68c95b 100644 --- a/tests/ui/closures/2229_closure_analysis/capture-enums.rs +++ b/tests/ui/closures/2229_closure_analysis/capture-enums.rs @@ -18,8 +18,8 @@ fn multi_variant_enum() { //~| NOTE: see issue #15701 //~| NOTE: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date || { - //~^ First Pass analysis includes: - //~| Min Capture analysis includes: + //~^ ERROR First Pass analysis includes: + //~| ERROR Min Capture analysis includes: if let Info::Point(_, _, str) = point { //~^ NOTE: Capturing point[] -> Immutable //~| NOTE: Capturing point[(2, 0)] -> ByValue @@ -50,8 +50,8 @@ fn single_variant_enum() { //~| NOTE: see issue #15701 //~| NOTE: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date || { - //~^ First Pass analysis includes: - //~| Min Capture analysis includes: + //~^ ERROR First Pass analysis includes: + //~| ERROR Min Capture analysis includes: let SingleVariant::Point(_, _, str) = point; //~^ NOTE: Capturing point[(2, 0)] -> ByValue //~| NOTE: Min Capture point[(2, 0)] -> ByValue diff --git a/tests/ui/closures/2229_closure_analysis/diagnostics/union.rs b/tests/ui/closures/2229_closure_analysis/diagnostics/union.rs index 647005bc1c97..c036712381ce 100644 --- a/tests/ui/closures/2229_closure_analysis/diagnostics/union.rs +++ b/tests/ui/closures/2229_closure_analysis/diagnostics/union.rs @@ -11,15 +11,15 @@ union A { fn main() { let mut a = A { y: 1 }; let mut c = || { - //~^ `a.y` is borrowed here + //~^ NOTE `a.y` is borrowed here let _ = unsafe { &a.y }; let _ = &mut a; - //~^ borrow occurs due to use in closure + //~^ NOTE borrow occurs due to use in closure let _ = unsafe { &mut a.y }; }; a.y = 1; - //~^ cannot assign to `a.y` because it is borrowed [E0506] - //~| `a.y` is assigned to here + //~^ ERROR cannot assign to `a.y` because it is borrowed [E0506] + //~| NOTE `a.y` is assigned to here c(); - //~^ borrow later used here + //~^ NOTE borrow later used here } diff --git a/tests/ui/closures/2229_closure_analysis/issue-89606.rs b/tests/ui/closures/2229_closure_analysis/issue-89606.rs index 8c88a4b82261..5494686356d5 100644 --- a/tests/ui/closures/2229_closure_analysis/issue-89606.rs +++ b/tests/ui/closures/2229_closure_analysis/issue-89606.rs @@ -2,8 +2,8 @@ // //@ check-pass //@ revisions: twenty_eighteen twenty_twentyone -//@ [twenty_eighteen]compile-flags: --edition 2018 -//@ [twenty_twentyone]compile-flags: --edition 2021 +//@ [twenty_eighteen] edition: 2018 +//@ [twenty_twentyone] edition: 2021 struct S<'a>(Option<&'a mut i32>); diff --git a/tests/ui/closures/2229_closure_analysis/match/patterns-capture-analysis.rs b/tests/ui/closures/2229_closure_analysis/match/patterns-capture-analysis.rs index 9c7b70457d98..40330af4088c 100644 --- a/tests/ui/closures/2229_closure_analysis/match/patterns-capture-analysis.rs +++ b/tests/ui/closures/2229_closure_analysis/match/patterns-capture-analysis.rs @@ -10,8 +10,8 @@ fn test_1_should_capture() { let variant = Some(2229); let c = #[rustc_capture_analysis] || { - //~^ First Pass analysis includes: - //~| Min Capture analysis includes: + //~^ ERROR First Pass analysis includes: + //~| ERROR Min Capture analysis includes: match variant { //~^ NOTE: Capturing variant[] -> Immutable //~| NOTE: Min Capture variant[] -> Immutable @@ -28,7 +28,7 @@ fn test_2_should_not_capture() { let variant = Some(2229); let c = #[rustc_capture_analysis] || { - //~^ First Pass analysis includes: + //~^ ERROR First Pass analysis includes: match variant { _ => {} } @@ -47,7 +47,7 @@ fn test_3_should_not_capture_single_variant() { let variant = SingleVariant::Points(1); let c = #[rustc_capture_analysis] || { - //~^ First Pass analysis includes: + //~^ ERROR First Pass analysis includes: match variant { SingleVariant::Points(_) => {} } @@ -61,8 +61,8 @@ fn test_6_should_capture_single_variant() { let variant = SingleVariant::Points(1); let c = #[rustc_capture_analysis] || { - //~^ First Pass analysis includes: - //~| Min Capture analysis includes: + //~^ ERROR First Pass analysis includes: + //~| ERROR Min Capture analysis includes: match variant { //~^ NOTE: Capturing variant[] -> Immutable //~| NOTE: Capturing variant[(0, 0)] -> Immutable @@ -81,7 +81,7 @@ fn test_4_should_not_capture_array() { let array: [i32; 3] = [0; 3]; let c = #[rustc_capture_analysis] || { - //~^ First Pass analysis includes: + //~^ ERROR First Pass analysis includes: match array { [_,_,_] => {} } @@ -93,7 +93,7 @@ fn test_4_should_not_capture_array() { let array: &[i32; 3] = &[0; 3]; let c = #[rustc_capture_analysis] || { - //~^ First Pass analysis includes: + //~^ ERROR First Pass analysis includes: match array { [_, _, _] => {} } @@ -106,7 +106,7 @@ fn test_4_should_not_capture_array() { let f = &Foo(&[10; 3]); let c = #[rustc_capture_analysis] || { - //~^ First Pass analysis includes: + //~^ ERROR First Pass analysis includes: match f { Foo([_, _, _]) => () } @@ -128,8 +128,8 @@ fn test_5_should_capture_multi_variant() { let variant = MVariant::A; let c = #[rustc_capture_analysis] || { - //~^ First Pass analysis includes: - //~| Min Capture analysis includes: + //~^ ERROR First Pass analysis includes: + //~| ERROR Min Capture analysis includes: match variant { //~^ NOTE: Capturing variant[] -> Immutable //~| NOTE: Min Capture variant[] -> Immutable @@ -146,8 +146,8 @@ fn test_7_should_capture_slice_len() { let slice: &[i32] = &[1, 2, 3]; let c = #[rustc_capture_analysis] || { - //~^ First Pass analysis includes: - //~| Min Capture analysis includes: + //~^ ERROR First Pass analysis includes: + //~| ERROR Min Capture analysis includes: match slice { //~^ NOTE: Capturing slice[] -> Immutable //~| NOTE: Min Capture slice[] -> Immutable @@ -158,8 +158,8 @@ fn test_7_should_capture_slice_len() { c(); let c = #[rustc_capture_analysis] || { - //~^ First Pass analysis includes: - //~| Min Capture analysis includes: + //~^ ERROR First Pass analysis includes: + //~| ERROR Min Capture analysis includes: match slice { //~^ NOTE: Capturing slice[] -> Immutable //~| NOTE: Min Capture slice[] -> Immutable @@ -170,8 +170,8 @@ fn test_7_should_capture_slice_len() { c(); let c = #[rustc_capture_analysis] || { - //~^ First Pass analysis includes: - //~| Min Capture analysis includes: + //~^ ERROR First Pass analysis includes: + //~| ERROR Min Capture analysis includes: match slice { //~^ NOTE: Capturing slice[] -> Immutable //~| NOTE: Min Capture slice[] -> Immutable @@ -187,7 +187,7 @@ fn test_8_capture_slice_wild() { let slice: &[i32] = &[1, 2, 3]; let c = #[rustc_capture_analysis] || { - //~^ First Pass analysis includes: + //~^ ERROR First Pass analysis includes: match slice { [..] => {}, _ => {} diff --git a/tests/ui/closures/2229_closure_analysis/move_closure.rs b/tests/ui/closures/2229_closure_analysis/move_closure.rs index b6690d060118..c681559f6190 100644 --- a/tests/ui/closures/2229_closure_analysis/move_closure.rs +++ b/tests/ui/closures/2229_closure_analysis/move_closure.rs @@ -181,9 +181,9 @@ fn box_mut_1() { //~^ ERROR: attributes on expressions are experimental //~| NOTE: see issue #15701 //~| NOTE: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - //~| First Pass analysis includes: + //~| ERROR First Pass analysis includes: //~| NOTE: Capturing box_p_foo[Deref,Deref,(0, 0)] -> Mutable - //~| Min Capture analysis includes: + //~| ERROR Min Capture analysis includes: //~| NOTE: Min Capture box_p_foo[] -> ByValue } @@ -199,9 +199,9 @@ fn box_mut_2() { //~^ ERROR: attributes on expressions are experimental //~| NOTE: see issue #15701 //~| NOTE: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - //~| First Pass analysis includes: + //~| ERROR First Pass analysis includes: //~| NOTE: Capturing p_foo[Deref,Deref,(0, 0)] -> Mutable - //~| Min Capture analysis includes: + //~| ERROR Min Capture analysis includes: //~| NOTE: Min Capture p_foo[] -> ByValue } @@ -213,9 +213,9 @@ fn returned_closure_owns_copy_type_data() -> impl Fn() -> i32 { //~^ ERROR: attributes on expressions are experimental //~| NOTE: see issue #15701 //~| NOTE: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - //~| First Pass analysis includes: + //~| ERROR First Pass analysis includes: //~| NOTE: Capturing x[] -> Immutable - //~| Min Capture analysis includes: + //~| ERROR Min Capture analysis includes: //~| NOTE: Min Capture x[] -> ByValue c diff --git a/tests/ui/closures/2229_closure_analysis/preserve_field_drop_order2.rs b/tests/ui/closures/2229_closure_analysis/preserve_field_drop_order2.rs index 4fc2e6c903a9..a771b815702a 100644 --- a/tests/ui/closures/2229_closure_analysis/preserve_field_drop_order2.rs +++ b/tests/ui/closures/2229_closure_analysis/preserve_field_drop_order2.rs @@ -1,8 +1,8 @@ //@ run-pass //@ check-run-results //@ revisions: twenty_eighteen twenty_twentyone -//@ [twenty_eighteen]compile-flags: --edition 2018 -//@ [twenty_twentyone]compile-flags: --edition 2021 +//@ [twenty_eighteen] edition: 2018 +//@ [twenty_twentyone] edition: 2021 #[derive(Debug)] struct Dropable(&'static str); diff --git a/tests/ui/closures/binder/implicit-return.rs b/tests/ui/closures/binder/implicit-return.rs index d34e5721d919..9889d055a366 100644 --- a/tests/ui/closures/binder/implicit-return.rs +++ b/tests/ui/closures/binder/implicit-return.rs @@ -2,5 +2,5 @@ fn main() { let _f = for<'a> |_: &'a ()| {}; - //~^ implicit types in closure signatures are forbidden when `for<...>` is present + //~^ ERROR implicit types in closure signatures are forbidden when `for<...>` is present } diff --git a/tests/ui/closures/deduce-signature/obligation-with-leaking-placeholders.rs b/tests/ui/closures/deduce-signature/obligation-with-leaking-placeholders.rs index deb888ec2867..f8e3b14f9276 100644 --- a/tests/ui/closures/deduce-signature/obligation-with-leaking-placeholders.rs +++ b/tests/ui/closures/deduce-signature/obligation-with-leaking-placeholders.rs @@ -16,7 +16,7 @@ impl<'a, T> Foo<'a> for Wrap where T: Fn(&'a i32) {} fn main() { needs_foo(|x| { - //[current]~^ implementation of `Foo` is not general enough + //[current]~^ ERROR implementation of `Foo` is not general enough //[next]~^^ ERROR type annotations needed x.to_string(); }); diff --git a/tests/ui/closures/issue-78720.rs b/tests/ui/closures/issue-78720.rs index 81af030fe556..a615cdf26902 100644 --- a/tests/ui/closures/issue-78720.rs +++ b/tests/ui/closures/issue-78720.rs @@ -1,5 +1,6 @@ fn server() -> impl { //~^ ERROR at least one trait must be specified + //~^^ ERROR type annotations needed ().map2(|| "") } diff --git a/tests/ui/closures/issue-78720.stderr b/tests/ui/closures/issue-78720.stderr index 90672cd83d7c..3e95fab441ad 100644 --- a/tests/ui/closures/issue-78720.stderr +++ b/tests/ui/closures/issue-78720.stderr @@ -5,7 +5,7 @@ LL | fn server() -> impl { | ^^^^ error[E0412]: cannot find type `F` in this scope - --> $DIR/issue-78720.rs:13:12 + --> $DIR/issue-78720.rs:14:12 | LL | _func: F, | ^ @@ -22,8 +22,14 @@ help: you might be missing a type parameter LL | struct Map2 { | +++ +error[E0282]: type annotations needed + --> $DIR/issue-78720.rs:1:16 + | +LL | fn server() -> impl { + | ^^^^ cannot infer type + error[E0308]: mismatched types - --> $DIR/issue-78720.rs:7:39 + --> $DIR/issue-78720.rs:8:39 | LL | fn map2(self, f: F) -> Map2 {} | ^^ expected `Map2`, found `()` @@ -32,7 +38,7 @@ LL | fn map2(self, f: F) -> Map2 {} found unit type `()` error[E0277]: the size for values of type `Self` cannot be known at compilation time - --> $DIR/issue-78720.rs:7:16 + --> $DIR/issue-78720.rs:8:16 | LL | fn map2(self, f: F) -> Map2 {} | ^^^^ doesn't have a size known at compile-time @@ -47,7 +53,7 @@ help: function arguments must have a statically known size, borrowed types alway LL | fn map2(&self, f: F) -> Map2 {} | + -error: aborting due to 4 previous errors +error: aborting due to 5 previous errors -Some errors have detailed explanations: E0277, E0308, E0412. +Some errors have detailed explanations: E0277, E0282, E0308, E0412. For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/closures/wrong-closure-arg-suggestion-125325.rs b/tests/ui/closures/wrong-closure-arg-suggestion-125325.rs index ce575697cf68..c72d19e84816 100644 --- a/tests/ui/closures/wrong-closure-arg-suggestion-125325.rs +++ b/tests/ui/closures/wrong-closure-arg-suggestion-125325.rs @@ -21,9 +21,9 @@ fn func(_f: impl Fn()) -> usize { fn test_func(s: &S) -> usize { let mut x = (); s.assoc_func(|| x = ()); - //~^ cannot assign to `x`, as it is a captured variable in a `Fn` closure + //~^ ERROR cannot assign to `x`, as it is a captured variable in a `Fn` closure func(|| x = ()) - //~^ cannot assign to `x`, as it is a captured variable in a `Fn` closure + //~^ ERROR cannot assign to `x`, as it is a captured variable in a `Fn` closure } fn main() {} diff --git a/tests/ui/codegen/empty-static-libs-issue-108825.rs b/tests/ui/codegen/empty-static-libs-issue-108825.rs index 46bd6d6b2da4..4c644be0954e 100644 --- a/tests/ui/codegen/empty-static-libs-issue-108825.rs +++ b/tests/ui/codegen/empty-static-libs-issue-108825.rs @@ -3,7 +3,6 @@ //@ compile-flags: -Cpanic=abort --print=native-static-libs //@ build-pass -//@ error-pattern: note: native-static-libs: //@ dont-check-compiler-stderr (libcore links `/defaultlib:msvcrt` or `/defaultlib:libcmt` on MSVC) //@ ignore-pass (the note is emitted later in the compilation pipeline, needs build) @@ -14,3 +13,6 @@ fn panic(_info: &core::panic::PanicInfo) -> ! { loop {} } + +//~? NOTE native-static-libs: +//~? NOTE Link against the following native artifacts when linking against this static library diff --git a/tests/ui/codegen/overflow-during-mono.rs b/tests/ui/codegen/overflow-during-mono.rs index 83a8b6b3ef6a..a9045840173e 100644 --- a/tests/ui/codegen/overflow-during-mono.rs +++ b/tests/ui/codegen/overflow-during-mono.rs @@ -1,4 +1,4 @@ -//~ ERROR overflow evaluating the requirement `{closure@$DIR/overflow-during-mono.rs:13:41: 13:44}: Sized` +//~ ERROR overflow evaluating the requirement `for<'a> {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}: FnMut(&'a _)` //@ build-fail #![recursion_limit = "32"] diff --git a/tests/ui/codegen/overflow-during-mono.stderr b/tests/ui/codegen/overflow-during-mono.stderr index f7a3e2df3dba..74d98fde285b 100644 --- a/tests/ui/codegen/overflow-during-mono.stderr +++ b/tests/ui/codegen/overflow-during-mono.stderr @@ -1,4 +1,4 @@ -error[E0275]: overflow evaluating the requirement `{closure@$DIR/overflow-during-mono.rs:13:41: 13:44}: Sized` +error[E0275]: overflow evaluating the requirement `for<'a> {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}: FnMut(&'a _)` | = help: consider increasing the recursion limit by adding a `#![recursion_limit = "64"]` attribute to your crate (`overflow_during_mono`) = note: required for `Filter, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>` to implement `Iterator` diff --git a/tests/ui/codemap_tests/two_files_data.rs b/tests/ui/codemap_tests/two_files_data.rs index a4e4cf7e896e..82852f6cfbdf 100644 --- a/tests/ui/codemap_tests/two_files_data.rs +++ b/tests/ui/codemap_tests/two_files_data.rs @@ -1,4 +1,4 @@ -//@ ignore-test (auxiliary, used by other tests) +//@ ignore-auxiliary (used by `./two_files.rs`) trait Foo { } diff --git a/tests/ui/codemap_tests/unicode.expanded.stdout b/tests/ui/codemap_tests/unicode.expanded.stdout index eb53d12e94f3..c88035de0449 100644 --- a/tests/ui/codemap_tests/unicode.expanded.stdout +++ b/tests/ui/codemap_tests/unicode.expanded.stdout @@ -7,6 +7,7 @@ extern crate std; //@ revisions: normal expanded //@[expanded] check-pass //@[expanded]compile-flags: -Zunpretty=expanded +//@ edition: 2015 extern "路濫狼á́́" fn foo() {} diff --git a/tests/ui/codemap_tests/unicode.normal.stderr b/tests/ui/codemap_tests/unicode.normal.stderr index 0f254e0246f4..10cb34f48326 100644 --- a/tests/ui/codemap_tests/unicode.normal.stderr +++ b/tests/ui/codemap_tests/unicode.normal.stderr @@ -1,5 +1,5 @@ error[E0703]: invalid ABI: found `路濫狼á́́` - --> $DIR/unicode.rs:5:8 + --> $DIR/unicode.rs:6:8 | LL | extern "路濫狼á́́" fn foo() {} | ^^^^^^^^^ invalid ABI diff --git a/tests/ui/codemap_tests/unicode.rs b/tests/ui/codemap_tests/unicode.rs index 73023e3c669d..4b93ef094069 100644 --- a/tests/ui/codemap_tests/unicode.rs +++ b/tests/ui/codemap_tests/unicode.rs @@ -1,6 +1,7 @@ //@ revisions: normal expanded //@[expanded] check-pass //@[expanded]compile-flags: -Zunpretty=expanded +//@ edition: 2015 extern "路濫狼á́́" fn foo() {} //[normal]~ ERROR invalid ABI diff --git a/tests/ui/coercion/codegen-smart-pointer-with-alias.rs b/tests/ui/coercion/codegen-smart-pointer-with-alias.rs new file mode 100644 index 000000000000..a68952bb70aa --- /dev/null +++ b/tests/ui/coercion/codegen-smart-pointer-with-alias.rs @@ -0,0 +1,32 @@ +//@ build-pass + +// Regression test for . + +// Make sure that the unsize coercion we collect in mono for `Signal -> Signal` +// doesn't choke on the fact that the inner unsized field of `Signal` is a (trivial) alias. +// This exercises a normalize call that is necessary since we're getting a type from the type +// system, which isn't guaranteed to be normalized after substitution. + +#![feature(coerce_unsized)] + +use std::ops::CoerceUnsized; + +trait Mirror { + type Assoc: ?Sized; +} +impl Mirror for T { + type Assoc = T; +} + +trait Any {} +impl Any for T {} + +struct Signal<'a, T: ?Sized>(<&'a T as Mirror>::Assoc); + +// This `CoerceUnsized` impl isn't special; it's a bit more restricted than we'd see in the wild, +// but this ICE also reproduces if we were to make it general over `Signal -> Signal`. +impl<'a> CoerceUnsized> for Signal<'a, i32> {} + +fn main() { + Signal(&1i32) as Signal; +} diff --git a/tests/ui/coercion/coerce-reborrow-multi-arg-fail.rs b/tests/ui/coercion/coerce-reborrow-multi-arg-fail.rs index 48be2d3146b8..0a58f0897aae 100644 --- a/tests/ui/coercion/coerce-reborrow-multi-arg-fail.rs +++ b/tests/ui/coercion/coerce-reborrow-multi-arg-fail.rs @@ -2,5 +2,5 @@ fn test(_a: T, _b: T) {} fn main() { test(&mut 7, &7); - //~^ mismatched types + //~^ ERROR mismatched types } diff --git a/tests/ui/coercion/mut-mut-wont-coerce.rs b/tests/ui/coercion/mut-mut-wont-coerce.rs index e99566461a24..33016e1e48a8 100644 --- a/tests/ui/coercion/mut-mut-wont-coerce.rs +++ b/tests/ui/coercion/mut-mut-wont-coerce.rs @@ -33,7 +33,7 @@ fn make_foo(_: *mut *mut Foo) { fn main() { let mut result: SmartPtr = SmartPtr(std::ptr::null_mut()); - make_foo(&mut &mut *result); //~ mismatched types + make_foo(&mut &mut *result); //~ ERROR mismatched types //~^ expected `*mut *mut Foo`, found `&mut &mut Foo` make_foo(out(&mut result)); // works, but makes one wonder why above coercion cannot happen } diff --git a/tests/ui/compiletest-self-test/trim-env-name.rs b/tests/ui/compiletest-self-test/trim-env-name.rs new file mode 100644 index 000000000000..0cb6efe9f765 --- /dev/null +++ b/tests/ui/compiletest-self-test/trim-env-name.rs @@ -0,0 +1,23 @@ +//@ edition: 2024 +//@ revisions: set unset +//@ run-pass +//@ ignore-cross-compile (assume that non-cross targets have working env vars) +//@ rustc-env: MY_RUSTC_ENV = my-rustc-value +//@ exec-env: MY_EXEC_ENV = my-exec-value +//@[unset] unset-rustc-env: MY_RUSTC_ENV +//@[unset] unset-exec-env: MY_EXEC_ENV + +// Check that compiletest trims whitespace from environment variable names +// specified in `rustc-env` and `exec-env` directives, so that +// `//@ exec-env: FOO=bar` sees the name as `FOO` and not ` FOO`. +// +// Values are currently not trimmed. +// +// Since this is a compiletest self-test, only run it on non-cross targets, +// to avoid having to worry about weird targets that don't support env vars. + +fn main() { + let is_set = cfg!(set); + assert_eq!(option_env!("MY_RUSTC_ENV"), is_set.then_some(" my-rustc-value")); + assert_eq!(std::env::var("MY_EXEC_ENV").ok().as_deref(), is_set.then_some(" my-exec-value")); +} diff --git a/tests/ui/conditional-compilation/cfg-arg-invalid-1.rs b/tests/ui/conditional-compilation/cfg-arg-invalid-1.rs index cd181f4a49f6..28d2d266b623 100644 --- a/tests/ui/conditional-compilation/cfg-arg-invalid-1.rs +++ b/tests/ui/conditional-compilation/cfg-arg-invalid-1.rs @@ -1,3 +1,5 @@ -//@ compile-flags: --error-format=human --cfg a(b=c) -//@ error-pattern: invalid `--cfg` argument: `a(b=c)` (expected `key` or `key="value"`, ensure escaping is appropriate for your shell, try 'key="value"' or key=\"value\") +//@ compile-flags: --cfg a(b=c) + fn main() {} + +//~? ERROR invalid `--cfg` argument: `a(b=c)` (expected `key` or `key="value"`, ensure escaping is appropriate for your shell, try 'key="value"' or key=\"value\") diff --git a/tests/ui/conditional-compilation/cfg-arg-invalid-2.rs b/tests/ui/conditional-compilation/cfg-arg-invalid-2.rs index a0c16bd1f80a..a46022602e27 100644 --- a/tests/ui/conditional-compilation/cfg-arg-invalid-2.rs +++ b/tests/ui/conditional-compilation/cfg-arg-invalid-2.rs @@ -1,3 +1,5 @@ -//@ compile-flags: --error-format=human --cfg a{b} -//@ error-pattern: invalid `--cfg` argument: `a{b}` (expected `key` or `key="value"`) +//@ compile-flags: --cfg a{b} + fn main() {} + +//~? ERROR invalid `--cfg` argument: `a{b}` (expected `key` or `key="value"`) diff --git a/tests/ui/conditional-compilation/cfg-arg-invalid-4.rs b/tests/ui/conditional-compilation/cfg-arg-invalid-4.rs index 30402d51852f..ba34708c171b 100644 --- a/tests/ui/conditional-compilation/cfg-arg-invalid-4.rs +++ b/tests/ui/conditional-compilation/cfg-arg-invalid-4.rs @@ -1,3 +1,5 @@ -//@ compile-flags: --error-format=human --cfg a(b) -//@ error-pattern: invalid `--cfg` argument: `a(b)` (expected `key` or `key="value"`) +//@ compile-flags: --cfg a(b) + fn main() {} + +//~? ERROR invalid `--cfg` argument: `a(b)` (expected `key` or `key="value"`) diff --git a/tests/ui/conditional-compilation/cfg-arg-invalid-6.rs b/tests/ui/conditional-compilation/cfg-arg-invalid-6.rs index e0ce66eab877..2c2fc105958a 100644 --- a/tests/ui/conditional-compilation/cfg-arg-invalid-6.rs +++ b/tests/ui/conditional-compilation/cfg-arg-invalid-6.rs @@ -1,3 +1,5 @@ -//@ compile-flags: --error-format=human --cfg a{ -//@ error-pattern: invalid `--cfg` argument: `a{` (expected `key` or `key="value"`) +//@ compile-flags: --cfg a{ + fn main() {} + +//~? ERROR invalid `--cfg` argument: `a{` (expected `key` or `key="value"`) diff --git a/tests/ui/conditional-compilation/cfg-arg-invalid-8.rs b/tests/ui/conditional-compilation/cfg-arg-invalid-8.rs index 33f8da25830e..c9185fc7b259 100644 --- a/tests/ui/conditional-compilation/cfg-arg-invalid-8.rs +++ b/tests/ui/conditional-compilation/cfg-arg-invalid-8.rs @@ -1,3 +1,5 @@ -//@ compile-flags: --error-format=human --cfg ) -//@ error-pattern: invalid `--cfg` argument: `)` (expected `key` or `key="value"`) +//@ compile-flags: --cfg ) + fn main() {} + +//~? ERROR invalid `--cfg` argument: `)` (expected `key` or `key="value"`) diff --git a/tests/ui/conditional-compilation/cfg-arg-invalid-9.rs b/tests/ui/conditional-compilation/cfg-arg-invalid-9.rs index 8ab3b101da79..8d07165dfae4 100644 --- a/tests/ui/conditional-compilation/cfg-arg-invalid-9.rs +++ b/tests/ui/conditional-compilation/cfg-arg-invalid-9.rs @@ -1,4 +1,6 @@ // Test for missing quotes around value, issue #66450. -//@ compile-flags: --error-format=human --cfg key=value -//@ error-pattern: invalid `--cfg` argument: `key=value` (expected `key` or `key="value"`, ensure escaping is appropriate for your shell, try 'key="value"' or key=\"value\") +//@ compile-flags: --cfg key=value + fn main() {} + +//~? ERROR invalid `--cfg` argument: `key=value` (expected `key` or `key="value"`, ensure escaping is appropriate for your shell, try 'key="value"' or key=\"value\") diff --git a/tests/ui/conditional-compilation/cfg-empty-codemap.rs b/tests/ui/conditional-compilation/cfg-empty-codemap.rs index d8fc02777595..9f7ef1bcf9aa 100644 --- a/tests/ui/conditional-compilation/cfg-empty-codemap.rs +++ b/tests/ui/conditional-compilation/cfg-empty-codemap.rs @@ -1,8 +1,8 @@ // Tests that empty source_maps don't ICE (#23301) -//@ compile-flags: --error-format=human --cfg "" - -//@ error-pattern: invalid `--cfg` argument: `""` (expected `key` or `key="value"`) +//@ compile-flags: --cfg "" pub fn main() { } + +//~? ERROR invalid `--cfg` argument: `""` (expected `key` or `key="value"`) diff --git a/tests/ui/conditional-compilation/cfg-generic-params.rs b/tests/ui/conditional-compilation/cfg-generic-params.rs index 4bb8f8ae94f6..6480a0f24794 100644 --- a/tests/ui/conditional-compilation/cfg-generic-params.rs +++ b/tests/ui/conditional-compilation/cfg-generic-params.rs @@ -1,18 +1,18 @@ //@ compile-flags:--cfg yes --check-cfg=cfg(yes,no) -fn f_lt<#[cfg(yes)] 'a: 'a, #[cfg(FALSE)] T>() {} -fn f_ty<#[cfg(FALSE)] 'a: 'a, #[cfg(yes)] T>() {} +fn f_lt<#[cfg(yes)] 'a: 'a, #[cfg(false)] T>() {} +fn f_ty<#[cfg(false)] 'a: 'a, #[cfg(yes)] T>() {} -type FnGood = for<#[cfg(yes)] 'a, #[cfg(FALSE)] T> fn(); // OK -type FnBad = for<#[cfg(FALSE)] 'a, #[cfg(yes)] T> fn(); +type FnGood = for<#[cfg(yes)] 'a, #[cfg(false)] T> fn(); // OK +type FnBad = for<#[cfg(false)] 'a, #[cfg(yes)] T> fn(); //~^ ERROR only lifetime parameters can be used in this context -type PolyGood = dyn for<#[cfg(yes)] 'a, #[cfg(FALSE)] T> Copy; // OK -type PolyBad = dyn for<#[cfg(FALSE)] 'a, #[cfg(yes)] T> Copy; +type PolyGood = dyn for<#[cfg(yes)] 'a, #[cfg(false)] T> Copy; // OK +type PolyBad = dyn for<#[cfg(false)] 'a, #[cfg(yes)] T> Copy; //~^ ERROR only lifetime parameters can be used in this context -struct WhereGood where for<#[cfg(yes)] 'a, #[cfg(FALSE)] T> u8: Copy; // OK -struct WhereBad where for<#[cfg(FALSE)] 'a, #[cfg(yes)] T> u8: Copy; +struct WhereGood where for<#[cfg(yes)] 'a, #[cfg(false)] T> u8: Copy; // OK +struct WhereBad where for<#[cfg(false)] 'a, #[cfg(yes)] T> u8: Copy; //~^ ERROR only lifetime parameters can be used in this context fn f_lt_no<#[cfg_attr(FALSE, unknown)] 'a>() {} // OK diff --git a/tests/ui/conditional-compilation/cfg-generic-params.stderr b/tests/ui/conditional-compilation/cfg-generic-params.stderr index 563616be36bc..bae75dd0deb0 100644 --- a/tests/ui/conditional-compilation/cfg-generic-params.stderr +++ b/tests/ui/conditional-compilation/cfg-generic-params.stderr @@ -31,7 +31,7 @@ LL | struct WhereYes where for<#[cfg_attr(yes, unknown)] 'a> u8: Copy; error[E0658]: only lifetime parameters can be used in this context --> $DIR/cfg-generic-params.rs:7:48 | -LL | type FnBad = for<#[cfg(FALSE)] 'a, #[cfg(yes)] T> fn(); +LL | type FnBad = for<#[cfg(false)] 'a, #[cfg(yes)] T> fn(); | ^ | = note: see issue #108185 for more information @@ -41,7 +41,7 @@ LL | type FnBad = for<#[cfg(FALSE)] 'a, #[cfg(yes)] T> fn(); error[E0658]: only lifetime parameters can be used in this context --> $DIR/cfg-generic-params.rs:11:54 | -LL | type PolyBad = dyn for<#[cfg(FALSE)] 'a, #[cfg(yes)] T> Copy; +LL | type PolyBad = dyn for<#[cfg(false)] 'a, #[cfg(yes)] T> Copy; | ^ | = note: see issue #108185 for more information @@ -51,7 +51,7 @@ LL | type PolyBad = dyn for<#[cfg(FALSE)] 'a, #[cfg(yes)] T> Copy; error[E0658]: only lifetime parameters can be used in this context --> $DIR/cfg-generic-params.rs:15:57 | -LL | struct WhereBad where for<#[cfg(FALSE)] 'a, #[cfg(yes)] T> u8: Copy; +LL | struct WhereBad where for<#[cfg(false)] 'a, #[cfg(yes)] T> u8: Copy; | ^ | = note: see issue #108185 for more information diff --git a/tests/ui/conditional-compilation/cfg-in-crate-1.rs b/tests/ui/conditional-compilation/cfg-in-crate-1.rs index a1faa2397a33..b9efa32babef 100644 --- a/tests/ui/conditional-compilation/cfg-in-crate-1.rs +++ b/tests/ui/conditional-compilation/cfg-in-crate-1.rs @@ -1 +1 @@ -#![cfg(FALSE)] //~ ERROR `main` function not found in crate `cfg_in_crate_1` +#![cfg(false)] //~ ERROR `main` function not found in crate `cfg_in_crate_1` diff --git a/tests/ui/conditional-compilation/cfg-in-crate-1.stderr b/tests/ui/conditional-compilation/cfg-in-crate-1.stderr index 126e10cf0402..352baf33091b 100644 --- a/tests/ui/conditional-compilation/cfg-in-crate-1.stderr +++ b/tests/ui/conditional-compilation/cfg-in-crate-1.stderr @@ -1,7 +1,7 @@ error[E0601]: `main` function not found in crate `cfg_in_crate_1` --> $DIR/cfg-in-crate-1.rs:1:15 | -LL | #![cfg(FALSE)] +LL | #![cfg(false)] | ^ consider adding a `main` function to `$DIR/cfg-in-crate-1.rs` error: aborting due to 1 previous error diff --git a/tests/ui/conditional-compilation/cfg-non-opt-expr.rs b/tests/ui/conditional-compilation/cfg-non-opt-expr.rs index ae85f38e645e..cae07ae0ced1 100644 --- a/tests/ui/conditional-compilation/cfg-non-opt-expr.rs +++ b/tests/ui/conditional-compilation/cfg-non-opt-expr.rs @@ -2,10 +2,10 @@ #![feature(custom_test_frameworks)] fn main() { - let _ = #[cfg(FALSE)] (); + let _ = #[cfg(false)] (); //~^ ERROR removing an expression is not supported in this position - let _ = 1 + 2 + #[cfg(FALSE)] 3; + let _ = 1 + 2 + #[cfg(false)] 3; //~^ ERROR removing an expression is not supported in this position - let _ = [1, 2, 3][#[cfg(FALSE)] 1]; + let _ = [1, 2, 3][#[cfg(false)] 1]; //~^ ERROR removing an expression is not supported in this position } diff --git a/tests/ui/conditional-compilation/cfg-non-opt-expr.stderr b/tests/ui/conditional-compilation/cfg-non-opt-expr.stderr index 06eaa59efdd7..bd1bfeb06c7a 100644 --- a/tests/ui/conditional-compilation/cfg-non-opt-expr.stderr +++ b/tests/ui/conditional-compilation/cfg-non-opt-expr.stderr @@ -1,19 +1,19 @@ error: removing an expression is not supported in this position --> $DIR/cfg-non-opt-expr.rs:5:13 | -LL | let _ = #[cfg(FALSE)] (); +LL | let _ = #[cfg(false)] (); | ^^^^^^^^^^^^^ error: removing an expression is not supported in this position --> $DIR/cfg-non-opt-expr.rs:7:21 | -LL | let _ = 1 + 2 + #[cfg(FALSE)] 3; +LL | let _ = 1 + 2 + #[cfg(false)] 3; | ^^^^^^^^^^^^^ error: removing an expression is not supported in this position --> $DIR/cfg-non-opt-expr.rs:9:23 | -LL | let _ = [1, 2, 3][#[cfg(FALSE)] 1]; +LL | let _ = [1, 2, 3][#[cfg(false)] 1]; | ^^^^^^^^^^^^^ error: aborting due to 3 previous errors diff --git a/tests/ui/conditional-compilation/cfg_accessible-not_sure.rs b/tests/ui/conditional-compilation/cfg_accessible-not_sure.rs index 2ac57f356740..7753b7d64fb3 100644 --- a/tests/ui/conditional-compilation/cfg_accessible-not_sure.rs +++ b/tests/ui/conditional-compilation/cfg_accessible-not_sure.rs @@ -1,6 +1,6 @@ //@ revisions: edition2015 edition2021 -//@ [edition2015]compile-flags: --edition=2015 -//@ [edition2021]compile-flags: --edition=2021 +//@ [edition2015] edition: 2015 +//@ [edition2021] edition: 2021 #![feature(extern_types)] #![feature(cfg_accessible)] diff --git a/tests/ui/conditional-compilation/module_with_cfg.rs b/tests/ui/conditional-compilation/module_with_cfg.rs index 778379fa6ea7..a96f8a3e6e96 100644 --- a/tests/ui/conditional-compilation/module_with_cfg.rs +++ b/tests/ui/conditional-compilation/module_with_cfg.rs @@ -1,3 +1,3 @@ -//@ ignore-test (auxiliary, used by other tests) +//@ ignore-auxiliary (used by `./inner-cfg-non-inline-mod.rs`) -#![cfg_attr(all(), cfg(FALSE))] +#![cfg_attr(all(), cfg(false))] diff --git a/tests/ui/const-generics/adt_const_params/nested_bad_const_param_ty.rs b/tests/ui/const-generics/adt_const_params/nested_bad_const_param_ty.rs index 3a283442a0b0..34ea143d2546 100644 --- a/tests/ui/const-generics/adt_const_params/nested_bad_const_param_ty.rs +++ b/tests/ui/const-generics/adt_const_params/nested_bad_const_param_ty.rs @@ -4,18 +4,18 @@ use std::marker::ConstParamTy; #[derive(ConstParamTy)] -//~^ the trait `ConstParamTy_` cannot be implemented for this ty -//~| the trait `ConstParamTy_` cannot be implemented for this ty +//~^ ERROR the trait `ConstParamTy_` cannot be implemented for this ty +//~| ERROR the trait `ConstParamTy_` cannot be implemented for this ty struct Foo([*const u8; 1]); #[derive(ConstParamTy)] -//~^ the trait `ConstParamTy_` cannot be implemented for this ty -//~| the trait `ConstParamTy_` cannot be implemented for this ty +//~^ ERROR the trait `ConstParamTy_` cannot be implemented for this ty +//~| ERROR the trait `ConstParamTy_` cannot be implemented for this ty struct Foo2([*mut u8; 1]); #[derive(ConstParamTy)] -//~^ the trait `ConstParamTy_` cannot be implemented for this ty -//~| the trait `ConstParamTy_` cannot be implemented for this ty +//~^ ERROR the trait `ConstParamTy_` cannot be implemented for this ty +//~| ERROR the trait `ConstParamTy_` cannot be implemented for this ty struct Foo3([fn(); 1]); fn main() {} diff --git a/tests/ui/const-generics/defaults/mismatch.rs b/tests/ui/const-generics/defaults/mismatch.rs index ec131505ed75..3e35c2060b1e 100644 --- a/tests/ui/const-generics/defaults/mismatch.rs +++ b/tests/ui/const-generics/defaults/mismatch.rs @@ -5,18 +5,18 @@ pub struct Example4; fn main() { let e: Example<13> = (); - //~^ Error: mismatched types + //~^ ERROR mismatched types //~| expected struct `Example` let e: Example2 = (); - //~^ Error: mismatched types + //~^ ERROR mismatched types //~| expected struct `Example2` let e: Example3<13, u32> = (); - //~^ Error: mismatched types + //~^ ERROR mismatched types //~| expected struct `Example3` let e: Example3<7> = (); - //~^ Error: mismatched types + //~^ ERROR mismatched types //~| expected struct `Example3<7>` let e: Example4<7> = (); - //~^ Error: mismatched types + //~^ ERROR mismatched types //~| expected struct `Example4<7>` } diff --git a/tests/ui/const-generics/defaults/pretty-printing-ast.rs b/tests/ui/const-generics/defaults/pretty-printing-ast.rs index 20bf900d9f3e..f7a166d00d55 100644 --- a/tests/ui/const-generics/defaults/pretty-printing-ast.rs +++ b/tests/ui/const-generics/defaults/pretty-printing-ast.rs @@ -1,6 +1,7 @@ // Test the AST pretty printer correctly handles default values for const generics //@ check-pass //@ compile-flags: -Z unpretty=expanded +//@ edition: 2015 #![crate_type = "lib"] diff --git a/tests/ui/const-generics/defaults/pretty-printing-ast.stdout b/tests/ui/const-generics/defaults/pretty-printing-ast.stdout index f1cd1451700f..b6cb7fa09c88 100644 --- a/tests/ui/const-generics/defaults/pretty-printing-ast.stdout +++ b/tests/ui/const-generics/defaults/pretty-printing-ast.stdout @@ -3,6 +3,7 @@ // Test the AST pretty printer correctly handles default values for const generics //@ check-pass //@ compile-flags: -Z unpretty=expanded +//@ edition: 2015 #![crate_type = "lib"] #[prelude_import] diff --git a/tests/ui/const-generics/dont-evaluate-array-len-on-err-1.rs b/tests/ui/const-generics/dont-evaluate-array-len-on-err-1.rs index 6c4ee1af210b..e7f050dae367 100644 --- a/tests/ui/const-generics/dont-evaluate-array-len-on-err-1.rs +++ b/tests/ui/const-generics/dont-evaluate-array-len-on-err-1.rs @@ -13,7 +13,7 @@ trait Foo { [Adt; std::mem::size_of::()]: , { <[Adt; std::mem::size_of::()] as Foo>::bar() - //~^ Error: the trait bound + //~^ ERROR the trait bound } fn bar() {} diff --git a/tests/ui/const-generics/early/invalid-const-arguments.rs b/tests/ui/const-generics/early/invalid-const-arguments.rs index 6619c9758859..68e6b2ac458e 100644 --- a/tests/ui/const-generics/early/invalid-const-arguments.rs +++ b/tests/ui/const-generics/early/invalid-const-arguments.rs @@ -4,7 +4,7 @@ struct A; trait Foo {} impl Foo for A {} //~^ ERROR cannot find type -//~| unresolved item provided when a constant +//~| ERROR unresolved item provided when a constant struct B; impl Foo for B {} @@ -13,4 +13,4 @@ impl Foo for B {} struct C; impl Foo for C {} //~^ ERROR cannot find type -//~| unresolved item provided when a constant +//~| ERROR unresolved item provided when a constant diff --git a/tests/ui/const-generics/generic_arg_infer/parend_infer.nogate.stderr b/tests/ui/const-generics/generic_arg_infer/parend_infer.nogate.stderr new file mode 100644 index 000000000000..d0a5da9676df --- /dev/null +++ b/tests/ui/const-generics/generic_arg_infer/parend_infer.nogate.stderr @@ -0,0 +1,53 @@ +error[E0658]: const arguments cannot yet be inferred with `_` + --> $DIR/parend_infer.rs:24:16 + | +LL | let c: Foo<_> = Foo::<1>; + | ^ + | + = note: see issue #85077 for more information + = help: add `#![feature(generic_arg_infer)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: const arguments cannot yet be inferred with `_` + --> $DIR/parend_infer.rs:26:16 + | +LL | let c: Foo<(_)> = Foo::<1>; + | ^^^ + | + = note: see issue #85077 for more information + = help: add `#![feature(generic_arg_infer)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: const arguments cannot yet be inferred with `_` + --> $DIR/parend_infer.rs:28:16 + | +LL | let c: Foo<(((_)))> = Foo::<1>; + | ^^^^^^^ + | + = note: see issue #85077 for more information + = help: add `#![feature(generic_arg_infer)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: using `_` for array lengths is unstable + --> $DIR/parend_infer.rs:17:17 + | +LL | let b: [u8; (_)] = [1; (((((_)))))]; + | ^^^ + | + = note: see issue #85077 for more information + = help: add `#![feature(generic_arg_infer)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: using `_` for array lengths is unstable + --> $DIR/parend_infer.rs:17:28 + | +LL | let b: [u8; (_)] = [1; (((((_)))))]; + | ^^^^^^^^^^^ + | + = note: see issue #85077 for more information + = help: add `#![feature(generic_arg_infer)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/const-generics/generic_arg_infer/parend_infer.rs b/tests/ui/const-generics/generic_arg_infer/parend_infer.rs index 81c42183b383..3dc27a702de4 100644 --- a/tests/ui/const-generics/generic_arg_infer/parend_infer.rs +++ b/tests/ui/const-generics/generic_arg_infer/parend_infer.rs @@ -1,7 +1,9 @@ -//@ check-pass +//@[gate] check-pass //@ revisions: gate nogate #![cfg_attr(gate, feature(generic_arg_infer))] +struct Foo; + fn main() { // AST Types preserve parens for pretty printing reasons. This means // that this is parsed as a `TyKind::Paren(TyKind::Infer)`. Generic @@ -9,4 +11,20 @@ fn main() { // but `TyKind::Infer` wrapped in arbitrarily many `TyKind::Paren`. let a: Vec<(_)> = vec![1_u8]; let a: Vec<(((((_)))))> = vec![1_u8]; + + // AST Exprs similarly preserve parens for pretty printing reasons. + #[rustfmt::skip] + let b: [u8; (_)] = [1; (((((_)))))]; + //[nogate]~^ error: using `_` for array lengths is unstable + //[nogate]~| error: using `_` for array lengths is unstable + let b: [u8; 2] = b; + + // This is the same case as AST types as the parser doesn't distinguish between const + // and type args when they share syntax + let c: Foo<_> = Foo::<1>; + //[nogate]~^ error: const arguments cannot yet be inferred with `_` + let c: Foo<(_)> = Foo::<1>; + //[nogate]~^ error: const arguments cannot yet be inferred with `_` + let c: Foo<(((_)))> = Foo::<1>; + //[nogate]~^ error: const arguments cannot yet be inferred with `_` } diff --git a/tests/ui/const-generics/generic_const_exprs/abstract-const-as-cast-3.rs b/tests/ui/const-generics/generic_const_exprs/abstract-const-as-cast-3.rs index 7561ae2febbd..33872ce7f0f2 100644 --- a/tests/ui/const-generics/generic_const_exprs/abstract-const-as-cast-3.rs +++ b/tests/ui/const-generics/generic_const_exprs/abstract-const-as-cast-3.rs @@ -15,15 +15,15 @@ where // errors are bad but seems to be pre-existing issue #86198 assert_impl::>(); - //~^ Error: mismatched types - //~^^ Error: unconstrained generic constant + //~^ ERROR mismatched types + //~^^ ERROR unconstrained generic constant assert_impl::>(); - //~^ Error: mismatched types - //~^^ Error: unconstrained generic constant + //~^ ERROR mismatched types + //~^^ ERROR unconstrained generic constant assert_impl::>(); - //~^ Error: mismatched types + //~^ ERROR mismatched types assert_impl::>(); - //~^ Error: mismatched types + //~^ ERROR mismatched types } pub fn use_trait_impl_2() where @@ -33,15 +33,15 @@ where // errors are bad but seems to be pre-existing issue #86198 assert_impl::>(); - //~^ Error: mismatched types - //~^^ Error: unconstrained generic constant + //~^ ERROR mismatched types + //~^^ ERROR unconstrained generic constant assert_impl::>(); - //~^ Error: mismatched types - //~^^ Error: unconstrained generic constant + //~^ ERROR mismatched types + //~^^ ERROR unconstrained generic constant assert_impl::>(); - //~^ Error: mismatched types + //~^ ERROR mismatched types assert_impl::>(); - //~^ Error: mismatched types + //~^ ERROR mismatched types } fn main() {} diff --git a/tests/ui/const-generics/generic_const_exprs/const-generics-closure.rs b/tests/ui/const-generics/generic_const_exprs/const-generics-closure.rs new file mode 100644 index 000000000000..aad8cefe5d62 --- /dev/null +++ b/tests/ui/const-generics/generic_const_exprs/const-generics-closure.rs @@ -0,0 +1,13 @@ +// Regression test for issue #127424 + +fn bar() -> impl Into< + [u8; { + //~^ ERROR mismatched types [E0308] + let _ = for<'a, 'b> |x: &'a &'a Vec<&'b u32>, b: bool| -> &'a Vec<&'b u32> { *x }; + //~^ ERROR `for<...>` binders for closures are experimental [E0658] + }], +> { + [89] +} + +fn main() {} diff --git a/tests/ui/const-generics/generic_const_exprs/const-generics-closure.stderr b/tests/ui/const-generics/generic_const_exprs/const-generics-closure.stderr new file mode 100644 index 000000000000..5410bbdc1253 --- /dev/null +++ b/tests/ui/const-generics/generic_const_exprs/const-generics-closure.stderr @@ -0,0 +1,26 @@ +error[E0658]: `for<...>` binders for closures are experimental + --> $DIR/const-generics-closure.rs:6:17 + | +LL | let _ = for<'a, 'b> |x: &'a &'a Vec<&'b u32>, b: bool| -> &'a Vec<&'b u32> { *x }; + | ^^^^^^^^^^^ + | + = note: see issue #97362 for more information + = help: add `#![feature(closure_lifetime_binder)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = help: consider removing `for<...>` + +error[E0308]: mismatched types + --> $DIR/const-generics-closure.rs:4:10 + | +LL | [u8; { + | __________^ +LL | | +LL | | let _ = for<'a, 'b> |x: &'a &'a Vec<&'b u32>, b: bool| -> &'a Vec<&'b u32> { *x }; +LL | | +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/tests/ui/const-generics/generic_const_exprs/issue-72787.rs b/tests/ui/const-generics/generic_const_exprs/issue-72787.rs index c3208786708b..ea65b6d3fdf2 100644 --- a/tests/ui/const-generics/generic_const_exprs/issue-72787.rs +++ b/tests/ui/const-generics/generic_const_exprs/issue-72787.rs @@ -9,8 +9,8 @@ pub trait True {} impl True for IsLessOrEqual where Condition<{ LHS <= RHS }>: True -//[min]~^ Error generic parameters may not be used in const operations -//[min]~| Error generic parameters may not be used in const operations +//[min]~^ ERROR generic parameters may not be used in const operations +//[min]~| ERROR generic parameters may not be used in const operations { } impl True for Condition {} @@ -21,8 +21,8 @@ where IsLessOrEqual: True, IsLessOrEqual: True, IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, -//[min]~^ Error generic parameters may not be used in const operations -//[min]~| Error generic parameters may not be used in const operations +//[min]~^ ERROR generic parameters may not be used in const operations +//[min]~| ERROR generic parameters may not be used in const operations // Condition<{ 8 - I <= 8 - J }>: True, { fn print() { diff --git a/tests/ui/const-generics/generic_const_exprs/issue-79518-default_trait_method_normalization.rs b/tests/ui/const-generics/generic_const_exprs/issue-79518-default_trait_method_normalization.rs index 2fa9a71fbb33..f08b9ceffb96 100644 --- a/tests/ui/const-generics/generic_const_exprs/issue-79518-default_trait_method_normalization.rs +++ b/tests/ui/const-generics/generic_const_exprs/issue-79518-default_trait_method_normalization.rs @@ -14,7 +14,7 @@ trait Foo { [(); std::mem::size_of::()]: , { Self::AssocInstance == [(); std::mem::size_of::()]; - //~^ Error: mismatched types + //~^ ERROR mismatched types } } diff --git a/tests/ui/const-generics/issues/issue-68366.rs b/tests/ui/const-generics/issues/issue-68366.rs index d9d5e21857b1..6f745b260b63 100644 --- a/tests/ui/const-generics/issues/issue-68366.rs +++ b/tests/ui/const-generics/issues/issue-68366.rs @@ -11,7 +11,7 @@ struct Collatz>; impl Collatz<{Some(N)}> {} //~^ ERROR the const parameter -//[min]~^^ generic parameters may not be used in const operations +//[min]~^^ ERROR generic parameters may not be used in const operations //[full]~^^^ ERROR overly complex struct Foo; diff --git a/tests/ui/const-generics/issues/issue-74950.rs b/tests/ui/const-generics/issues/issue-74950.rs index f79676ccee8e..150566e98c04 100644 --- a/tests/ui/const-generics/issues/issue-74950.rs +++ b/tests/ui/const-generics/issues/issue-74950.rs @@ -17,9 +17,9 @@ struct Inner; // - impl StructuralPartialEq #[derive(PartialEq, Eq)] struct Outer; -//[min]~^ `Inner` is forbidden -//[min]~| `Inner` is forbidden -//[min]~| `Inner` is forbidden -//[min]~| `Inner` is forbidden +//[min]~^ ERROR `Inner` is forbidden +//[min]~| ERROR `Inner` is forbidden +//[min]~| ERROR `Inner` is forbidden +//[min]~| ERROR `Inner` is forbidden fn main() {} diff --git a/tests/ui/const-generics/issues/issue-90318.rs b/tests/ui/const-generics/issues/issue-90318.rs index cebc1ce21420..317ddad49cd4 100644 --- a/tests/ui/const-generics/issues/issue-90318.rs +++ b/tests/ui/const-generics/issues/issue-90318.rs @@ -12,7 +12,7 @@ impl True for If {} fn consume(_val: T) where If<{ TypeId::of::() != TypeId::of::<()>() }>: True, - //~^ overly complex generic constant + //~^ ERROR overly complex generic constant //~| ERROR: cannot call { } @@ -20,7 +20,7 @@ where fn test() where If<{ TypeId::of::() != TypeId::of::<()>() }>: True, - //~^ overly complex generic constant + //~^ ERROR overly complex generic constant //~| ERROR: cannot call { } diff --git a/tests/ui/consts/async-block.rs b/tests/ui/consts/async-block.rs index 1211a150f7d5..96881bc91340 100644 --- a/tests/ui/consts/async-block.rs +++ b/tests/ui/consts/async-block.rs @@ -10,9 +10,9 @@ use std::future::Future; // From const _: i32 = { core::mem::ManuallyDrop::new(async { 0 }); 4 }; -//[without_feature]~^ `async` block +//[without_feature]~^ ERROR `async` block static _FUT: &(dyn Future + Sync) = &async {}; -//[without_feature]~^ `async` block +//[without_feature]~^ ERROR `async` block fn main() {} diff --git a/tests/ui/consts/const-array-oob-arith.rs b/tests/ui/consts/const-array-oob-arith.rs index 0f6e76768cd1..8e5c56e0ea82 100644 --- a/tests/ui/consts/const-array-oob-arith.rs +++ b/tests/ui/consts/const-array-oob-arith.rs @@ -4,10 +4,10 @@ const VAL: i32 = ARR[IDX]; const BONG: [i32; (ARR[0] - 41) as usize] = [5]; const BLUB: [i32; (ARR[0] - 40) as usize] = [5]; //~^ ERROR: mismatched types -//~| expected an array +//~| NOTE expected an array const BOO: [i32; (ARR[0] - 41) as usize] = [5, 99]; //~^ ERROR: mismatched types -//~| expected an array +//~| NOTE expected an array fn main() { let _ = VAL; diff --git a/tests/ui/consts/const-blocks/const-block-in-array-size.rs b/tests/ui/consts/const-blocks/const-block-in-array-size.rs new file mode 100644 index 000000000000..ecab24322869 --- /dev/null +++ b/tests/ui/consts/const-blocks/const-block-in-array-size.rs @@ -0,0 +1,5 @@ +//@ check-pass + +type A = [u32; const { 2 }]; + +fn main() {} diff --git a/tests/ui/consts/const-cast-wrong-type.rs b/tests/ui/consts/const-cast-wrong-type.rs index 6e055a2bcd34..9936a660936b 100644 --- a/tests/ui/consts/const-cast-wrong-type.rs +++ b/tests/ui/consts/const-cast-wrong-type.rs @@ -1,5 +1,5 @@ const a: [u8; 3] = ['h' as u8, 'i' as u8, 0 as u8]; -const b: *const i8 = &a as *const i8; //~ ERROR mismatched types +const b: *const i8 = &a as *const i8; //~ ERROR casting `&[u8; 3]` as `*const i8` is invalid fn main() { } diff --git a/tests/ui/consts/const-cast-wrong-type.stderr b/tests/ui/consts/const-cast-wrong-type.stderr index 44361f15d8a9..0730bac22354 100644 --- a/tests/ui/consts/const-cast-wrong-type.stderr +++ b/tests/ui/consts/const-cast-wrong-type.stderr @@ -1,9 +1,9 @@ -error[E0308]: mismatched types +error[E0606]: casting `&[u8; 3]` as `*const i8` is invalid --> $DIR/const-cast-wrong-type.rs:2:22 | LL | const b: *const i8 = &a as *const i8; - | ^^^^^^^^^^^^^^^ expected `u8`, found `i8` + | ^^^^^^^^^^^^^^^ error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0308`. +For more information about this error, try `rustc --explain E0606`. diff --git a/tests/ui/consts/const-deref-ptr.rs b/tests/ui/consts/const-deref-ptr.rs index 2607d4de2291..c80cb95ea936 100644 --- a/tests/ui/consts/const-deref-ptr.rs +++ b/tests/ui/consts/const-deref-ptr.rs @@ -3,6 +3,6 @@ fn main() { static C: u64 = unsafe {*(0xdeadbeef as *const u64)}; //~^ ERROR could not evaluate static initializer - //~| dangling pointer + //~| NOTE dangling pointer println!("{}", C); } diff --git a/tests/ui/consts/const-err-enum-discriminant.rs b/tests/ui/consts/const-err-enum-discriminant.rs index ebb3e551ba81..42165ff53465 100644 --- a/tests/ui/consts/const-err-enum-discriminant.rs +++ b/tests/ui/consts/const-err-enum-discriminant.rs @@ -7,7 +7,7 @@ union Foo { enum Bar { Boo = [unsafe { Foo { b: () }.a }; 4][3], //~^ ERROR evaluation of constant value failed - //~| uninitialized + //~| NOTE uninitialized } fn main() { diff --git a/tests/ui/consts/const-eval/assign-to-static-within-other-static.rs b/tests/ui/consts/const-eval/assign-to-static-within-other-static.rs index ecf97223f6ad..30e40bd8be13 100644 --- a/tests/ui/consts/const-eval/assign-to-static-within-other-static.rs +++ b/tests/ui/consts/const-eval/assign-to-static-within-other-static.rs @@ -6,7 +6,7 @@ use std::cell::UnsafeCell; static mut FOO: u32 = 42; static BOO: () = unsafe { FOO = 5; - //~^ could not evaluate static initializer [E0080] + //~^ ERROR could not evaluate static initializer [E0080] }; fn main() {} diff --git a/tests/ui/consts/const-eval/const-eval-span.rs b/tests/ui/consts/const-eval/const-eval-span.rs index 1667c77d124c..f1904c76b6c1 100644 --- a/tests/ui/consts/const-eval/const-eval-span.rs +++ b/tests/ui/consts/const-eval/const-eval-span.rs @@ -8,7 +8,7 @@ const CONSTANT: S = S(0); enum E { V = CONSTANT, //~^ ERROR mismatched types - //~| expected `isize`, found `S` + //~| NOTE expected `isize`, found `S` } fn main() {} diff --git a/tests/ui/consts/const-eval/const_raw_ptr_ops2.rs b/tests/ui/consts/const-eval/const_raw_ptr_ops2.rs index ec5508a1e90c..ca96cfd9d193 100644 --- a/tests/ui/consts/const-eval/const_raw_ptr_ops2.rs +++ b/tests/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 a dangling pointer +//~| NOTE is a dangling pointer const Z3: i32 = unsafe { *(44 as *const i32) }; //~ ERROR evaluation of constant value failed -//~| is a dangling pointer +//~| NOTE is a dangling pointer diff --git a/tests/ui/consts/const-eval/issue-91827-extern-types-field-offset.rs b/tests/ui/consts/const-eval/issue-91827-extern-types-field-offset.rs index c6960fa7259d..3a932343ddda 100644 --- a/tests/ui/consts/const-eval/issue-91827-extern-types-field-offset.rs +++ b/tests/ui/consts/const-eval/issue-91827-extern-types-field-offset.rs @@ -37,7 +37,7 @@ const OFFSET: () = unsafe { // fails. let field = &x.a; //~^ ERROR: evaluation of constant value failed - //~| does not have a known offset + //~| NOTE does not have a known offset }; fn main() {} diff --git a/tests/ui/consts/const-eval/partial_ptr_overwrite.rs b/tests/ui/consts/const-eval/partial_ptr_overwrite.rs index 1e99d84bba4b..9438de5e3fe7 100644 --- a/tests/ui/consts/const-eval/partial_ptr_overwrite.rs +++ b/tests/ui/consts/const-eval/partial_ptr_overwrite.rs @@ -5,7 +5,7 @@ const PARTIAL_OVERWRITE: () = { unsafe { let ptr: *mut _ = &mut p; *(ptr as *mut u8) = 123; //~ ERROR constant - //~| unable to overwrite parts of a pointer + //~| NOTE unable to overwrite parts of a pointer } let x = *p; }; diff --git a/tests/ui/consts/const-eval/ub-enum-overwrite.rs b/tests/ui/consts/const-eval/ub-enum-overwrite.rs index 69f1d01b2f31..e37c25718f8e 100644 --- a/tests/ui/consts/const-eval/ub-enum-overwrite.rs +++ b/tests/ui/consts/const-eval/ub-enum-overwrite.rs @@ -10,7 +10,7 @@ const _: u8 = { e = E::B; unsafe { *p } //~^ ERROR evaluation of constant value failed - //~| uninitialized + //~| NOTE uninitialized }; fn main() {} diff --git a/tests/ui/consts/const-eval/ub-write-through-immutable.rs b/tests/ui/consts/const-eval/ub-write-through-immutable.rs index d3ae2d818848..795ac602a1c6 100644 --- a/tests/ui/consts/const-eval/ub-write-through-immutable.rs +++ b/tests/ui/consts/const-eval/ub-write-through-immutable.rs @@ -8,14 +8,14 @@ const WRITE_AFTER_CAST: () = unsafe { let mut x = 0; let ptr = &x as *const i32 as *mut i32; *ptr = 0; //~ERROR: evaluation of constant value failed - //~| immutable + //~| NOTE immutable }; const WRITE_AFTER_TRANSMUTE: () = unsafe { let mut x = 0; let ptr: *mut i32 = mem::transmute(&x); *ptr = 0; //~ERROR: evaluation of constant value failed - //~| immutable + //~| NOTE immutable }; // it's okay when there is interior mutability; diff --git a/tests/ui/consts/const-eval/union-ice.rs b/tests/ui/consts/const-eval/union-ice.rs index 1db9470912d3..8ce5f6d89a8f 100644 --- a/tests/ui/consts/const-eval/union-ice.rs +++ b/tests/ui/consts/const-eval/union-ice.rs @@ -13,13 +13,13 @@ const UNION: DummyUnion = DummyUnion { field1: 1065353216 }; const FIELD3: Field3 = unsafe { UNION.field3 }; //~^ ERROR evaluation of constant value failed -//~| uninitialized +//~| NOTE uninitialized const FIELD_PATH: Struct = Struct { a: 42, b: unsafe { UNION.field3 }, //~^ ERROR evaluation of constant value failed - //~| uninitialized + //~| NOTE uninitialized }; struct Struct { @@ -32,7 +32,7 @@ const FIELD_PATH2: Struct2 = Struct2 { 21, unsafe { UNION.field3 }, //~^ ERROR evaluation of constant value failed - //~| uninitialized + //~| NOTE uninitialized 23, 24, ], diff --git a/tests/ui/consts/const-eval/union_promotion.rs b/tests/ui/consts/const-eval/union_promotion.rs index 18894c45fd82..3868b0b18b1e 100644 --- a/tests/ui/consts/const-eval/union_promotion.rs +++ b/tests/ui/consts/const-eval/union_promotion.rs @@ -5,7 +5,7 @@ union Foo { } fn main() { - let x: &'static bool = &unsafe { //~ temporary value dropped while borrowed + let x: &'static bool = &unsafe { //~ ERROR temporary value dropped while borrowed Foo { a: &1 }.b == Foo { a: &2 }.b }; } diff --git a/tests/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.rs b/tests/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.rs index a77ee2938207..89a8d1429b4d 100644 --- a/tests/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.rs +++ b/tests/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.rs @@ -8,11 +8,11 @@ const unsafe extern "C-unwind" fn bar() -> usize { fn main() { let a: [u8; foo()]; - //~^ call to unsafe function `foo` is unsafe and requires unsafe function or block + //~^ ERROR call to unsafe function `foo` is unsafe and requires unsafe function or block foo(); //~^ ERROR call to unsafe function `foo` is unsafe and requires unsafe function or block let b: [u8; bar()]; - //~^ call to unsafe function `bar` is unsafe and requires unsafe function or block + //~^ ERROR call to unsafe function `bar` is unsafe and requires unsafe function or block bar(); //~^ ERROR call to unsafe function `bar` is unsafe and requires unsafe function or block } diff --git a/tests/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier-2.rs b/tests/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier-2.rs index 7ced24808bf6..50728970be2c 100644 --- a/tests/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier-2.rs +++ b/tests/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier-2.rs @@ -1,6 +1,6 @@ fn main() {} -#[cfg(FALSE)] +#[cfg(false)] fn container() { const unsafe WhereIsFerris Now() {} //~^ ERROR expected one of `extern` or `fn` diff --git a/tests/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier.rs b/tests/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier.rs index 6f575d055a29..20e79ca200bb 100644 --- a/tests/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier.rs +++ b/tests/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier.rs @@ -1,6 +1,6 @@ fn main() {} -#[cfg(FALSE)] +#[cfg(false)] fn container() { const extern "Rust" PUT_ANYTHING_YOU_WANT_HERE bug() -> usize { 1 } //~^ ERROR expected `fn` diff --git a/tests/ui/consts/const-integer-bool-ops.rs b/tests/ui/consts/const-integer-bool-ops.rs index 35915a7a606a..fbbd51adfe88 100644 --- a/tests/ui/consts/const-integer-bool-ops.rs +++ b/tests/ui/consts/const-integer-bool-ops.rs @@ -1,67 +1,67 @@ const X: usize = 42 && 39; //~^ ERROR mismatched types -//~| expected `bool`, found integer +//~| NOTE expected `bool`, found integer //~| ERROR mismatched types -//~| expected `bool`, found integer +//~| NOTE expected `bool`, found integer //~| ERROR mismatched types -//~| expected `usize`, found `bool` +//~| NOTE expected `usize`, found `bool` const ARR: [i32; X] = [99; 34]; const X1: usize = 42 || 39; //~^ ERROR mismatched types -//~| expected `bool`, found integer +//~| NOTE expected `bool`, found integer //~| ERROR mismatched types -//~| expected `bool`, found integer +//~| NOTE expected `bool`, found integer //~| ERROR mismatched types -//~| expected `usize`, found `bool` +//~| NOTE expected `usize`, found `bool` const ARR1: [i32; X1] = [99; 47]; const X2: usize = -42 || -39; //~^ ERROR mismatched types -//~| expected `bool`, found integer +//~| NOTE expected `bool`, found integer //~| ERROR mismatched types -//~| expected `bool`, found integer +//~| NOTE expected `bool`, found integer //~| ERROR mismatched types -//~| expected `usize`, found `bool` +//~| NOTE expected `usize`, found `bool` const ARR2: [i32; X2] = [99; 18446744073709551607]; const X3: usize = -42 && -39; //~^ ERROR mismatched types -//~| expected `bool`, found integer +//~| NOTE expected `bool`, found integer //~| ERROR mismatched types -//~| expected `bool`, found integer +//~| NOTE expected `bool`, found integer //~| ERROR mismatched types -//~| expected `usize`, found `bool` +//~| NOTE expected `usize`, found `bool` const ARR3: [i32; X3] = [99; 6]; const Y: usize = 42.0 == 42.0; //~^ ERROR mismatched types -//~| expected `usize`, found `bool` +//~| NOTE expected `usize`, found `bool` const ARRR: [i32; Y] = [99; 1]; const Y1: usize = 42.0 >= 42.0; //~^ ERROR mismatched types -//~| expected `usize`, found `bool` +//~| NOTE expected `usize`, found `bool` const ARRR1: [i32; Y1] = [99; 1]; const Y2: usize = 42.0 <= 42.0; //~^ ERROR mismatched types -//~| expected `usize`, found `bool` +//~| NOTE expected `usize`, found `bool` const ARRR2: [i32; Y2] = [99; 1]; const Y3: usize = 42.0 > 42.0; //~^ ERROR mismatched types -//~| expected `usize`, found `bool` +//~| NOTE expected `usize`, found `bool` const ARRR3: [i32; Y3] = [99; 0]; const Y4: usize = 42.0 < 42.0; //~^ ERROR mismatched types -//~| expected `usize`, found `bool` +//~| NOTE expected `usize`, found `bool` const ARRR4: [i32; Y4] = [99; 0]; const Y5: usize = 42.0 != 42.0; //~^ ERROR mismatched types -//~| expected `usize`, found `bool` +//~| NOTE expected `usize`, found `bool` const ARRR5: [i32; Y5] = [99; 0]; fn main() { diff --git a/tests/ui/consts/const-len-underflow-subspans.rs b/tests/ui/consts/const-len-underflow-subspans.rs index ed77e9078425..5afb1bf89d09 100644 --- a/tests/ui/consts/const-len-underflow-subspans.rs +++ b/tests/ui/consts/const-len-underflow-subspans.rs @@ -7,5 +7,5 @@ const TWO: usize = 2; fn main() { let a: [i8; ONE - TWO] = unimplemented!(); //~^ ERROR evaluation of constant value failed - //~| attempt to compute `1_usize - 2_usize`, which would overflow + //~| NOTE attempt to compute `1_usize - 2_usize`, which would overflow } diff --git a/tests/ui/consts/const-slice-oob.rs b/tests/ui/consts/const-slice-oob.rs index 429b97821321..09202df72c0f 100644 --- a/tests/ui/consts/const-slice-oob.rs +++ b/tests/ui/consts/const-slice-oob.rs @@ -1,6 +1,6 @@ const FOO: &'static[u32] = &[1, 2, 3]; const BAR: u32 = FOO[5]; -//~^ index out of bounds: the length is 3 but the index is 5 +//~^ NOTE index out of bounds: the length is 3 but the index is 5 //~| ERROR evaluation of constant value failed fn main() { diff --git a/tests/ui/consts/const-suggest-feature.rs b/tests/ui/consts/const-suggest-feature.rs index 0c9403689761..dbb166dd6c5d 100644 --- a/tests/ui/consts/const-suggest-feature.rs +++ b/tests/ui/consts/const-suggest-feature.rs @@ -1,4 +1,4 @@ -//@compile-flags: --edition 2018 +//@ edition: 2018 use std::cell::Cell; const WRITE: () = unsafe { diff --git a/tests/ui/consts/const_in_pattern/reject_non_structural.rs b/tests/ui/consts/const_in_pattern/reject_non_structural.rs index 39e5f732a898..6478bf9c6ee1 100644 --- a/tests/ui/consts/const_in_pattern/reject_non_structural.rs +++ b/tests/ui/consts/const_in_pattern/reject_non_structural.rs @@ -93,6 +93,7 @@ fn main() { //~| NOTE constant of non-structural type trait Trait: Sized { const ASSOC: Option; } //~ NOTE constant defined here + //~^ NOTE impl Trait for NoDerive { const ASSOC: Option = Some(NoDerive); } match Some(NoDerive) { NoDerive::ASSOC => dbg!(NoDerive::ASSOC), _ => panic!("whoops"), }; //~^ ERROR constant of non-structural type `NoDerive` in a pattern diff --git a/tests/ui/consts/const_in_pattern/reject_non_structural.stderr b/tests/ui/consts/const_in_pattern/reject_non_structural.stderr index fa16d0b06a7f..bf54d3d76aed 100644 --- a/tests/ui/consts/const_in_pattern/reject_non_structural.stderr +++ b/tests/ui/consts/const_in_pattern/reject_non_structural.stderr @@ -118,14 +118,14 @@ LL | impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: constant of non-structural type `NoDerive` in a pattern - --> $DIR/reject_non_structural.rs:97:28 + --> $DIR/reject_non_structural.rs:98:28 | LL | struct NoDerive; | --------------- `NoDerive` must be annotated with `#[derive(PartialEq)]` to be usable in patterns ... LL | trait Trait: Sized { const ASSOC: Option; } | ------------------ ------------------------- constant defined here -LL | impl Trait for NoDerive { const ASSOC: Option = Some(NoDerive); } +... LL | match Some(NoDerive) { NoDerive::ASSOC => dbg!(NoDerive::ASSOC), _ => panic!("whoops"), }; | ^^^^^^^^^^^^^^^ constant of non-structural type | @@ -136,7 +136,7 @@ LL | impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: constant of non-structural type `NoDerive` in a pattern - --> $DIR/reject_non_structural.rs:102:28 + --> $DIR/reject_non_structural.rs:103:28 | LL | struct NoDerive; | --------------- `NoDerive` must be annotated with `#[derive(PartialEq)]` to be usable in patterns @@ -153,7 +153,7 @@ LL | impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: constant of non-structural type `NoDerive` in a pattern - --> $DIR/reject_non_structural.rs:107:29 + --> $DIR/reject_non_structural.rs:108:29 | LL | struct NoDerive; | --------------- `NoDerive` must be annotated with `#[derive(PartialEq)]` to be usable in patterns diff --git a/tests/ui/consts/copy-intrinsic.rs b/tests/ui/consts/copy-intrinsic.rs index 08fbcc107e7e..5ae467878001 100644 --- a/tests/ui/consts/copy-intrinsic.rs +++ b/tests/ui/consts/copy-intrinsic.rs @@ -32,7 +32,7 @@ const COPY_OOB_1: () = unsafe { copy_nonoverlapping(0x100 as *const i32, dangle, 0); // Non-zero-sized copy is not. copy_nonoverlapping(0x100 as *const i32, dangle, 1); //~ ERROR evaluation of constant value failed [E0080] - //~| got 0x100[noalloc] which is a dangling pointer + //~| NOTE got 0x100[noalloc] which is a dangling pointer }; const COPY_OOB_2: () = unsafe { let x = 0i32; @@ -41,20 +41,20 @@ const COPY_OOB_2: () = unsafe { copy_nonoverlapping(dangle, 0x100 as *mut i32, 0); // Non-zero-sized copy is not. copy_nonoverlapping(dangle, 0x100 as *mut i32, 1); //~ ERROR evaluation of constant value failed [E0080] - //~| +0x28 which is at or beyond the end of the allocation + //~| NOTE +0x28 which is at or beyond the end of the allocation }; const COPY_SIZE_OVERFLOW: () = unsafe { let x = 0; let mut y = 0; copy(&x, &mut y, 1usize << (mem::size_of::() * 8 - 1)); //~ ERROR evaluation of constant value failed [E0080] - //~| overflow computing total size of `copy` + //~| NOTE overflow computing total size of `copy` }; const COPY_NONOVERLAPPING_SIZE_OVERFLOW: () = unsafe { let x = 0; let mut y = 0; - copy_nonoverlapping(&x, &mut y, 1usize << (mem::size_of::() * 8 - 1)); //~ evaluation of constant value failed [E0080] - //~| overflow computing total size of `copy_nonoverlapping` + copy_nonoverlapping(&x, &mut y, 1usize << (mem::size_of::() * 8 - 1)); //~ ERROR evaluation of constant value failed [E0080] + //~| NOTE overflow computing total size of `copy_nonoverlapping` }; fn main() { diff --git a/tests/ui/consts/drop_zst.rs b/tests/ui/consts/drop_zst.rs index 40c66043f9fd..daf8f1b0343d 100644 --- a/tests/ui/consts/drop_zst.rs +++ b/tests/ui/consts/drop_zst.rs @@ -11,7 +11,7 @@ impl Drop for S { } const fn foo() { - let s = S; //~ destructor + let s = S; //~ ERROR destructor } fn main() {} diff --git a/tests/ui/consts/eval-enum.rs b/tests/ui/consts/eval-enum.rs index 551f10e66e35..fa9ad6736e29 100644 --- a/tests/ui/consts/eval-enum.rs +++ b/tests/ui/consts/eval-enum.rs @@ -1,9 +1,9 @@ enum Test { DivZero = 1/0, - //~^ attempt to divide `1_isize` by zero + //~^ NOTE attempt to divide `1_isize` by zero //~| ERROR evaluation of constant value failed RemZero = 1%0, - //~^ attempt to calculate the remainder of `1_isize` with a divisor of zero + //~^ NOTE attempt to calculate the remainder of `1_isize` with a divisor of zero //~| ERROR evaluation of constant value failed } diff --git a/tests/ui/consts/extra-const-ub/detect-extra-ub.rs b/tests/ui/consts/extra-const-ub/detect-extra-ub.rs index d2b157e03e7c..481f2ff88df6 100644 --- a/tests/ui/consts/extra-const-ub/detect-extra-ub.rs +++ b/tests/ui/consts/extra-const-ub/detect-extra-ub.rs @@ -28,32 +28,32 @@ enum UninhDiscriminant { const INVALID_BOOL: () = unsafe { let _x: bool = transmute(3u8); //[with_flag]~^ ERROR: evaluation of constant value failed - //[with_flag]~| invalid value + //[with_flag]~| NOTE invalid value }; const INVALID_PTR_IN_INT: () = unsafe { let _x: usize = transmute(&3u8); //[with_flag]~^ ERROR: evaluation of constant value failed - //[with_flag]~| invalid value + //[with_flag]~| NOTE invalid value }; const INVALID_PTR_IN_ENUM: () = unsafe { let _x: PtrSizedEnum = transmute(&3u8); //[with_flag]~^ ERROR: evaluation of constant value failed - //[with_flag]~| invalid value + //[with_flag]~| NOTE invalid value }; const INVALID_SLICE_TO_USIZE_TRANSMUTE: () = unsafe { let x: &[u8] = &[0; 32]; let _x: (usize, usize) = transmute(x); //[with_flag]~^ ERROR: evaluation of constant value failed - //[with_flag]~| invalid value + //[with_flag]~| NOTE invalid value }; const UNALIGNED_PTR: () = unsafe { let _x: &u32 = transmute(&[0u8; 4]); //[with_flag]~^ ERROR: evaluation of constant value failed - //[with_flag]~| invalid value + //[with_flag]~| NOTE invalid value }; const UNINHABITED_VARIANT: () = unsafe { @@ -61,7 +61,7 @@ const UNINHABITED_VARIANT: () = unsafe { // Not using transmute, we want to hit the ImmTy code path. let v = *addr_of!(data).cast::(); //[with_flag]~^ ERROR: evaluation of constant value failed - //[with_flag]~| invalid value + //[with_flag]~| NOTE invalid value }; const PARTIAL_POINTER: () = unsafe { @@ -81,7 +81,7 @@ const PARTIAL_POINTER: () = unsafe { let mem = Align { p: mem, align: 0 }; let _val = *(&mem as *const Align as *const [*const u8; 2]); //[with_flag]~^ ERROR: evaluation of constant value failed - //[with_flag]~| invalid value + //[with_flag]~| NOTE invalid value }; // Regression tests for an ICE (related to ). @@ -96,7 +96,7 @@ const OVERSIZED_REF: () = { unsafe { let slice: *const [u8] = transmute((1usize, usize::MAX)); let _val = &*slice; //[with_flag]~^ ERROR: evaluation of constant value failed - //[with_flag]~| slice is bigger than largest supported object + //[with_flag]~| NOTE slice is bigger than largest supported object } }; fn main() {} diff --git a/tests/ui/consts/issue-19244-2.rs b/tests/ui/consts/issue-19244-2.rs index c9a68b05c5ba..87f8c1581a75 100644 --- a/tests/ui/consts/issue-19244-2.rs +++ b/tests/ui/consts/issue-19244-2.rs @@ -3,5 +3,5 @@ const STRUCT: MyStruct = MyStruct { field: 42 }; fn main() { let a: [isize; STRUCT.nonexistent_field]; - //~^ no field `nonexistent_field` on type `MyStruct` + //~^ ERROR no field `nonexistent_field` on type `MyStruct` } diff --git a/tests/ui/consts/min_const_fn/min_const_fn.rs b/tests/ui/consts/min_const_fn/min_const_fn.rs index e6d9d184e041..38ca10858b19 100644 --- a/tests/ui/consts/min_const_fn/min_const_fn.rs +++ b/tests/ui/consts/min_const_fn/min_const_fn.rs @@ -34,13 +34,13 @@ const fn foo35(a: bool, b: bool) -> bool { a ^ b } struct Foo(T); impl Foo { const fn new(t: T) -> Self { Foo(t) } - const fn into_inner(self) -> T { self.0 } //~ destructor of + const fn into_inner(self) -> T { self.0 } //~ ERROR destructor of const fn get(&self) -> &T { &self.0 } const fn get_mut(&mut self) -> &mut T { &mut self.0 } } impl<'a, T> Foo { const fn new_lt(t: T) -> Self { Foo(t) } - const fn into_inner_lt(self) -> T { self.0 } //~ destructor of + const fn into_inner_lt(self) -> T { self.0 } //~ ERROR destructor of const fn get_lt(&self) -> &T { &self.0 } const fn get_mut_lt(&mut self) -> &mut T { &mut self.0 } } diff --git a/tests/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs b/tests/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs index d6f07994e820..8f2bcd82c73f 100644 --- a/tests/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs +++ b/tests/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs @@ -1,4 +1,4 @@ -//@ compile-flags: --edition 2018 +//@ edition: 2018 #![unstable(feature = "humans", reason = "who ever let humans program computers, we're apparently really bad at it", diff --git a/tests/ui/consts/miri_unleashed/drop.rs b/tests/ui/consts/miri_unleashed/drop.rs index 17d089222d96..190072d9c206 100644 --- a/tests/ui/consts/miri_unleashed/drop.rs +++ b/tests/ui/consts/miri_unleashed/drop.rs @@ -1,5 +1,4 @@ //@ compile-flags: -Zunleash-the-miri-inside-of-you -//@ error-pattern: calling non-const function ` as Drop>::drop` use std::mem::ManuallyDrop; @@ -15,5 +14,7 @@ static TEST_OK: () = { static TEST_BAD: () = { let _v: Vec = Vec::new(); }; //~ ERROR could not evaluate static initializer + //~| NOTE calling non-const function ` as Drop>::drop` + //~| NOTE inside `std::ptr::drop_in_place::> - shim(Some(Vec))` //~? WARN skipping const checks diff --git a/tests/ui/consts/miri_unleashed/drop.stderr b/tests/ui/consts/miri_unleashed/drop.stderr index 40a29d5a819a..f9ff5491ea6c 100644 --- a/tests/ui/consts/miri_unleashed/drop.stderr +++ b/tests/ui/consts/miri_unleashed/drop.stderr @@ -1,5 +1,5 @@ error[E0080]: could not evaluate static initializer - --> $DIR/drop.rs:17:1 + --> $DIR/drop.rs:16:1 | LL | }; | ^ calling non-const function ` as Drop>::drop` @@ -10,7 +10,7 @@ note: inside `std::ptr::drop_in_place::> - shim(Some(Vec))` warning: skipping const checks | help: skipping check that does not even have a feature gate - --> $DIR/drop.rs:16:9 + --> $DIR/drop.rs:15:9 | LL | let _v: Vec = Vec::new(); | ^^ diff --git a/tests/ui/consts/miri_unleashed/ptr_arith.rs b/tests/ui/consts/miri_unleashed/ptr_arith.rs index 4e1183220792..408aa5db24d1 100644 --- a/tests/ui/consts/miri_unleashed/ptr_arith.rs +++ b/tests/ui/consts/miri_unleashed/ptr_arith.rs @@ -6,7 +6,7 @@ static PTR_INT_CAST: () = { let x = &0 as *const _ as usize; //~^ ERROR could not evaluate static initializer - //~| exposing pointers + //~| NOTE exposing pointers let _v = x == x; }; @@ -14,7 +14,7 @@ static PTR_INT_TRANSMUTE: () = unsafe { let x: usize = std::mem::transmute(&0); let _v = x + 0; //~^ ERROR could not evaluate static initializer - //~| unable to turn pointer into integer + //~| NOTE unable to turn pointer into integer }; // I'd love to test pointer comparison, but that is not possible since diff --git a/tests/ui/consts/missing_span_in_backtrace.stderr b/tests/ui/consts/missing_span_in_backtrace.stderr index 2f3a65302bd5..aad3d76dd269 100644 --- a/tests/ui/consts/missing_span_in_backtrace.stderr +++ b/tests/ui/consts/missing_span_in_backtrace.stderr @@ -12,10 +12,10 @@ note: inside `swap_nonoverlapping::>` --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL note: inside `swap_nonoverlapping::compiletime::>` --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL -note: inside `std::ptr::swap_nonoverlapping_simple_untyped::>` - --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL -note: inside `std::ptr::read::>>` +note: inside `std::ptr::swap_nonoverlapping_const::>` --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL +note: inside `copy_nonoverlapping::>` + --> $SRC_DIR/core/src/intrinsics/mod.rs:LL:COL = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported = note: this error originates in the macro `$crate::intrinsics::const_eval_select` which comes from the expansion of the macro `const_eval_select` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/consts/no-ice-from-static-in-const-issue-52060.rs b/tests/ui/consts/no-ice-from-static-in-const-issue-52060.rs index e0f9e462d32e..e3cd8ec7d8a6 100644 --- a/tests/ui/consts/no-ice-from-static-in-const-issue-52060.rs +++ b/tests/ui/consts/no-ice-from-static-in-const-issue-52060.rs @@ -4,6 +4,6 @@ static mut A: &'static [u32] = &[1]; static B: [u32; 1] = [0; unsafe { A.len() }]; //~^ ERROR: evaluation of constant value failed -//~| mutable global memory +//~| NOTE mutable global memory fn main() {} diff --git a/tests/ui/consts/promoted_running_out_of_memory_issue-130687.rs b/tests/ui/consts/promoted_running_out_of_memory_issue-130687.rs index 75765596fa17..e458a6f98adf 100644 --- a/tests/ui/consts/promoted_running_out_of_memory_issue-130687.rs +++ b/tests/ui/consts/promoted_running_out_of_memory_issue-130687.rs @@ -12,6 +12,6 @@ pub struct Data([u8; (1 << 47) - 1]); const _: &'static Data = &Data([0; (1 << 47) - 1]); //~^ERROR: evaluation of constant value failed -//~| tried to allocate more memory than available to compiler +//~| NOTE tried to allocate more memory than available to compiler fn main() {} diff --git a/tests/ui/consts/promoted_size_overflow.rs b/tests/ui/consts/promoted_size_overflow.rs index 3d606905e782..ebd5ab064871 100644 --- a/tests/ui/consts/promoted_size_overflow.rs +++ b/tests/ui/consts/promoted_size_overflow.rs @@ -2,6 +2,6 @@ pub struct Data([u8; usize::MAX >> 2]); const _: &'static [Data] = &[]; //~^ERROR: evaluation of constant value failed -//~| too big for the target architecture +//~| NOTE too big for the target architecture fn main() {} diff --git a/tests/ui/consts/recursive-zst-static.rs b/tests/ui/consts/recursive-zst-static.rs index 53d32254a684..a52624fada8d 100644 --- a/tests/ui/consts/recursive-zst-static.rs +++ b/tests/ui/consts/recursive-zst-static.rs @@ -10,7 +10,7 @@ static FOO: () = FOO; //~^ ERROR could not evaluate static initializer -static A: () = B; //~ cycle detected when evaluating initializer of static `A` +static A: () = B; //~ ERROR cycle detected when evaluating initializer of static `A` static B: () = A; fn main() { diff --git a/tests/ui/consts/slice-index-overflow-issue-130284.rs b/tests/ui/consts/slice-index-overflow-issue-130284.rs index 299009082563..6877ebe14768 100644 --- a/tests/ui/consts/slice-index-overflow-issue-130284.rs +++ b/tests/ui/consts/slice-index-overflow-issue-130284.rs @@ -6,7 +6,7 @@ const C: () = { // This used to ICE, but it should just report UB. let _ice = (*fat)[usize::MAX - 1]; //~^ERROR: constant value failed - //~| overflow + //~| NOTE overflow } }; diff --git a/tests/ui/consts/static-default-lifetime/elided-lifetime.rs b/tests/ui/consts/static-default-lifetime/elided-lifetime.rs index ccf63f86fcf3..d60fe7d409af 100644 --- a/tests/ui/consts/static-default-lifetime/elided-lifetime.rs +++ b/tests/ui/consts/static-default-lifetime/elided-lifetime.rs @@ -16,7 +16,7 @@ impl Bar for Foo<'_> { const STATIC: &str = ""; //~^ ERROR `&` without an explicit lifetime name cannot be used here //~| WARN this was previously accepted by the compiler but is being phased out - //~| ERROR lifetime parameters or bounds on const `STATIC` do not match the trait declaration + //~| ERROR lifetime parameters or bounds on associated const `STATIC` do not match the trait declaration } fn main() {} diff --git a/tests/ui/consts/static-default-lifetime/elided-lifetime.stderr b/tests/ui/consts/static-default-lifetime/elided-lifetime.stderr index 33873f5c5a50..bb8365b0ae56 100644 --- a/tests/ui/consts/static-default-lifetime/elided-lifetime.stderr +++ b/tests/ui/consts/static-default-lifetime/elided-lifetime.stderr @@ -39,14 +39,14 @@ help: use the `'static` lifetime LL | const STATIC: &'static str = ""; | +++++++ -error[E0195]: lifetime parameters or bounds on const `STATIC` do not match the trait declaration +error[E0195]: lifetime parameters or bounds on associated const `STATIC` do not match the trait declaration --> $DIR/elided-lifetime.rs:16:17 | LL | const STATIC: &str; - | - lifetimes in impl do not match this const in trait + | - lifetimes in impl do not match this associated const in trait ... LL | const STATIC: &str = ""; - | ^ lifetimes do not match const in trait + | ^ lifetimes do not match associated const in trait error: aborting due to 3 previous errors diff --git a/tests/ui/consts/static-default-lifetime/static-trait-impl.rs b/tests/ui/consts/static-default-lifetime/static-trait-impl.rs index 1e12259e4833..85746df146fc 100644 --- a/tests/ui/consts/static-default-lifetime/static-trait-impl.rs +++ b/tests/ui/consts/static-default-lifetime/static-trait-impl.rs @@ -9,7 +9,7 @@ impl Bar<'_> for A { const STATIC: &str = ""; //~^ ERROR `&` without an explicit lifetime name cannot be used here //~| WARN this was previously accepted by the compiler but is being phased out - //~| ERROR lifetime parameters or bounds on const `STATIC` do not match the trait declaration + //~| ERROR lifetime parameters or bounds on associated const `STATIC` do not match the trait declaration } struct B; diff --git a/tests/ui/consts/static-default-lifetime/static-trait-impl.stderr b/tests/ui/consts/static-default-lifetime/static-trait-impl.stderr index 116f28e84847..38d24db1317f 100644 --- a/tests/ui/consts/static-default-lifetime/static-trait-impl.stderr +++ b/tests/ui/consts/static-default-lifetime/static-trait-impl.stderr @@ -21,14 +21,14 @@ help: use the `'static` lifetime LL | const STATIC: &'static str = ""; | +++++++ -error[E0195]: lifetime parameters or bounds on const `STATIC` do not match the trait declaration +error[E0195]: lifetime parameters or bounds on associated const `STATIC` do not match the trait declaration --> $DIR/static-trait-impl.rs:9:17 | LL | const STATIC: &'a str; - | - lifetimes in impl do not match this const in trait + | - lifetimes in impl do not match this associated const in trait ... LL | const STATIC: &str = ""; - | ^ lifetimes do not match const in trait + | ^ lifetimes do not match associated const in trait error: aborting due to 2 previous errors diff --git a/tests/ui/contracts/contract-captures-via-closure-noncopy.stderr b/tests/ui/contracts/contract-captures-via-closure-noncopy.stderr index 4a47671fee19..b6f2e014e0a8 100644 --- a/tests/ui/contracts/contract-captures-via-closure-noncopy.stderr +++ b/tests/ui/contracts/contract-captures-via-closure-noncopy.stderr @@ -16,6 +16,7 @@ LL | #[core::contracts::ensures({let old = x; move |ret:&Baz| ret.baz == old.baz | | within this `{closure@$DIR/contract-captures-via-closure-noncopy.rs:12:42: 12:57}` | | this tail expression is of type `{closure@contract-captures-via-closure-noncopy.rs:12:42}` | unsatisfied trait bound + | required by a bound introduced by this call | = help: within `{closure@$DIR/contract-captures-via-closure-noncopy.rs:12:42: 12:57}`, the trait `std::marker::Copy` is not implemented for `Baz` note: required because it's used within this closure diff --git a/tests/ui/contracts/contract-const-fn.all_pass.stderr b/tests/ui/contracts/contract-const-fn.all_pass.stderr new file mode 100644 index 000000000000..e5b1df655823 --- /dev/null +++ b/tests/ui/contracts/contract-const-fn.all_pass.stderr @@ -0,0 +1,11 @@ +warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/contract-const-fn.rs:17:12 + | +LL | #![feature(contracts)] + | ^^^^^^^^^ + | + = note: see issue #128044 for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/contracts/contract-const-fn.rs b/tests/ui/contracts/contract-const-fn.rs new file mode 100644 index 000000000000..733a06ae5709 --- /dev/null +++ b/tests/ui/contracts/contract-const-fn.rs @@ -0,0 +1,56 @@ +//! Check if we can annotate a constant function with contracts. +//! +//! The contract is only checked at runtime, and it will not fail if evaluated statically. +//! This is an existing limitation due to the existing architecture and the lack of constant +//! closures. +//! +//@ revisions: all_pass runtime_fail_pre runtime_fail_post +// +//@ [all_pass] run-pass +// +//@ [runtime_fail_pre] run-fail +//@ [runtime_fail_post] run-fail +// +//@ [all_pass] compile-flags: -Zcontract-checks=yes +//@ [runtime_fail_pre] compile-flags: -Zcontract-checks=yes +//@ [runtime_fail_post] compile-flags: -Zcontract-checks=yes +#![feature(contracts)] +//~^ WARN the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features] + +extern crate core; +use core::contracts::*; + +#[requires(x < 100)] +const fn less_than_100(x: u8) -> u8 { + x +} + +// This is wrong on purpose. +#[ensures(|ret| *ret)] +const fn always_true(b: bool) -> bool { + b +} + +const ZERO: u8 = less_than_100(0); +// This is no-op because the contract cannot be checked at compilation time. +const TWO_HUNDRED: u8 = less_than_100(200); + +/// Example from . +#[ensures(move |ret: &u32| *ret > x)] +const fn broken_sum(x: u32, y: u32) -> u32 { + x + y +} + +fn main() { + assert_eq!(ZERO, 0); + assert_eq!(TWO_HUNDRED, 200); + assert_eq!(broken_sum(0, 1), 1); + assert_eq!(always_true(true), true); + + #[cfg(runtime_fail_post)] + let _ok = always_true(false); + + // Runtime check should fail. + #[cfg(runtime_fail_pre)] + let _200 = less_than_100(200); +} diff --git a/tests/ui/contracts/contract-const-fn.runtime_fail_post.stderr b/tests/ui/contracts/contract-const-fn.runtime_fail_post.stderr new file mode 100644 index 000000000000..e5b1df655823 --- /dev/null +++ b/tests/ui/contracts/contract-const-fn.runtime_fail_post.stderr @@ -0,0 +1,11 @@ +warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/contract-const-fn.rs:17:12 + | +LL | #![feature(contracts)] + | ^^^^^^^^^ + | + = note: see issue #128044 for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/contracts/contract-const-fn.runtime_fail_pre.stderr b/tests/ui/contracts/contract-const-fn.runtime_fail_pre.stderr new file mode 100644 index 000000000000..e5b1df655823 --- /dev/null +++ b/tests/ui/contracts/contract-const-fn.runtime_fail_pre.stderr @@ -0,0 +1,11 @@ +warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/contract-const-fn.rs:17:12 + | +LL | #![feature(contracts)] + | ^^^^^^^^^ + | + = note: see issue #128044 for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/contracts/internal_machinery/contract-intrinsics.rs b/tests/ui/contracts/internal_machinery/contract-intrinsics.rs index ae692afd146f..c62b8cca75ab 100644 --- a/tests/ui/contracts/internal_machinery/contract-intrinsics.rs +++ b/tests/ui/contracts/internal_machinery/contract-intrinsics.rs @@ -26,11 +26,11 @@ fn main() { #[cfg(any(default, unchk_pass, chk_fail_requires))] core::intrinsics::contract_check_requires(|| false); - let doubles_to_two = { let old = 2; move |ret| ret + ret == old }; + let doubles_to_two = { let old = 2; move |ret: &u32 | ret + ret == old }; // Always pass - core::intrinsics::contract_check_ensures(&1, doubles_to_two); + core::intrinsics::contract_check_ensures(doubles_to_two, 1); // Fail if enabled #[cfg(any(default, unchk_pass, chk_fail_ensures))] - core::intrinsics::contract_check_ensures(&2, doubles_to_two); + core::intrinsics::contract_check_ensures(doubles_to_two, 2); } diff --git a/tests/ui/contracts/internal_machinery/contract-lang-items.rs b/tests/ui/contracts/internal_machinery/contract-lang-items.rs index e91bbed294d1..73c591945310 100644 --- a/tests/ui/contracts/internal_machinery/contract-lang-items.rs +++ b/tests/ui/contracts/internal_machinery/contract-lang-items.rs @@ -15,14 +15,14 @@ #![feature(contracts)] // to access core::contracts //~^ WARN the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features] #![feature(contracts_internals)] // to access check_requires lang item - +#![feature(core_intrinsics)] fn foo(x: Baz) -> i32 { let injected_checker = { core::contracts::build_check_ensures(|ret| *ret > 100) }; let ret = x.baz + 50; - injected_checker(ret) + core::intrinsics::contract_check_ensures(injected_checker, ret) } struct Baz { baz: i32 } diff --git a/tests/ui/contracts/internal_machinery/internal-feature-gating.rs b/tests/ui/contracts/internal_machinery/internal-feature-gating.rs index 1b76eef6780f..6e5a7a3f9500 100644 --- a/tests/ui/contracts/internal_machinery/internal-feature-gating.rs +++ b/tests/ui/contracts/internal_machinery/internal-feature-gating.rs @@ -6,7 +6,7 @@ fn main() { //~^ ERROR use of unstable library feature `contracts_internals` core::intrinsics::contract_check_requires(|| true); //~^ ERROR use of unstable library feature `contracts_internals` - core::intrinsics::contract_check_ensures(&1, |_|true); + core::intrinsics::contract_check_ensures( |_|true, &1); //~^ ERROR use of unstable library feature `contracts_internals` core::contracts::build_check_ensures(|_: &()| true); diff --git a/tests/ui/contracts/internal_machinery/internal-feature-gating.stderr b/tests/ui/contracts/internal_machinery/internal-feature-gating.stderr index 7302694a7874..1e39bd62e245 100644 --- a/tests/ui/contracts/internal_machinery/internal-feature-gating.stderr +++ b/tests/ui/contracts/internal_machinery/internal-feature-gating.stderr @@ -41,7 +41,7 @@ LL | core::intrinsics::contract_check_requires(|| true); error[E0658]: use of unstable library feature `contracts_internals` --> $DIR/internal-feature-gating.rs:9:5 | -LL | core::intrinsics::contract_check_ensures(&1, |_|true); +LL | core::intrinsics::contract_check_ensures( |_|true, &1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #128044 for more information diff --git a/tests/ui/coroutine/async-gen-deduce-yield.rs b/tests/ui/coroutine/async-gen-deduce-yield.rs index f85e4a52e9b9..a9572ee9b0dd 100644 --- a/tests/ui/coroutine/async-gen-deduce-yield.rs +++ b/tests/ui/coroutine/async-gen-deduce-yield.rs @@ -1,4 +1,4 @@ -//@ compile-flags: --edition 2024 +//@ edition: 2024 //@ check-pass #![feature(async_iterator, gen_blocks)] diff --git a/tests/ui/coroutine/async-gen-yield-ty-is-unit.rs b/tests/ui/coroutine/async-gen-yield-ty-is-unit.rs index 583820c7aa39..53e3ce77f8a8 100644 --- a/tests/ui/coroutine/async-gen-yield-ty-is-unit.rs +++ b/tests/ui/coroutine/async-gen-yield-ty-is-unit.rs @@ -1,4 +1,4 @@ -//@ compile-flags: --edition 2024 +//@ edition: 2024 //@ check-pass #![feature(async_iterator, gen_blocks)] diff --git a/tests/ui/coroutine/auto-trait-regions.rs b/tests/ui/coroutine/auto-trait-regions.rs index 4c239f9ee76c..1c7f0304ddbe 100644 --- a/tests/ui/coroutine/auto-trait-regions.rs +++ b/tests/ui/coroutine/auto-trait-regions.rs @@ -43,8 +43,8 @@ fn main() { // Disallow impls which relates lifetimes in the coroutine interior let gen = #[coroutine] move || { let a = A(&mut true, &mut true, No); - //~^ temporary value dropped while borrowed - //~| temporary value dropped while borrowed + //~^ ERROR temporary value dropped while borrowed + //~| ERROR temporary value dropped while borrowed yield; assert_foo(a); }; diff --git a/tests/ui/coroutine/coroutine-with-nll.rs b/tests/ui/coroutine/coroutine-with-nll.rs index fa77ab4e0495..44ead560cf88 100644 --- a/tests/ui/coroutine/coroutine-with-nll.rs +++ b/tests/ui/coroutine/coroutine-with-nll.rs @@ -6,7 +6,7 @@ fn main() { // The reference in `_a` is a Legal with NLL since it ends before the yield let _a = &mut true; let b = &mut true; - //~^ borrow may still be in use when coroutine yields + //~^ ERROR borrow may still be in use when coroutine yields yield (); println!("{}", b); }; diff --git a/tests/ui/coroutine/higher-ranked-rigid.rs b/tests/ui/coroutine/higher-ranked-rigid.rs new file mode 100644 index 000000000000..23a7d51300c9 --- /dev/null +++ b/tests/ui/coroutine/higher-ranked-rigid.rs @@ -0,0 +1,41 @@ +//@ edition: 2024 +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver +//@ check-pass + +// Regression test for . +// Coroutines erase all free lifetimes from their interior types, replacing them with higher- +// ranked regions which act as universals, to properly represent the fact that we don't know what +// the value of the region is within the coroutine. +// +// In the future in `from_request`, that means that the `'r` lifetime is being replaced in +// `>::Assoc`, which is in present in the existential bounds of the +// `dyn Future` that it's awaiting. Normalizing this associated type, with its free lifetimes +// replaced, means proving `T: FromRequest<'!0>`, which doesn't hold without constraining the +// `'!0` lifetime, which we don't do today. + +// Proving `T: Trait` holds when `::Assoc` is rigid is not necessary for soundness, +// at least not *yet*, and it's not even necessary for diagnostics since we have other special +// casing for, e.g., AliasRelate goals failing in the BestObligation folder. + +// The old solver unintentioanlly avoids this by never checking that `T: Trait` holds when +// `::Assoc` is rigid. Introducing this additional requirement when projecting rigidly +// in the old solver causes this (and tons of production crates) to fail. See the fallout from the +// crater run at . + +use std::future::Future; +use std::pin::Pin; + +pub trait FromRequest<'r> { + type Assoc; + fn from_request() -> Pin + Send>>; +} + +fn test<'r, T: FromRequest<'r>>() -> Pin + Send>> { + Box::pin(async move { + T::from_request().await; + }) +} + +fn main() {} diff --git a/tests/ui/coroutine/postfix-yield.rs b/tests/ui/coroutine/postfix-yield.rs index ff843138c8c2..f2fdcebdaa9a 100644 --- a/tests/ui/coroutine/postfix-yield.rs +++ b/tests/ui/coroutine/postfix-yield.rs @@ -3,7 +3,7 @@ //@ run-pass //@ edition: 2024 -#![feature(gen_blocks, coroutines, coroutine_trait, yield_expr)] +#![feature(gen_blocks, coroutines, coroutine_trait, yield_expr, stmt_expr_attributes)] use std::ops::{Coroutine, CoroutineState}; use std::pin::pin; diff --git a/tests/ui/coroutine/retain-resume-ref.rs b/tests/ui/coroutine/retain-resume-ref.rs index 6e688c33979a..000e40d47fbe 100644 --- a/tests/ui/coroutine/retain-resume-ref.rs +++ b/tests/ui/coroutine/retain-resume-ref.rs @@ -22,5 +22,5 @@ fn main() { let mut gen = Pin::new(&mut gen); gen.as_mut().resume(&mut thing); gen.as_mut().resume(&mut thing); - //~^ cannot borrow `thing` as mutable more than once at a time + //~^ ERROR cannot borrow `thing` as mutable more than once at a time } diff --git a/tests/ui/cross/cross-file-errors/underscore.rs b/tests/ui/cross/cross-file-errors/underscore.rs index 9d075735393d..73eb36cec24c 100644 --- a/tests/ui/cross/cross-file-errors/underscore.rs +++ b/tests/ui/cross/cross-file-errors/underscore.rs @@ -1,4 +1,4 @@ -//@ ignore-test (auxiliary, used by other tests) +//@ ignore-auxiliary (used by `./main.rs`) #![crate_type = "lib"] macro_rules! underscore { diff --git a/tests/ui/debuginfo/dwarf-versions.rs b/tests/ui/debuginfo/dwarf-versions.rs index 6030b2fcf3cd..8f731f10ead4 100644 --- a/tests/ui/debuginfo/dwarf-versions.rs +++ b/tests/ui/debuginfo/dwarf-versions.rs @@ -1,26 +1,25 @@ // This test verifies the expected behavior of various options passed to -// `-Zdwarf-version`: 2 - 5 (valid) with all other options being invalid. +// `-Cdwarf-version`: 2 - 5 (valid) with all other options being invalid. //@ revisions: zero one two three four five six -//@[zero] compile-flags: -Zdwarf-version=0 +//@[zero] compile-flags: -Cdwarf-version=0 -//@[one] compile-flags: -Zdwarf-version=1 -//@[one] error-pattern: requested DWARF version 1 is not supported +//@[one] compile-flags: -Cdwarf-version=1 -//@[two] compile-flags: -Zdwarf-version=2 +//@[two] compile-flags: -Cdwarf-version=2 //@[two] check-pass -//@[three] compile-flags: -Zdwarf-version=3 +//@[three] compile-flags: -Cdwarf-version=3 //@[three] check-pass -//@[four] compile-flags: -Zdwarf-version=4 +//@[four] compile-flags: -Cdwarf-version=4 //@[four] check-pass -//@[five] compile-flags: -Zdwarf-version=5 +//@[five] compile-flags: -Cdwarf-version=5 //@[five] check-pass -//@[six] compile-flags: -Zdwarf-version=6 +//@[six] compile-flags: -Cdwarf-version=6 //@ compile-flags: -g --target x86_64-unknown-linux-gnu --crate-type cdylib //@ needs-llvm-components: x86 diff --git a/tests/ui/debuginfo/issue-105386-debuginfo-ub.rs b/tests/ui/debuginfo/issue-105386-debuginfo-ub.rs index 7b850f32b4b6..e926a337659c 100644 --- a/tests/ui/debuginfo/issue-105386-debuginfo-ub.rs +++ b/tests/ui/debuginfo/issue-105386-debuginfo-ub.rs @@ -1,5 +1,6 @@ //@ run-pass -//@ compile-flags: --edition 2021 -Copt-level=3 -Cdebuginfo=2 -Zmir-opt-level=3 +//@ compile-flags: -Copt-level=3 -Cdebuginfo=2 -Zmir-opt-level=3 +//@ edition: 2021 fn main() { TranslatorI.visit_pre(); diff --git a/tests/ui/deduplicate-diagnostics.duplicate.stderr b/tests/ui/deduplicate-diagnostics.duplicate.stderr index 0544b993278d..48e2ba7b86aa 100644 --- a/tests/ui/deduplicate-diagnostics.duplicate.stderr +++ b/tests/ui/deduplicate-diagnostics.duplicate.stderr @@ -26,6 +26,14 @@ LL | #[deny("literal")] | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: aborting due to 4 previous errors +error[E0452]: malformed lint attribute input + --> $DIR/deduplicate-diagnostics.rs:8:8 + | +LL | #[deny("literal")] + | ^^^^^^^^^ bad attribute argument + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0452`. diff --git a/tests/ui/deduplicate-diagnostics.rs b/tests/ui/deduplicate-diagnostics.rs index 54bd5dd5098c..299c1f5f4610 100644 --- a/tests/ui/deduplicate-diagnostics.rs +++ b/tests/ui/deduplicate-diagnostics.rs @@ -7,4 +7,5 @@ struct S; #[deny("literal")] //~ ERROR malformed lint attribute input //[duplicate]~| ERROR malformed lint attribute input + //[duplicate]~| ERROR malformed lint attribute input fn main() {} diff --git a/tests/ui/delegation/explicit-paths-signature-pass.rs b/tests/ui/delegation/explicit-paths-signature-pass.rs index 8c16ad92393c..11bc8a70db0e 100644 --- a/tests/ui/delegation/explicit-paths-signature-pass.rs +++ b/tests/ui/delegation/explicit-paths-signature-pass.rs @@ -6,7 +6,7 @@ mod to_reuse { use crate::S; - pub fn foo<'a>(#[cfg(FALSE)] a: u8, _b: &'a S) -> u32 { + pub fn foo<'a>(#[cfg(false)] a: u8, _b: &'a S) -> u32 { 1 } } diff --git a/tests/ui/delegation/ice-issue-124347.rs b/tests/ui/delegation/ice-issue-124347.rs index b2b3c61a722b..3e0a5b36ddcf 100644 --- a/tests/ui/delegation/ice-issue-124347.rs +++ b/tests/ui/delegation/ice-issue-124347.rs @@ -4,7 +4,6 @@ // FIXME(fn_delegation): `recursive delegation` error should be emitted here trait Trait { reuse Trait::foo { &self.0 } - //~^ ERROR recursive delegation is not supported yet } reuse foo; diff --git a/tests/ui/delegation/ice-issue-124347.stderr b/tests/ui/delegation/ice-issue-124347.stderr index 74c4b5cd949a..2955c0442034 100644 --- a/tests/ui/delegation/ice-issue-124347.stderr +++ b/tests/ui/delegation/ice-issue-124347.stderr @@ -1,23 +1,17 @@ -error: recursive delegation is not supported yet - --> $DIR/ice-issue-124347.rs:6:18 - | -LL | reuse Trait::foo { &self.0 } - | ^^^ callee defined here - error[E0391]: cycle detected when computing generics of `foo` - --> $DIR/ice-issue-124347.rs:10:7 + --> $DIR/ice-issue-124347.rs:9:7 | LL | reuse foo; | ^^^ | = note: ...which immediately requires computing generics of `foo` again note: cycle used when checking that `foo` is well-formed - --> $DIR/ice-issue-124347.rs:10:7 + --> $DIR/ice-issue-124347.rs:9:7 | LL | reuse foo; | ^^^ = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/delegation/unsupported.stderr b/tests/ui/delegation/unsupported.stderr index 2b0bcf9d84e8..cb14d9f459a2 100644 --- a/tests/ui/delegation/unsupported.stderr +++ b/tests/ui/delegation/unsupported.stderr @@ -1,4 +1,4 @@ -error[E0391]: cycle detected when computing type of `opaque::::{synthetic#0}` +error[E0391]: cycle detected when computing type of `opaque::::{anon_assoc#0}` --> $DIR/unsupported.rs:22:25 | LL | reuse to_reuse::opaque_ret; @@ -9,7 +9,7 @@ note: ...which requires comparing an impl and trait method signature, inferring | LL | reuse to_reuse::opaque_ret; | ^^^^^^^^^^ - = note: ...which again requires computing type of `opaque::::{synthetic#0}`, completing the cycle + = note: ...which again requires computing type of `opaque::::{anon_assoc#0}`, completing the cycle note: cycle used when checking that `opaque::` is well-formed --> $DIR/unsupported.rs:21:5 | @@ -17,7 +17,7 @@ LL | impl ToReuse for u8 { | ^^^^^^^^^^^^^^^^^^^ = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information -error[E0391]: cycle detected when computing type of `opaque::::{synthetic#0}` +error[E0391]: cycle detected when computing type of `opaque::::{anon_assoc#0}` --> $DIR/unsupported.rs:25:24 | LL | reuse ToReuse::opaque_ret; @@ -28,7 +28,7 @@ note: ...which requires comparing an impl and trait method signature, inferring | LL | reuse ToReuse::opaque_ret; | ^^^^^^^^^^ - = note: ...which again requires computing type of `opaque::::{synthetic#0}`, completing the cycle + = note: ...which again requires computing type of `opaque::::{anon_assoc#0}`, completing the cycle note: cycle used when checking that `opaque::` is well-formed --> $DIR/unsupported.rs:24:5 | diff --git a/tests/ui/deprecation/try-macro-suggestion.rs b/tests/ui/deprecation/try-macro-suggestion.rs index 1e477ab9c88f..0775f0011001 100644 --- a/tests/ui/deprecation/try-macro-suggestion.rs +++ b/tests/ui/deprecation/try-macro-suggestion.rs @@ -1,4 +1,4 @@ -//@ compile-flags: --edition 2018 +//@ edition: 2018 fn foo() -> Result<(), ()> { Ok(try!()); //~ ERROR use of deprecated `try` macro Ok(try!(Ok(()))) //~ ERROR use of deprecated `try` macro diff --git a/tests/ui/deref-patterns/gate.rs b/tests/ui/deref-patterns/gate.rs index ff50e30dea8c..835fdf854d2c 100644 --- a/tests/ui/deref-patterns/gate.rs +++ b/tests/ui/deref-patterns/gate.rs @@ -2,6 +2,6 @@ fn main() { match String::new() { "" | _ => {} - //~^ mismatched types + //~^ ERROR mismatched types } } diff --git a/tests/ui/deriving/built-in-proc-macro-scope.rs b/tests/ui/deriving/built-in-proc-macro-scope.rs index e67197b7e205..69128a08b997 100644 --- a/tests/ui/deriving/built-in-proc-macro-scope.rs +++ b/tests/ui/deriving/built-in-proc-macro-scope.rs @@ -1,6 +1,7 @@ //@ check-pass //@ proc-macro: another-proc-macro.rs //@ compile-flags: -Zunpretty=expanded +//@ edition:2015 #![feature(derive_coerce_pointee)] diff --git a/tests/ui/deriving/built-in-proc-macro-scope.stdout b/tests/ui/deriving/built-in-proc-macro-scope.stdout index fa4e50968f4d..2697618ab003 100644 --- a/tests/ui/deriving/built-in-proc-macro-scope.stdout +++ b/tests/ui/deriving/built-in-proc-macro-scope.stdout @@ -3,6 +3,7 @@ //@ check-pass //@ proc-macro: another-proc-macro.rs //@ compile-flags: -Zunpretty=expanded +//@ edition:2015 #![feature(derive_coerce_pointee)] #[prelude_import] diff --git a/tests/ui/deriving/deriving-coerce-pointee-expanded.rs b/tests/ui/deriving/deriving-coerce-pointee-expanded.rs index 94be7031fb77..9394ae4efe5a 100644 --- a/tests/ui/deriving/deriving-coerce-pointee-expanded.rs +++ b/tests/ui/deriving/deriving-coerce-pointee-expanded.rs @@ -1,5 +1,6 @@ //@ check-pass //@ compile-flags: -Zunpretty=expanded +//@ edition: 2015 #![feature(derive_coerce_pointee)] use std::marker::CoercePointee; diff --git a/tests/ui/deriving/deriving-coerce-pointee-expanded.stdout b/tests/ui/deriving/deriving-coerce-pointee-expanded.stdout index a774efbbe354..84f8e9a3195a 100644 --- a/tests/ui/deriving/deriving-coerce-pointee-expanded.stdout +++ b/tests/ui/deriving/deriving-coerce-pointee-expanded.stdout @@ -2,6 +2,7 @@ #![no_std] //@ check-pass //@ compile-flags: -Zunpretty=expanded +//@ edition: 2015 #![feature(derive_coerce_pointee)] #[prelude_import] use ::std::prelude::rust_2015::*; diff --git a/tests/ui/deriving/proc-macro-attribute-mixing.rs b/tests/ui/deriving/proc-macro-attribute-mixing.rs index 2c11c3f72ca5..c9e123d7e8a1 100644 --- a/tests/ui/deriving/proc-macro-attribute-mixing.rs +++ b/tests/ui/deriving/proc-macro-attribute-mixing.rs @@ -7,6 +7,7 @@ //@ check-pass //@ proc-macro: another-proc-macro.rs //@ compile-flags: -Zunpretty=expanded +//@ edition: 2015 #![feature(derive_coerce_pointee)] diff --git a/tests/ui/deriving/proc-macro-attribute-mixing.stdout b/tests/ui/deriving/proc-macro-attribute-mixing.stdout index ad743d013d25..faa9c0218a33 100644 --- a/tests/ui/deriving/proc-macro-attribute-mixing.stdout +++ b/tests/ui/deriving/proc-macro-attribute-mixing.stdout @@ -9,6 +9,7 @@ //@ check-pass //@ proc-macro: another-proc-macro.rs //@ compile-flags: -Zunpretty=expanded +//@ edition: 2015 #![feature(derive_coerce_pointee)] #[prelude_import] diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr index 90bb715a0522..6170250992ce 100644 --- a/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr +++ b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr @@ -1,12 +1,14 @@ -error[E0277]: the trait bound `&str: AsExpression<::SqlType>` is not satisfied +error[E0277]: the trait bound `&str: AsExpression` is not satisfied --> $DIR/as_expression.rs:56:21 | LL | SelectInt.check("bar"); - | ----- ^^^^^ the trait `AsExpression<::SqlType>` is not implemented for `&str` + | ----- ^^^^^ the trait `AsExpression` is not implemented for `&str` | | | required by a bound introduced by this call | - = help: the trait `AsExpression` is implemented for `&str` + = help: the trait `AsExpression` is not implemented for `&str` + but trait `AsExpression` is implemented for it + = help: for that trait implementation, expected `Text`, found `Integer` note: required by a bound in `Foo::check` --> $DIR/as_expression.rs:47:12 | @@ -16,11 +18,11 @@ LL | where LL | T: AsExpression, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Foo::check` -error[E0271]: type mismatch resolving `::SqlType == Text` +error[E0271]: type mismatch resolving `Integer == Text` --> $DIR/as_expression.rs:56:5 | LL | SelectInt.check("bar"); - | ^^^^^^^^^^^^^^^^^^^^^^ expected `Text`, found `Integer` + | ^^^^^^^^^^^^^^^^^^^^^^ types differ error: aborting due to 2 previous errors diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.rs b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.rs index 73a238ddf50d..673adb82870d 100644 --- a/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.rs +++ b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.rs @@ -54,7 +54,6 @@ impl Foo for T where T: Expression {} fn main() { SelectInt.check("bar"); - //[current]~^ ERROR the trait bound `&str: AsExpression` is not satisfied - //[next]~^^ the trait bound `&str: AsExpression<::SqlType>` is not satisfied - //[next]~| type mismatch + //~^ ERROR the trait bound `&str: AsExpression` is not satisfied + //[next]~| ERROR type mismatch } diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/custom-on-unimplemented-diagnostic.rs b/tests/ui/diagnostic_namespace/on_unimplemented/custom-on-unimplemented-diagnostic.rs index 1173c939038a..3bb0939b5f91 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/custom-on-unimplemented-diagnostic.rs +++ b/tests/ui/diagnostic_namespace/on_unimplemented/custom-on-unimplemented-diagnostic.rs @@ -15,7 +15,7 @@ struct B; fn main() { B.request(); - //~^ my message [E0599] + //~^ ERROR my message [E0599] //~| my label //~| my note } diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.rs b/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.rs index c638681173d9..b06f56bd66e4 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.rs +++ b/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.rs @@ -8,8 +8,8 @@ note = "custom note" )] #[diagnostic::on_unimplemented(message = "fallback!!")] -//~^ `message` is ignored due to previous definition of `message` -//~| `message` is ignored due to previous definition of `message` +//~^ WARN `message` is ignored due to previous definition of `message` +//~| WARN `message` is ignored due to previous definition of `message` #[diagnostic::on_unimplemented(label = "fallback label")] #[diagnostic::on_unimplemented(note = "fallback note")] trait Foo {} diff --git a/tests/ui/did_you_mean/E0178.stderr b/tests/ui/did_you_mean/E0178.stderr index 5f289da8a6c3..36e4dbdf7c45 100644 --- a/tests/ui/did_you_mean/E0178.stderr +++ b/tests/ui/did_you_mean/E0178.stderr @@ -1,41 +1,43 @@ -error[E0178]: expected a path on the left-hand side of `+`, not `&'a Foo` +error[E0178]: expected a path on the left-hand side of `+` --> $DIR/E0178.rs:6:8 | LL | w: &'a Foo + Copy, - | ^^^^^^^^^^^^^^ + | ^^^^^^^ | help: try adding parentheses | LL | w: &'a (Foo + Copy), | + + -error[E0178]: expected a path on the left-hand side of `+`, not `&'a Foo` +error[E0178]: expected a path on the left-hand side of `+` --> $DIR/E0178.rs:7:8 | LL | x: &'a Foo + 'a, - | ^^^^^^^^^^^^ + | ^^^^^^^ | help: try adding parentheses | LL | x: &'a (Foo + 'a), | + + -error[E0178]: expected a path on the left-hand side of `+`, not `&'a mut Foo` +error[E0178]: expected a path on the left-hand side of `+` --> $DIR/E0178.rs:8:8 | LL | y: &'a mut Foo + 'a, - | ^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^ | help: try adding parentheses | LL | y: &'a mut (Foo + 'a), | + + -error[E0178]: expected a path on the left-hand side of `+`, not `fn() -> Foo` +error[E0178]: expected a path on the left-hand side of `+` --> $DIR/E0178.rs:9:8 | LL | z: fn() -> Foo + 'a, - | ^^^^^^^^^^^^^^^^ perhaps you forgot parentheses? + | ^^^^^^^^^^^----- + | | + | perhaps you forgot parentheses? error: aborting due to 4 previous errors diff --git a/tests/ui/did_you_mean/issue-38147-1.rs b/tests/ui/did_you_mean/issue-38147-1.rs index c068a1834f35..80f71b8b821e 100644 --- a/tests/ui/did_you_mean/issue-38147-1.rs +++ b/tests/ui/did_you_mean/issue-38147-1.rs @@ -14,7 +14,7 @@ struct Foo<'a> { impl<'a> Foo<'a> { fn f(&self) { - self.s.push('x'); //~ cannot borrow `*self.s` as mutable, as it is behind a `&` reference + self.s.push('x'); //~ ERROR cannot borrow `*self.s` as mutable, as it is behind a `&` reference } } diff --git a/tests/ui/did_you_mean/issue-40006.rs b/tests/ui/did_you_mean/issue-40006.rs index fff31bfc85e3..fcb86814c6e5 100644 --- a/tests/ui/did_you_mean/issue-40006.rs +++ b/tests/ui/did_you_mean/issue-40006.rs @@ -35,5 +35,5 @@ impl S { } fn main() { - S.hello_method(); //~ no method named `hello_method` found + S.hello_method(); //~ ERROR no method named `hello_method` found } diff --git a/tests/ui/did_you_mean/issue-42764.rs b/tests/ui/did_you_mean/issue-42764.rs index eb96c2480630..2766bb2c1b61 100644 --- a/tests/ui/did_you_mean/issue-42764.rs +++ b/tests/ui/did_you_mean/issue-42764.rs @@ -26,5 +26,5 @@ struct Context { wrapper: Wrapper } fn overton() { let _c = Context { wrapper: Payload{} }; //~^ ERROR mismatched types - //~| try wrapping the expression in `Wrapper` + //~| HELP try wrapping the expression in `Wrapper` } diff --git a/tests/ui/did_you_mean/issue-48492-tuple-destructure-missing-parens.stderr b/tests/ui/did_you_mean/issue-48492-tuple-destructure-missing-parens.stderr index d4812d4831b0..c74cb89f85cb 100644 --- a/tests/ui/did_you_mean/issue-48492-tuple-destructure-missing-parens.stderr +++ b/tests/ui/did_you_mean/issue-48492-tuple-destructure-missing-parens.stderr @@ -66,7 +66,6 @@ error: unexpected `,` in pattern LL | let women, men: (Vec, Vec) = genomes.iter().cloned() | ^ | - = note: type ascription syntax has been removed, see issue #101728 help: try adding parentheses to match on a tuple | LL | let (women, men): (Vec, Vec) = genomes.iter().cloned() diff --git a/tests/ui/did_you_mean/trait-object-reference-without-parens-suggestion.stderr b/tests/ui/did_you_mean/trait-object-reference-without-parens-suggestion.stderr index 4fee6cc9a222..762b37b9e9d6 100644 --- a/tests/ui/did_you_mean/trait-object-reference-without-parens-suggestion.stderr +++ b/tests/ui/did_you_mean/trait-object-reference-without-parens-suggestion.stderr @@ -1,19 +1,19 @@ -error[E0178]: expected a path on the left-hand side of `+`, not `&Copy` +error[E0178]: expected a path on the left-hand side of `+` --> $DIR/trait-object-reference-without-parens-suggestion.rs:4:12 | LL | let _: &Copy + 'static; - | ^^^^^^^^^^^^^^^ + | ^^^^^ | help: try adding parentheses | LL | let _: &(Copy + 'static); | + + -error[E0178]: expected a path on the left-hand side of `+`, not `&'static Copy` +error[E0178]: expected a path on the left-hand side of `+` --> $DIR/trait-object-reference-without-parens-suggestion.rs:6:12 | LL | let _: &'static Copy + 'static; - | ^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^ | help: try adding parentheses | diff --git a/tests/ui/directory_ownership/macro_expanded_mod_helper/foo/bar.rs b/tests/ui/directory_ownership/macro_expanded_mod_helper/foo/bar.rs index 1d832a36ef50..2ccdd798c73d 100644 --- a/tests/ui/directory_ownership/macro_expanded_mod_helper/foo/bar.rs +++ b/tests/ui/directory_ownership/macro_expanded_mod_helper/foo/bar.rs @@ -1 +1 @@ -//@ ignore-test not a test, auxiliary +//@ ignore-auxiliary (used by `../../macro-expanded-mod.rs`) diff --git a/tests/ui/directory_ownership/macro_expanded_mod_helper/foo/mod.rs b/tests/ui/directory_ownership/macro_expanded_mod_helper/foo/mod.rs index 08349ba6747d..9009f80c6910 100644 --- a/tests/ui/directory_ownership/macro_expanded_mod_helper/foo/mod.rs +++ b/tests/ui/directory_ownership/macro_expanded_mod_helper/foo/mod.rs @@ -1,3 +1,3 @@ -//@ ignore-test not a test, auxiliary +//@ ignore-auxiliary (used by `../../macro-expanded-mod.rs`) mod_decl!(bar); diff --git a/tests/ui/directory_ownership/mod_file_not_owning_aux1.rs b/tests/ui/directory_ownership/mod_file_not_owning_aux1.rs deleted file mode 100644 index 6d6884fef040..000000000000 --- a/tests/ui/directory_ownership/mod_file_not_owning_aux1.rs +++ /dev/null @@ -1,6 +0,0 @@ -//@ ignore-test this is not a test - -macro_rules! m { - () => { mod mod_file_not_owning_aux2; } -} -m!(); diff --git a/tests/ui/directory_ownership/mod_file_not_owning_aux2.rs b/tests/ui/directory_ownership/mod_file_not_owning_aux2.rs deleted file mode 100644 index 76f1c1a72763..000000000000 --- a/tests/ui/directory_ownership/mod_file_not_owning_aux2.rs +++ /dev/null @@ -1 +0,0 @@ -//@ ignore-test this is not a test diff --git a/tests/ui/directory_ownership/mod_file_not_owning_aux3.rs b/tests/ui/directory_ownership/mod_file_not_owning_aux3.rs deleted file mode 100644 index 96a5780d971f..000000000000 --- a/tests/ui/directory_ownership/mod_file_not_owning_aux3.rs +++ /dev/null @@ -1,3 +0,0 @@ -//@ ignore-test this is not a test - -mod mod_file_not_owning_aux2; diff --git a/tests/ui/drop/drop-order-comparisons.e2021.stderr b/tests/ui/drop/drop-order-comparisons.e2021.stderr index 601b0a38412f..0717a8c1b9b9 100644 --- a/tests/ui/drop/drop-order-comparisons.e2021.stderr +++ b/tests/ui/drop/drop-order-comparisons.e2021.stderr @@ -31,39 +31,23 @@ LL | | }, e.mark(3), e.ok(4)); note: `#3` invokes this custom destructor --> $DIR/drop-order-comparisons.rs:571:1 | -LL | / impl<'b> Drop for LogDrop<'b> { -LL | | fn drop(&mut self) { -LL | | self.0.mark(self.1); -LL | | } -LL | | } - | |_^ +LL | impl<'b> Drop for LogDrop<'b> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: `#1` invokes this custom destructor --> $DIR/drop-order-comparisons.rs:571:1 | -LL | / impl<'b> Drop for LogDrop<'b> { -LL | | fn drop(&mut self) { -LL | | self.0.mark(self.1); -LL | | } -LL | | } - | |_^ +LL | impl<'b> Drop for LogDrop<'b> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: `_v` invokes this custom destructor --> $DIR/drop-order-comparisons.rs:571:1 | -LL | / impl<'b> Drop for LogDrop<'b> { -LL | | fn drop(&mut self) { -LL | | self.0.mark(self.1); -LL | | } -LL | | } - | |_^ +LL | impl<'b> Drop for LogDrop<'b> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: `#2` invokes this custom destructor --> $DIR/drop-order-comparisons.rs:571:1 | -LL | / impl<'b> Drop for LogDrop<'b> { -LL | | fn drop(&mut self) { -LL | | self.0.mark(self.1); -LL | | } -LL | | } - | |_^ +LL | impl<'b> Drop for LogDrop<'b> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages note: the lint level is defined here --> $DIR/drop-order-comparisons.rs:28:25 @@ -95,21 +79,13 @@ LL | | }, e.mark(1), e.ok(4)); note: `#2` invokes this custom destructor --> $DIR/drop-order-comparisons.rs:571:1 | -LL | / impl<'b> Drop for LogDrop<'b> { -LL | | fn drop(&mut self) { -LL | | self.0.mark(self.1); -LL | | } -LL | | } - | |_^ +LL | impl<'b> Drop for LogDrop<'b> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: `#1` invokes this custom destructor --> $DIR/drop-order-comparisons.rs:571:1 | -LL | / impl<'b> Drop for LogDrop<'b> { -LL | | fn drop(&mut self) { -LL | | self.0.mark(self.1); -LL | | } -LL | | } - | |_^ +LL | impl<'b> Drop for LogDrop<'b> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages warning: relative drop order changing in Rust 2024 @@ -135,21 +111,13 @@ LL | | }, e.mark(1), e.ok(4)); note: `#2` invokes this custom destructor --> $DIR/drop-order-comparisons.rs:571:1 | -LL | / impl<'b> Drop for LogDrop<'b> { -LL | | fn drop(&mut self) { -LL | | self.0.mark(self.1); -LL | | } -LL | | } - | |_^ +LL | impl<'b> Drop for LogDrop<'b> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: `#1` invokes this custom destructor --> $DIR/drop-order-comparisons.rs:571:1 | -LL | / impl<'b> Drop for LogDrop<'b> { -LL | | fn drop(&mut self) { -LL | | self.0.mark(self.1); -LL | | } -LL | | } - | |_^ +LL | impl<'b> Drop for LogDrop<'b> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages warning: relative drop order changing in Rust 2024 @@ -175,21 +143,13 @@ LL | | }, e.mark(2), e.ok(3)); note: `#2` invokes this custom destructor --> $DIR/drop-order-comparisons.rs:571:1 | -LL | / impl<'b> Drop for LogDrop<'b> { -LL | | fn drop(&mut self) { -LL | | self.0.mark(self.1); -LL | | } -LL | | } - | |_^ +LL | impl<'b> Drop for LogDrop<'b> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: `#1` invokes this custom destructor --> $DIR/drop-order-comparisons.rs:571:1 | -LL | / impl<'b> Drop for LogDrop<'b> { -LL | | fn drop(&mut self) { -LL | | self.0.mark(self.1); -LL | | } -LL | | } - | |_^ +LL | impl<'b> Drop for LogDrop<'b> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages warning: relative drop order changing in Rust 2024 @@ -215,21 +175,13 @@ LL | | }, e.mark(2), e.ok(3)); note: `#2` invokes this custom destructor --> $DIR/drop-order-comparisons.rs:571:1 | -LL | / impl<'b> Drop for LogDrop<'b> { -LL | | fn drop(&mut self) { -LL | | self.0.mark(self.1); -LL | | } -LL | | } - | |_^ +LL | impl<'b> Drop for LogDrop<'b> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: `#1` invokes this custom destructor --> $DIR/drop-order-comparisons.rs:571:1 | -LL | / impl<'b> Drop for LogDrop<'b> { -LL | | fn drop(&mut self) { -LL | | self.0.mark(self.1); -LL | | } -LL | | } - | |_^ +LL | impl<'b> Drop for LogDrop<'b> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages warning: `if let` assigns a shorter lifetime since Edition 2024 @@ -245,12 +197,8 @@ LL | _ = (if let Ok(_) = e.ok(4).as_ref() { note: value invokes this custom destructor --> $DIR/drop-order-comparisons.rs:571:1 | -LL | / impl<'b> Drop for LogDrop<'b> { -LL | | fn drop(&mut self) { -LL | | self.0.mark(self.1); -LL | | } -LL | | } - | |_^ +LL | impl<'b> Drop for LogDrop<'b> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: the value is now dropped here in Edition 2024 --> $DIR/drop-order-comparisons.rs:127:5 | @@ -279,12 +227,8 @@ LL | _ = (if let Ok(_) = e.err(4).as_ref() {} else { note: value invokes this custom destructor --> $DIR/drop-order-comparisons.rs:571:1 | -LL | / impl<'b> Drop for LogDrop<'b> { -LL | | fn drop(&mut self) { -LL | | self.0.mark(self.1); -LL | | } -LL | | } - | |_^ +LL | impl<'b> Drop for LogDrop<'b> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: the value is now dropped here in Edition 2024 --> $DIR/drop-order-comparisons.rs:145:44 | @@ -312,12 +256,8 @@ LL | if let Ok(_) = e.err(4).as_ref() {} else { note: value invokes this custom destructor --> $DIR/drop-order-comparisons.rs:571:1 | -LL | / impl<'b> Drop for LogDrop<'b> { -LL | | fn drop(&mut self) { -LL | | self.0.mark(self.1); -LL | | } -LL | | } - | |_^ +LL | impl<'b> Drop for LogDrop<'b> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: the value is now dropped here in Edition 2024 --> $DIR/drop-order-comparisons.rs:247:43 | @@ -345,12 +285,8 @@ LL | if let true = e.err(9).is_ok() {} else { note: value invokes this custom destructor --> $DIR/drop-order-comparisons.rs:571:1 | -LL | / impl<'b> Drop for LogDrop<'b> { -LL | | fn drop(&mut self) { -LL | | self.0.mark(self.1); -LL | | } -LL | | } - | |_^ +LL | impl<'b> Drop for LogDrop<'b> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: the value is now dropped here in Edition 2024 --> $DIR/drop-order-comparisons.rs:352:41 | @@ -378,12 +314,8 @@ LL | if let Ok(_v) = e.err(8) {} else { note: value invokes this custom destructor --> $DIR/drop-order-comparisons.rs:571:1 | -LL | / impl<'b> Drop for LogDrop<'b> { -LL | | fn drop(&mut self) { -LL | | self.0.mark(self.1); -LL | | } -LL | | } - | |_^ +LL | impl<'b> Drop for LogDrop<'b> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: the value is now dropped here in Edition 2024 --> $DIR/drop-order-comparisons.rs:355:35 | @@ -411,12 +343,8 @@ LL | if let Ok(_) = e.err(7) {} else { note: value invokes this custom destructor --> $DIR/drop-order-comparisons.rs:571:1 | -LL | / impl<'b> Drop for LogDrop<'b> { -LL | | fn drop(&mut self) { -LL | | self.0.mark(self.1); -LL | | } -LL | | } - | |_^ +LL | impl<'b> Drop for LogDrop<'b> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: the value is now dropped here in Edition 2024 --> $DIR/drop-order-comparisons.rs:358:34 | @@ -444,12 +372,8 @@ LL | if let Ok(_) = e.err(6).as_ref() {} else { note: value invokes this custom destructor --> $DIR/drop-order-comparisons.rs:571:1 | -LL | / impl<'b> Drop for LogDrop<'b> { -LL | | fn drop(&mut self) { -LL | | self.0.mark(self.1); -LL | | } -LL | | } - | |_^ +LL | impl<'b> Drop for LogDrop<'b> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: the value is now dropped here in Edition 2024 --> $DIR/drop-order-comparisons.rs:361:43 | @@ -477,12 +401,8 @@ LL | if let Ok(_v) = e.err(5) {} else { note: value invokes this custom destructor --> $DIR/drop-order-comparisons.rs:571:1 | -LL | / impl<'b> Drop for LogDrop<'b> { -LL | | fn drop(&mut self) { -LL | | self.0.mark(self.1); -LL | | } -LL | | } - | |_^ +LL | impl<'b> Drop for LogDrop<'b> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: the value is now dropped here in Edition 2024 --> $DIR/drop-order-comparisons.rs:365:35 | @@ -510,12 +430,8 @@ LL | if let Ok(_) = e.err(4) {} else { note: value invokes this custom destructor --> $DIR/drop-order-comparisons.rs:571:1 | -LL | / impl<'b> Drop for LogDrop<'b> { -LL | | fn drop(&mut self) { -LL | | self.0.mark(self.1); -LL | | } -LL | | } - | |_^ +LL | impl<'b> Drop for LogDrop<'b> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: the value is now dropped here in Edition 2024 --> $DIR/drop-order-comparisons.rs:368:34 | @@ -543,12 +459,8 @@ LL | if let Ok(_) = e.err(4).as_ref() {} else { note: value invokes this custom destructor --> $DIR/drop-order-comparisons.rs:571:1 | -LL | / impl<'b> Drop for LogDrop<'b> { -LL | | fn drop(&mut self) { -LL | | self.0.mark(self.1); -LL | | } -LL | | } - | |_^ +LL | impl<'b> Drop for LogDrop<'b> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: the value is now dropped here in Edition 2024 --> $DIR/drop-order-comparisons.rs:404:43 | diff --git a/tests/crashes/137287.rs b/tests/ui/drop/drop_elaboration_with_errors2.rs similarity index 68% rename from tests/crashes/137287.rs rename to tests/ui/drop/drop_elaboration_with_errors2.rs index 59fdf568d368..946c253179cb 100644 --- a/tests/crashes/137287.rs +++ b/tests/ui/drop/drop_elaboration_with_errors2.rs @@ -1,11 +1,14 @@ -//@ known-bug: #137287 +// Regression test for #137287 mod defining_scope { use super::*; pub type Alias = impl Sized; + //~^ ERROR unconstrained opaque type + //~| ERROR `impl Trait` in type aliases is unstable pub fn cast(x: Container, T>) -> Container { x + //~^ ERROR mismatched types } } @@ -21,6 +24,7 @@ impl Trait for T { type Assoc = Box; } impl Trait for defining_scope::Alias { + //~^ ERROR conflicting implementations of trait `Trait<_>` type Assoc = usize; } diff --git a/tests/ui/drop/drop_elaboration_with_errors2.stderr b/tests/ui/drop/drop_elaboration_with_errors2.stderr new file mode 100644 index 000000000000..15fe3f6ecc1f --- /dev/null +++ b/tests/ui/drop/drop_elaboration_with_errors2.stderr @@ -0,0 +1,47 @@ +error[E0658]: `impl Trait` in type aliases is unstable + --> $DIR/drop_elaboration_with_errors2.rs:5:25 + | +LL | pub type Alias = impl Sized; + | ^^^^^^^^^^ + | + = note: see issue #63063 for more information + = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0119]: conflicting implementations of trait `Trait<_>` + --> $DIR/drop_elaboration_with_errors2.rs:26:1 + | +LL | impl Trait for T { + | ---------------------- first implementation here +... +LL | impl Trait for defining_scope::Alias { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation + +error: unconstrained opaque type + --> $DIR/drop_elaboration_with_errors2.rs:5:25 + | +LL | pub type Alias = impl Sized; + | ^^^^^^^^^^ + | + = note: `Alias` must be used in combination with a concrete type within the same crate + +error[E0308]: mismatched types + --> $DIR/drop_elaboration_with_errors2.rs:10:9 + | +LL | pub type Alias = impl Sized; + | ---------- the found opaque type +... +LL | pub fn cast(x: Container, T>) -> Container { + | - expected this type parameter --------------- expected `Container` because of return type +LL | x + | ^ expected `Container`, found `Container, T>` + | + = note: expected struct `Container` + found struct `Container, _>` + = help: type parameters must be constrained to match other types + = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0119, E0308, E0658. +For more information about an error, try `rustc --explain E0119`. diff --git a/tests/crashes/135668.rs b/tests/ui/drop/drop_elaboration_with_errors3.rs similarity index 85% rename from tests/crashes/135668.rs rename to tests/ui/drop/drop_elaboration_with_errors3.rs index 8126a65606b2..c5ed63eb7ac2 100644 --- a/tests/crashes/135668.rs +++ b/tests/ui/drop/drop_elaboration_with_errors3.rs @@ -1,5 +1,6 @@ -//@ known-bug: #135668 -//@ compile-flags: --edition=2021 +// Regression test for #135668 +//@ edition: 2021 + use std::future::Future; pub async fn foo() { @@ -11,7 +12,8 @@ async fn create_task() -> impl Sized { } async fn documentation() { - include_str!("nonexistent"); + compile_error!("bonjour"); + //~^ ERROR bonjour } fn bind(_filter: F) -> impl Sized @@ -36,3 +38,5 @@ where { type Assoc = F; } + +fn main() {} diff --git a/tests/ui/drop/drop_elaboration_with_errors3.stderr b/tests/ui/drop/drop_elaboration_with_errors3.stderr new file mode 100644 index 000000000000..2d44e7c66259 --- /dev/null +++ b/tests/ui/drop/drop_elaboration_with_errors3.stderr @@ -0,0 +1,8 @@ +error: bonjour + --> $DIR/drop_elaboration_with_errors3.rs:15:5 + | +LL | compile_error!("bonjour"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/drop/lint-if-let-rescope-gated.edition2021.stderr b/tests/ui/drop/lint-if-let-rescope-gated.edition2021.stderr index 070ba1c6a4cf..0d6974d516b6 100644 --- a/tests/ui/drop/lint-if-let-rescope-gated.edition2021.stderr +++ b/tests/ui/drop/lint-if-let-rescope-gated.edition2021.stderr @@ -11,12 +11,8 @@ LL | if let Some(_value) = Droppy.get() { note: value invokes this custom destructor --> $DIR/lint-if-let-rescope-gated.rs:14:1 | -LL | / impl Drop for Droppy { -LL | | fn drop(&mut self) { -LL | | println!("dropped"); -LL | | } -LL | | } - | |_^ +LL | impl Drop for Droppy { + | ^^^^^^^^^^^^^^^^^^^^ help: the value is now dropped here in Edition 2024 --> $DIR/lint-if-let-rescope-gated.rs:30:5 | diff --git a/tests/ui/drop/lint-if-let-rescope-with-macro.stderr b/tests/ui/drop/lint-if-let-rescope-with-macro.stderr index f1ca0ba57de4..a0afb8eddb53 100644 --- a/tests/ui/drop/lint-if-let-rescope-with-macro.stderr +++ b/tests/ui/drop/lint-if-let-rescope-with-macro.stderr @@ -18,12 +18,8 @@ LL | | }; note: value invokes this custom destructor --> $DIR/lint-if-let-rescope-with-macro.rs:22:1 | -LL | / impl Drop for Droppy { -LL | | fn drop(&mut self) { -LL | | println!("dropped"); -LL | | } -LL | | } - | |_^ +LL | impl Drop for Droppy { + | ^^^^^^^^^^^^^^^^^^^^ help: the value is now dropped here in Edition 2024 --> $DIR/lint-if-let-rescope-with-macro.rs:12:38 | diff --git a/tests/ui/drop/lint-if-let-rescope.stderr b/tests/ui/drop/lint-if-let-rescope.stderr index e95ec8fcea7f..ca2416efcb1a 100644 --- a/tests/ui/drop/lint-if-let-rescope.stderr +++ b/tests/ui/drop/lint-if-let-rescope.stderr @@ -11,12 +11,8 @@ LL | if let Some(_value) = droppy().get() { note: value invokes this custom destructor --> $DIR/lint-if-let-rescope.rs:11:1 | -LL | / impl Drop for Droppy { -LL | | fn drop(&mut self) { -LL | | println!("dropped"); -LL | | } -LL | | } - | |_^ +LL | impl Drop for Droppy { + | ^^^^^^^^^^^^^^^^^^^^ help: the value is now dropped here in Edition 2024 --> $DIR/lint-if-let-rescope.rs:32:5 | @@ -55,21 +51,13 @@ LL | } else if let Some(_value) = droppy().get() { note: value invokes this custom destructor --> $DIR/lint-if-let-rescope.rs:11:1 | -LL | / impl Drop for Droppy { -LL | | fn drop(&mut self) { -LL | | println!("dropped"); -LL | | } -LL | | } - | |_^ +LL | impl Drop for Droppy { + | ^^^^^^^^^^^^^^^^^^^^ note: value invokes this custom destructor --> $DIR/lint-if-let-rescope.rs:11:1 | -LL | / impl Drop for Droppy { -LL | | fn drop(&mut self) { -LL | | println!("dropped"); -LL | | } -LL | | } - | |_^ +LL | impl Drop for Droppy { + | ^^^^^^^^^^^^^^^^^^^^ help: the value is now dropped here in Edition 2024 --> $DIR/lint-if-let-rescope.rs:42:5 | @@ -105,12 +93,8 @@ LL | } else if let Some(_value) = droppy().get() { note: value invokes this custom destructor --> $DIR/lint-if-let-rescope.rs:11:1 | -LL | / impl Drop for Droppy { -LL | | fn drop(&mut self) { -LL | | println!("dropped"); -LL | | } -LL | | } - | |_^ +LL | impl Drop for Droppy { + | ^^^^^^^^^^^^^^^^^^^^ help: the value is now dropped here in Edition 2024 --> $DIR/lint-if-let-rescope.rs:54:5 | @@ -140,12 +124,8 @@ LL | if let Some(1) = { if let Some(_value) = Droppy.get() { Some(1) } else note: value invokes this custom destructor --> $DIR/lint-if-let-rescope.rs:11:1 | -LL | / impl Drop for Droppy { -LL | | fn drop(&mut self) { -LL | | println!("dropped"); -LL | | } -LL | | } - | |_^ +LL | impl Drop for Droppy { + | ^^^^^^^^^^^^^^^^^^^^ help: the value is now dropped here in Edition 2024 --> $DIR/lint-if-let-rescope.rs:58:69 | @@ -170,12 +150,8 @@ LL | if (if let Some(_value) = droppy().get() { true } else { false }) { note: value invokes this custom destructor --> $DIR/lint-if-let-rescope.rs:11:1 | -LL | / impl Drop for Droppy { -LL | | fn drop(&mut self) { -LL | | println!("dropped"); -LL | | } -LL | | } - | |_^ +LL | impl Drop for Droppy { + | ^^^^^^^^^^^^^^^^^^^^ help: the value is now dropped here in Edition 2024 --> $DIR/lint-if-let-rescope.rs:72:53 | @@ -200,12 +176,8 @@ LL | } else if (((if let Some(_value) = droppy().get() { true } else { false note: value invokes this custom destructor --> $DIR/lint-if-let-rescope.rs:11:1 | -LL | / impl Drop for Droppy { -LL | | fn drop(&mut self) { -LL | | println!("dropped"); -LL | | } -LL | | } - | |_^ +LL | impl Drop for Droppy { + | ^^^^^^^^^^^^^^^^^^^^ help: the value is now dropped here in Edition 2024 --> $DIR/lint-if-let-rescope.rs:78:62 | @@ -230,12 +202,8 @@ LL | while (if let Some(_value) = droppy().get() { false } else { true }) { note: value invokes this custom destructor --> $DIR/lint-if-let-rescope.rs:11:1 | -LL | / impl Drop for Droppy { -LL | | fn drop(&mut self) { -LL | | println!("dropped"); -LL | | } -LL | | } - | |_^ +LL | impl Drop for Droppy { + | ^^^^^^^^^^^^^^^^^^^^ help: the value is now dropped here in Edition 2024 --> $DIR/lint-if-let-rescope.rs:90:57 | diff --git a/tests/ui/drop/lint-tail-expr-drop-order-borrowck.rs b/tests/ui/drop/lint-tail-expr-drop-order-borrowck.rs index 6f64d83f8a0c..e8368b0a369d 100644 --- a/tests/ui/drop/lint-tail-expr-drop-order-borrowck.rs +++ b/tests/ui/drop/lint-tail-expr-drop-order-borrowck.rs @@ -10,7 +10,7 @@ fn should_lint_with_potential_borrowck_err() { //~^ ERROR: relative drop order changing //~| WARN: this changes meaning in Rust 2024 //~| NOTE: this temporary value will be dropped at the end of the block - //~| borrow later used by call + //~| NOTE: borrow later used by call //~| NOTE: for more information, see } @@ -20,7 +20,7 @@ fn should_lint_with_unsafe_block() { //~^ ERROR: relative drop order changing //~| WARN: this changes meaning in Rust 2024 //~| NOTE: this temporary value will be dropped at the end of the block - //~| borrow later used by call + //~| NOTE: borrow later used by call //~| NOTE: for more information, see } @@ -32,7 +32,7 @@ fn should_lint_with_big_block() { //~^ ERROR: relative drop order changing //~| WARN: this changes meaning in Rust 2024 //~| NOTE: this temporary value will be dropped at the end of the block - //~| borrow later used here + //~| NOTE: borrow later used here //~| NOTE: for more information, see }) } @@ -44,7 +44,7 @@ fn another_temp_that_is_copy_in_arg() { //~^ ERROR: relative drop order changing //~| WARN: this changes meaning in Rust 2024 //~| NOTE: this temporary value will be dropped at the end of the block - //~| borrow later used by call + //~| NOTE: borrow later used by call //~| NOTE: for more information, see } diff --git a/tests/ui/drop/lint-tail-expr-drop-order.stderr b/tests/ui/drop/lint-tail-expr-drop-order.stderr index 6ff9b7c12681..e124e9874d0b 100644 --- a/tests/ui/drop/lint-tail-expr-drop-order.stderr +++ b/tests/ui/drop/lint-tail-expr-drop-order.stderr @@ -21,17 +21,13 @@ LL | } note: `#1` invokes this custom destructor --> $DIR/lint-tail-expr-drop-order.rs:10:1 | -LL | / impl Drop for LoudDropper { -... | -LL | | } - | |_^ +LL | impl Drop for LoudDropper { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ note: `x` invokes this custom destructor --> $DIR/lint-tail-expr-drop-order.rs:10:1 | -LL | / impl Drop for LoudDropper { -... | -LL | | } - | |_^ +LL | impl Drop for LoudDropper { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages note: the lint level is defined here --> $DIR/lint-tail-expr-drop-order.rs:6:9 @@ -62,17 +58,13 @@ LL | } note: `#1` invokes this custom destructor --> $DIR/lint-tail-expr-drop-order.rs:10:1 | -LL | / impl Drop for LoudDropper { -... | -LL | | } - | |_^ +LL | impl Drop for LoudDropper { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ note: `x` invokes this custom destructor --> $DIR/lint-tail-expr-drop-order.rs:10:1 | -LL | / impl Drop for LoudDropper { -... | -LL | | } - | |_^ +LL | impl Drop for LoudDropper { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages error: relative drop order changing in Rust 2024 @@ -98,17 +90,13 @@ LL | } note: `#1` invokes this custom destructor --> $DIR/lint-tail-expr-drop-order.rs:10:1 | -LL | / impl Drop for LoudDropper { -... | -LL | | } - | |_^ +LL | impl Drop for LoudDropper { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ note: `x` invokes this custom destructor --> $DIR/lint-tail-expr-drop-order.rs:10:1 | -LL | / impl Drop for LoudDropper { -... | -LL | | } - | |_^ +LL | impl Drop for LoudDropper { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages error: relative drop order changing in Rust 2024 @@ -134,10 +122,8 @@ LL | } note: `#1` invokes this custom destructor --> $DIR/lint-tail-expr-drop-order.rs:10:1 | -LL | / impl Drop for LoudDropper { -... | -LL | | } - | |_^ +LL | impl Drop for LoudDropper { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages error: relative drop order changing in Rust 2024 @@ -185,17 +171,13 @@ LL | } note: `#1` invokes this custom destructor --> $DIR/lint-tail-expr-drop-order.rs:10:1 | -LL | / impl Drop for LoudDropper { -... | -LL | | } - | |_^ +LL | impl Drop for LoudDropper { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ note: `x` invokes this custom destructor --> $DIR/lint-tail-expr-drop-order.rs:10:1 | -LL | / impl Drop for LoudDropper { -... | -LL | | } - | |_^ +LL | impl Drop for LoudDropper { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages error: relative drop order changing in Rust 2024 @@ -221,23 +203,13 @@ LL | } note: `#1` invokes this custom destructor --> $DIR/lint-tail-expr-drop-order.rs:193:5 | -LL | / impl Drop for LoudDropper3 { -LL | | -LL | | fn drop(&mut self) { -LL | | println!("loud drop"); -LL | | } -LL | | } - | |_____^ +LL | impl Drop for LoudDropper3 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ note: `x` invokes this custom destructor --> $DIR/lint-tail-expr-drop-order.rs:205:5 | -LL | / impl Drop for LoudDropper2 { -LL | | -LL | | fn drop(&mut self) { -LL | | println!("loud drop"); -LL | | } -LL | | } - | |_____^ +LL | impl Drop for LoudDropper2 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages error: relative drop order changing in Rust 2024 @@ -263,17 +235,13 @@ LL | )); note: `#1` invokes this custom destructor --> $DIR/lint-tail-expr-drop-order.rs:10:1 | -LL | / impl Drop for LoudDropper { -... | -LL | | } - | |_^ +LL | impl Drop for LoudDropper { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ note: `_x` invokes this custom destructor --> $DIR/lint-tail-expr-drop-order.rs:10:1 | -LL | / impl Drop for LoudDropper { -... | -LL | | } - | |_^ +LL | impl Drop for LoudDropper { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages error: aborting due to 8 previous errors diff --git a/tests/ui/drop/tail_expr_drop_order-on-coroutine-unwind.stderr b/tests/ui/drop/tail_expr_drop_order-on-coroutine-unwind.stderr index b0f971dd5cec..7bf452e2496c 100644 --- a/tests/ui/drop/tail_expr_drop_order-on-coroutine-unwind.stderr +++ b/tests/ui/drop/tail_expr_drop_order-on-coroutine-unwind.stderr @@ -27,24 +27,18 @@ LL | } note: `#2` invokes this custom destructor --> $DIR/tail_expr_drop_order-on-coroutine-unwind.rs:9:1 | -LL | / impl std::ops::Drop for Drop { -LL | | fn drop(&mut self) {} -LL | | } - | |_^ +LL | impl std::ops::Drop for Drop { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: `#1` invokes this custom destructor --> $DIR/tail_expr_drop_order-on-coroutine-unwind.rs:9:1 | -LL | / impl std::ops::Drop for Drop { -LL | | fn drop(&mut self) {} -LL | | } - | |_^ +LL | impl std::ops::Drop for Drop { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: `e` invokes this custom destructor --> $DIR/tail_expr_drop_order-on-coroutine-unwind.rs:9:1 | -LL | / impl std::ops::Drop for Drop { -LL | | fn drop(&mut self) {} -LL | | } - | |_^ +LL | impl std::ops::Drop for Drop { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages note: the lint level is defined here --> $DIR/tail_expr_drop_order-on-coroutine-unwind.rs:6:9 diff --git a/tests/ui/duplicate/dupe-symbols-1.rs b/tests/ui/duplicate/dupe-symbols-1.rs index f49bf44a0612..4e03d7c4ce5a 100644 --- a/tests/ui/duplicate/dupe-symbols-1.rs +++ b/tests/ui/duplicate/dupe-symbols-1.rs @@ -10,5 +10,5 @@ pub fn a() { #[export_name="fail"] pub fn b() { -//~^ symbol `fail` is already defined +//~^ ERROR symbol `fail` is already defined } diff --git a/tests/ui/duplicate/dupe-symbols-2.rs b/tests/ui/duplicate/dupe-symbols-2.rs index 343c7131d1fb..03fff570dff5 100644 --- a/tests/ui/duplicate/dupe-symbols-2.rs +++ b/tests/ui/duplicate/dupe-symbols-2.rs @@ -13,6 +13,6 @@ pub mod a { pub mod b { #[no_mangle] pub extern "C" fn fail() { - //~^ symbol `fail` is already defined + //~^ ERROR symbol `fail` is already defined } } diff --git a/tests/ui/duplicate/dupe-symbols-3.rs b/tests/ui/duplicate/dupe-symbols-3.rs index 365ec182f53a..41bbe5173573 100644 --- a/tests/ui/duplicate/dupe-symbols-3.rs +++ b/tests/ui/duplicate/dupe-symbols-3.rs @@ -10,5 +10,5 @@ pub fn a() { #[no_mangle] pub fn fail() { -//~^ symbol `fail` is already defined +//~^ ERROR symbol `fail` is already defined } diff --git a/tests/ui/duplicate/dupe-symbols-5.rs b/tests/ui/duplicate/dupe-symbols-5.rs index 2ed803c1ddad..4aaf2bd29c5c 100644 --- a/tests/ui/duplicate/dupe-symbols-5.rs +++ b/tests/ui/duplicate/dupe-symbols-5.rs @@ -9,5 +9,5 @@ static HELLO: u8 = 0; #[export_name="fail"] pub fn b() { -//~^ symbol `fail` is already defined +//~^ ERROR symbol `fail` is already defined } diff --git a/tests/ui/duplicate/dupe-symbols-6.rs b/tests/ui/duplicate/dupe-symbols-6.rs index 9841be7365a3..b3f430f51bb9 100644 --- a/tests/ui/duplicate/dupe-symbols-6.rs +++ b/tests/ui/duplicate/dupe-symbols-6.rs @@ -8,4 +8,4 @@ static HELLO: u8 = 0; #[export_name="fail"] static HELLO_TWICE: u16 = 0; -//~^ symbol `fail` is already defined +//~^ ERROR symbol `fail` is already defined diff --git a/tests/ui/dyn-compatibility/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.stderr b/tests/ui/dyn-compatibility/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.stderr index 832e7ef4dc38..2cf244185e69 100644 --- a/tests/ui/dyn-compatibility/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.stderr +++ b/tests/ui/dyn-compatibility/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.stderr @@ -187,166 +187,6 @@ help: consider using the `'static` lifetime, but this is uncommon unless you're LL | fn parrot() -> &'static mut Trait { | +++++++ -error[E0782]: expected a type, found a trait - --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:52:16 - | -LL | fn foo(_: &Trait); - | ^^^^^ - | -help: use a new generic type parameter, constrained by `Trait` - | -LL - fn foo(_: &Trait); -LL + fn foo(_: &T); - | -help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference - | -LL | fn foo(_: &impl Trait); - | ++++ -help: alternatively, use a trait object to accept any type that implements `Trait`, accessing its methods at runtime using dynamic dispatch - | -LL | fn foo(_: &dyn Trait); - | +++ - -error[E0782]: expected a type, found a trait - --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:55:19 - | -LL | fn bar(_: &'a Trait); - | ^^^^^ - | -help: use a new generic type parameter, constrained by `Trait` - | -LL - fn bar(_: &'a Trait); -LL + fn bar(_: &'a T); - | -help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference - | -LL | fn bar(_: &'a impl Trait); - | ++++ -help: alternatively, use a trait object to accept any type that implements `Trait`, accessing its methods at runtime using dynamic dispatch - | -LL | fn bar(_: &'a dyn Trait); - | +++ - -error[E0782]: expected a type, found a trait - --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:59:22 - | -LL | fn alice<'a>(_: &Trait); - | ^^^^^ - | -help: use a new generic type parameter, constrained by `Trait` - | -LL - fn alice<'a>(_: &Trait); -LL + fn alice<'a, T: Trait>(_: &T); - | -help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference - | -LL | fn alice<'a>(_: &impl Trait); - | ++++ -help: alternatively, use a trait object to accept any type that implements `Trait`, accessing its methods at runtime using dynamic dispatch - | -LL | fn alice<'a>(_: &dyn Trait); - | +++ - -error[E0782]: expected a type, found a trait - --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:62:23 - | -LL | fn bob<'a>(_: &'a Trait); - | ^^^^^ - | -help: use a new generic type parameter, constrained by `Trait` - | -LL - fn bob<'a>(_: &'a Trait); -LL + fn bob<'a, T: Trait>(_: &'a T); - | -help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference - | -LL | fn bob<'a>(_: &'a impl Trait); - | ++++ -help: alternatively, use a trait object to accept any type that implements `Trait`, accessing its methods at runtime using dynamic dispatch - | -LL | fn bob<'a>(_: &'a dyn Trait); - | +++ - -error[E0782]: expected a type, found a trait - --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:65:18 - | -LL | fn cat() -> &Trait; - | ^^^^^ - | -help: use `impl Trait` to return an opaque type, as long as you return a single underlying type - | -LL | fn cat() -> &impl Trait; - | ++++ -help: alternatively, you can return an owned trait object - | -LL - fn cat() -> &Trait; -LL + fn cat() -> Box; - | - -error[E0782]: expected a type, found a trait - --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:69:22 - | -LL | fn dog<'a>() -> &Trait { - | ^^^^^ - | -help: use `impl Trait` to return an opaque type, as long as you return a single underlying type - | -LL | fn dog<'a>() -> &impl Trait { - | ++++ -help: alternatively, you can return an owned trait object - | -LL - fn dog<'a>() -> &Trait { -LL + fn dog<'a>() -> Box { - | - -error[E0782]: expected a type, found a trait - --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:75:24 - | -LL | fn kitten() -> &'a Trait { - | ^^^^^ - | -help: use `impl Trait` to return an opaque type, as long as you return a single underlying type - | -LL | fn kitten() -> &'a impl Trait { - | ++++ -help: alternatively, you can return an owned trait object - | -LL - fn kitten() -> &'a Trait { -LL + fn kitten() -> Box { - | - -error[E0782]: expected a type, found a trait - --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:81:27 - | -LL | fn puppy<'a>() -> &'a Trait { - | ^^^^^ - | -help: use `impl Trait` to return an opaque type, as long as you return a single underlying type - | -LL | fn puppy<'a>() -> &'a impl Trait { - | ++++ -help: alternatively, you can return an owned trait object - | -LL - fn puppy<'a>() -> &'a Trait { -LL + fn puppy<'a>() -> Box { - | - -error[E0782]: expected a type, found a trait - --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:86:25 - | -LL | fn parrot() -> &mut Trait { - | ^^^^^ - | -help: use `impl Trait` to return an opaque type, as long as you return a single underlying type - | -LL | fn parrot() -> &mut impl Trait { - | ++++ -help: alternatively, you can return an owned trait object - | -LL - fn parrot() -> &mut Trait { -LL + fn parrot() -> Box { - | - error[E0782]: expected a type, found a trait --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:93:12 | @@ -667,6 +507,166 @@ LL - fn parrot() -> &mut Trait { LL + fn parrot() -> Box { | +error[E0782]: expected a type, found a trait + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:52:16 + | +LL | fn foo(_: &Trait); + | ^^^^^ + | +help: use a new generic type parameter, constrained by `Trait` + | +LL - fn foo(_: &Trait); +LL + fn foo(_: &T); + | +help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference + | +LL | fn foo(_: &impl Trait); + | ++++ +help: alternatively, use a trait object to accept any type that implements `Trait`, accessing its methods at runtime using dynamic dispatch + | +LL | fn foo(_: &dyn Trait); + | +++ + +error[E0782]: expected a type, found a trait + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:55:19 + | +LL | fn bar(_: &'a Trait); + | ^^^^^ + | +help: use a new generic type parameter, constrained by `Trait` + | +LL - fn bar(_: &'a Trait); +LL + fn bar(_: &'a T); + | +help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference + | +LL | fn bar(_: &'a impl Trait); + | ++++ +help: alternatively, use a trait object to accept any type that implements `Trait`, accessing its methods at runtime using dynamic dispatch + | +LL | fn bar(_: &'a dyn Trait); + | +++ + +error[E0782]: expected a type, found a trait + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:59:22 + | +LL | fn alice<'a>(_: &Trait); + | ^^^^^ + | +help: use a new generic type parameter, constrained by `Trait` + | +LL - fn alice<'a>(_: &Trait); +LL + fn alice<'a, T: Trait>(_: &T); + | +help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference + | +LL | fn alice<'a>(_: &impl Trait); + | ++++ +help: alternatively, use a trait object to accept any type that implements `Trait`, accessing its methods at runtime using dynamic dispatch + | +LL | fn alice<'a>(_: &dyn Trait); + | +++ + +error[E0782]: expected a type, found a trait + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:62:23 + | +LL | fn bob<'a>(_: &'a Trait); + | ^^^^^ + | +help: use a new generic type parameter, constrained by `Trait` + | +LL - fn bob<'a>(_: &'a Trait); +LL + fn bob<'a, T: Trait>(_: &'a T); + | +help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference + | +LL | fn bob<'a>(_: &'a impl Trait); + | ++++ +help: alternatively, use a trait object to accept any type that implements `Trait`, accessing its methods at runtime using dynamic dispatch + | +LL | fn bob<'a>(_: &'a dyn Trait); + | +++ + +error[E0782]: expected a type, found a trait + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:65:18 + | +LL | fn cat() -> &Trait; + | ^^^^^ + | +help: use `impl Trait` to return an opaque type, as long as you return a single underlying type + | +LL | fn cat() -> &impl Trait; + | ++++ +help: alternatively, you can return an owned trait object + | +LL - fn cat() -> &Trait; +LL + fn cat() -> Box; + | + +error[E0782]: expected a type, found a trait + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:69:22 + | +LL | fn dog<'a>() -> &Trait { + | ^^^^^ + | +help: use `impl Trait` to return an opaque type, as long as you return a single underlying type + | +LL | fn dog<'a>() -> &impl Trait { + | ++++ +help: alternatively, you can return an owned trait object + | +LL - fn dog<'a>() -> &Trait { +LL + fn dog<'a>() -> Box { + | + +error[E0782]: expected a type, found a trait + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:75:24 + | +LL | fn kitten() -> &'a Trait { + | ^^^^^ + | +help: use `impl Trait` to return an opaque type, as long as you return a single underlying type + | +LL | fn kitten() -> &'a impl Trait { + | ++++ +help: alternatively, you can return an owned trait object + | +LL - fn kitten() -> &'a Trait { +LL + fn kitten() -> Box { + | + +error[E0782]: expected a type, found a trait + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:81:27 + | +LL | fn puppy<'a>() -> &'a Trait { + | ^^^^^ + | +help: use `impl Trait` to return an opaque type, as long as you return a single underlying type + | +LL | fn puppy<'a>() -> &'a impl Trait { + | ++++ +help: alternatively, you can return an owned trait object + | +LL - fn puppy<'a>() -> &'a Trait { +LL + fn puppy<'a>() -> Box { + | + +error[E0782]: expected a type, found a trait + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:86:25 + | +LL | fn parrot() -> &mut Trait { + | ^^^^^ + | +help: use `impl Trait` to return an opaque type, as long as you return a single underlying type + | +LL | fn parrot() -> &mut impl Trait { + | ++++ +help: alternatively, you can return an owned trait object + | +LL - fn parrot() -> &mut Trait { +LL + fn parrot() -> Box { + | + error: aborting due to 42 previous errors Some errors have detailed explanations: E0106, E0261, E0782. diff --git a/tests/ui/dyn-compatibility/taint-const-eval.rs b/tests/ui/dyn-compatibility/taint-const-eval.rs index 7ea763e18469..64c4df611e65 100644 --- a/tests/ui/dyn-compatibility/taint-const-eval.rs +++ b/tests/ui/dyn-compatibility/taint-const-eval.rs @@ -5,8 +5,8 @@ trait Qux { } static FOO: &(dyn Qux + Sync) = "desc"; -//~^ the trait `Qux` is not dyn compatible -//~| the trait `Qux` is not dyn compatible -//~| the trait `Qux` is not dyn compatible +//~^ ERROR the trait `Qux` is not dyn compatible +//~| ERROR the trait `Qux` is not dyn compatible +//~| ERROR the trait `Qux` is not dyn compatible fn main() {} diff --git a/tests/ui/dyn-compatibility/trait-alias-self-projection.rs b/tests/ui/dyn-compatibility/trait-alias-self-projection.rs new file mode 100644 index 000000000000..0badb738809e --- /dev/null +++ b/tests/ui/dyn-compatibility/trait-alias-self-projection.rs @@ -0,0 +1,12 @@ +#![feature(trait_alias)] +trait B = Fn() -> Self; +type D = &'static dyn B; +//~^ ERROR E0411 + +fn a() -> D { + unreachable!(); +} + +fn main() { + _ = a(); +} diff --git a/tests/ui/dyn-compatibility/trait-alias-self-projection.stderr b/tests/ui/dyn-compatibility/trait-alias-self-projection.stderr new file mode 100644 index 000000000000..dccee02e9cd1 --- /dev/null +++ b/tests/ui/dyn-compatibility/trait-alias-self-projection.stderr @@ -0,0 +1,9 @@ +error[E0411]: `Self` is not allowed in type aliases + --> $DIR/trait-alias-self-projection.rs:3:19 + | +LL | type D = &'static dyn B; + | ^^^^^ `Self` is only available in impls, traits, and concrete type definitions + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0411`. diff --git a/tests/ui/dyn-star/async-block-dyn-star.rs b/tests/ui/dyn-star/async-block-dyn-star.rs index 9bffd6c67253..db133d94c918 100644 --- a/tests/ui/dyn-star/async-block-dyn-star.rs +++ b/tests/ui/dyn-star/async-block-dyn-star.rs @@ -4,6 +4,6 @@ //~^ WARN the feature `dyn_star` is incomplete static S: dyn* Send + Sync = async { 42 }; -//~^ needs to have the same ABI as a pointer +//~^ ERROR needs to have the same ABI as a pointer pub fn main() {} diff --git a/tests/ui/dyn-star/feature-gate-dyn_star.rs b/tests/ui/dyn-star/feature-gate-dyn_star.rs index 41eed71cdc30..b12fd7755be0 100644 --- a/tests/ui/dyn-star/feature-gate-dyn_star.rs +++ b/tests/ui/dyn-star/feature-gate-dyn_star.rs @@ -3,7 +3,7 @@ /// dyn* is not necessarily the final surface syntax (if we have one at all), /// but for now we will support it to aid in writing tests independently. pub fn dyn_star_parameter(_: &dyn* Send) { - //~^ `dyn*` trait objects are experimental + //~^ ERROR `dyn*` trait objects are experimental } fn main() {} diff --git a/tests/ui/editions/never-type-fallback-breaking.e2021.fixed b/tests/ui/editions/never-type-fallback-breaking.e2021.fixed index 11ec273fc4bf..8c11ab0791dd 100644 --- a/tests/ui/editions/never-type-fallback-breaking.e2021.fixed +++ b/tests/ui/editions/never-type-fallback-breaking.e2021.fixed @@ -16,8 +16,8 @@ fn main() { } fn m() { - //[e2021]~^ this function depends on never type fallback being `()` - //[e2021]~| this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! + //[e2021]~^ WARN this function depends on never type fallback being `()` + //[e2021]~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! let x: () = match true { true => Default::default(), //[e2024]~^ error: the trait bound `!: Default` is not satisfied @@ -28,8 +28,8 @@ fn m() { } fn q() -> Option<()> { - //[e2021]~^ this function depends on never type fallback being `()` - //[e2021]~| this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! + //[e2021]~^ WARN this function depends on never type fallback being `()` + //[e2021]~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! fn deserialize() -> Option { Some(T::default()) } @@ -45,8 +45,8 @@ fn help<'a: 'a, T: Into<()>, U>(_: U) -> Result { Err(()) } fn meow() -> Result<(), ()> { - //[e2021]~^ this function depends on never type fallback being `()` - //[e2021]~| this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! + //[e2021]~^ WARN this function depends on never type fallback being `()` + //[e2021]~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! help::<(), _>(1)?; //[e2024]~^ error: the trait bound `(): From` is not satisfied Ok(()) @@ -57,8 +57,8 @@ pub fn takes_apit(_y: impl Fn() -> T) -> Result { } pub fn fallback_return() -> Result<(), ()> { - //[e2021]~^ this function depends on never type fallback being `()` - //[e2021]~| this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! + //[e2021]~^ WARN this function depends on never type fallback being `()` + //[e2021]~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! takes_apit::<()>(|| Default::default())?; //[e2024]~^ error: the trait bound `!: Default` is not satisfied Ok(()) @@ -71,8 +71,8 @@ fn mk() -> Result { fn takes_apit2(_x: impl Default) {} fn fully_apit() -> Result<(), ()> { - //[e2021]~^ this function depends on never type fallback being `()` - //[e2021]~| this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! + //[e2021]~^ WARN this function depends on never type fallback being `()` + //[e2021]~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! takes_apit2(mk::<()>()?); //[e2024]~^ error: the trait bound `!: Default` is not satisfied Ok(()) diff --git a/tests/ui/editions/never-type-fallback-breaking.rs b/tests/ui/editions/never-type-fallback-breaking.rs index daafc526eff4..80974f830137 100644 --- a/tests/ui/editions/never-type-fallback-breaking.rs +++ b/tests/ui/editions/never-type-fallback-breaking.rs @@ -16,8 +16,8 @@ fn main() { } fn m() { - //[e2021]~^ this function depends on never type fallback being `()` - //[e2021]~| this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! + //[e2021]~^ WARN this function depends on never type fallback being `()` + //[e2021]~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! let x = match true { true => Default::default(), //[e2024]~^ error: the trait bound `!: Default` is not satisfied @@ -28,8 +28,8 @@ fn m() { } fn q() -> Option<()> { - //[e2021]~^ this function depends on never type fallback being `()` - //[e2021]~| this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! + //[e2021]~^ WARN this function depends on never type fallback being `()` + //[e2021]~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! fn deserialize() -> Option { Some(T::default()) } @@ -45,8 +45,8 @@ fn help<'a: 'a, T: Into<()>, U>(_: U) -> Result { Err(()) } fn meow() -> Result<(), ()> { - //[e2021]~^ this function depends on never type fallback being `()` - //[e2021]~| this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! + //[e2021]~^ WARN this function depends on never type fallback being `()` + //[e2021]~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! help(1)?; //[e2024]~^ error: the trait bound `(): From` is not satisfied Ok(()) @@ -57,8 +57,8 @@ pub fn takes_apit(_y: impl Fn() -> T) -> Result { } pub fn fallback_return() -> Result<(), ()> { - //[e2021]~^ this function depends on never type fallback being `()` - //[e2021]~| this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! + //[e2021]~^ WARN this function depends on never type fallback being `()` + //[e2021]~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! takes_apit(|| Default::default())?; //[e2024]~^ error: the trait bound `!: Default` is not satisfied Ok(()) @@ -71,8 +71,8 @@ fn mk() -> Result { fn takes_apit2(_x: impl Default) {} fn fully_apit() -> Result<(), ()> { - //[e2021]~^ this function depends on never type fallback being `()` - //[e2021]~| this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! + //[e2021]~^ WARN this function depends on never type fallback being `()` + //[e2021]~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! takes_apit2(mk()?); //[e2024]~^ error: the trait bound `!: Default` is not satisfied Ok(()) diff --git a/tests/ui/enum-discriminant/discriminant-ill-typed.rs b/tests/ui/enum-discriminant/discriminant-ill-typed.rs index 3cf0ea0e6b99..e3cbd01a1ddf 100644 --- a/tests/ui/enum-discriminant/discriminant-ill-typed.rs +++ b/tests/ui/enum-discriminant/discriminant-ill-typed.rs @@ -14,7 +14,7 @@ fn f_i8() { Ok2, OhNo = 0_u8, //~^ ERROR mismatched types - //~| expected `i8`, found `u8` + //~| NOTE expected `i8`, found `u8` } let x = A::Ok; @@ -27,7 +27,7 @@ fn f_u8() { Ok2, OhNo = 0_i8, //~^ ERROR mismatched types - //~| expected `u8`, found `i8` + //~| NOTE expected `u8`, found `i8` } let x = A::Ok; @@ -40,7 +40,7 @@ fn f_i16() { Ok2, OhNo = 0_u16, //~^ ERROR mismatched types - //~| expected `i16`, found `u16` + //~| NOTE expected `i16`, found `u16` } let x = A::Ok; @@ -53,7 +53,7 @@ fn f_u16() { Ok2, OhNo = 0_i16, //~^ ERROR mismatched types - //~| expected `u16`, found `i16` + //~| NOTE expected `u16`, found `i16` } let x = A::Ok; @@ -66,7 +66,7 @@ fn f_i32() { Ok2, OhNo = 0_u32, //~^ ERROR mismatched types - //~| expected `i32`, found `u32` + //~| NOTE expected `i32`, found `u32` } let x = A::Ok; @@ -79,7 +79,7 @@ fn f_u32() { Ok2, OhNo = 0_i32, //~^ ERROR mismatched types - //~| expected `u32`, found `i32` + //~| NOTE expected `u32`, found `i32` } let x = A::Ok; @@ -92,7 +92,7 @@ fn f_i64() { Ok2, OhNo = 0_u64, //~^ ERROR mismatched types - //~| expected `i64`, found `u64` + //~| NOTE expected `i64`, found `u64` } let x = A::Ok; @@ -105,7 +105,7 @@ fn f_u64() { Ok2, OhNo = 0_i64, //~^ ERROR mismatched types - //~| expected `u64`, found `i64` + //~| NOTE expected `u64`, found `i64` } let x = A::Ok; diff --git a/tests/ui/ergonomic-clones/closure/multiple-use-variants.rs b/tests/ui/ergonomic-clones/closure/multiple-use-variants.rs new file mode 100644 index 000000000000..e2e9820a740f --- /dev/null +++ b/tests/ui/ergonomic-clones/closure/multiple-use-variants.rs @@ -0,0 +1,35 @@ +#![feature(ergonomic_clones)] +#![allow(incomplete_features)] + +use std::clone::UseCloned; + +fn takes_val(_: T) {} +fn takes_ref<'a, T>(_: &'a T) {} + +#[derive(Clone)] +struct Inner<'a, T>(&'a T); + +impl<'a, T> UseCloned for Inner<'a, T> where T: Clone {} + +fn main() { + let v = String::new(); + let inner = Inner(&v); + + let _ = use || { + takes_ref(inner.0); + takes_val(inner.0) + }; + let _ = use || { + takes_ref(inner.0); + takes_val(inner.0); + takes_val(inner.0); + takes_val(inner) + }; + let _ = use || { + takes_ref(inner.0); + takes_val(inner.0); + takes_val(inner); + takes_val(inner) + //~^ ERROR: use of moved value: `inner` [E0382] + }; +} diff --git a/tests/ui/ergonomic-clones/closure/multiple-use-variants.stderr b/tests/ui/ergonomic-clones/closure/multiple-use-variants.stderr new file mode 100644 index 000000000000..7b25ca9bba83 --- /dev/null +++ b/tests/ui/ergonomic-clones/closure/multiple-use-variants.stderr @@ -0,0 +1,13 @@ +error[E0382]: use of moved value: `inner` + --> $DIR/multiple-use-variants.rs:32:19 + | +LL | takes_val(inner); + | ----- value moved here +LL | takes_val(inner) + | ^^^^^ value used here after move + | + = note: move occurs because `inner` has type `Inner<'_, String>`, which does not implement the `Copy` trait + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/ergonomic-clones/closure/rfc2229-migration.fixed b/tests/ui/ergonomic-clones/closure/rfc2229-migration.fixed new file mode 100644 index 000000000000..fa83b53526a8 --- /dev/null +++ b/tests/ui/ergonomic-clones/closure/rfc2229-migration.fixed @@ -0,0 +1,26 @@ +//@ run-rustfix +//@ edition:2018 +//@ check-pass +#![feature(ergonomic_clones)] +#![warn(rust_2021_compatibility)] +#![allow(incomplete_features)] + +#[derive(Debug)] +struct Foo(i32); +impl Drop for Foo { + fn drop(&mut self) { + println!("{:?} dropped", self.0); + } +} + +fn main() { + let a = (Foo(0), Foo(1)); + let f = use || { + let _ = &a; + //~^ HELP: add a dummy + //~| WARNING: drop order + let x = a.0; + println!("{:?}", x); + }; + f(); +} diff --git a/tests/ui/ergonomic-clones/closure/rfc2229-migration.rs b/tests/ui/ergonomic-clones/closure/rfc2229-migration.rs new file mode 100644 index 000000000000..4070e5c35a44 --- /dev/null +++ b/tests/ui/ergonomic-clones/closure/rfc2229-migration.rs @@ -0,0 +1,25 @@ +//@ run-rustfix +//@ edition:2018 +//@ check-pass +#![feature(ergonomic_clones)] +#![warn(rust_2021_compatibility)] +#![allow(incomplete_features)] + +#[derive(Debug)] +struct Foo(i32); +impl Drop for Foo { + fn drop(&mut self) { + println!("{:?} dropped", self.0); + } +} + +fn main() { + let a = (Foo(0), Foo(1)); + let f = use || { + //~^ HELP: add a dummy + //~| WARNING: drop order + let x = a.0; + println!("{:?}", x); + }; + f(); +} diff --git a/tests/ui/ergonomic-clones/closure/rfc2229-migration.stderr b/tests/ui/ergonomic-clones/closure/rfc2229-migration.stderr new file mode 100644 index 000000000000..b980be6cb86b --- /dev/null +++ b/tests/ui/ergonomic-clones/closure/rfc2229-migration.stderr @@ -0,0 +1,27 @@ +warning: changes to closure capture in Rust 2021 will affect drop order + --> $DIR/rfc2229-migration.rs:18:13 + | +LL | let f = use || { + | ^^^^^^ +... +LL | let x = 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 + | + = note: for more information, see +note: the lint level is defined here + --> $DIR/rfc2229-migration.rs:5:9 + | +LL | #![warn(rust_2021_compatibility)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + = note: `#[warn(rust_2021_incompatible_closure_captures)]` implied by `#[warn(rust_2021_compatibility)]` +help: add a dummy let to cause `a` to be fully captured + | +LL ~ let f = use || { +LL + let _ = &a; + | + +warning: 1 warning emitted + diff --git a/tests/ui/ergonomic-clones/closure/spawn-thread.edition2018.stderr b/tests/ui/ergonomic-clones/closure/spawn-thread.edition2018.stderr new file mode 100644 index 000000000000..ac8e1c5fa858 --- /dev/null +++ b/tests/ui/ergonomic-clones/closure/spawn-thread.edition2018.stderr @@ -0,0 +1,28 @@ +error[E0382]: use of moved value: `x` + --> $DIR/spawn-thread.rs:15:42 + | +LL | let x = (Arc::new("foo".to_owned()), Arc::new(vec![1, 2, 3]), Arc::new(1)); + | - move occurs because `x` has type `(Arc, Arc>, Arc)`, which does not implement the `Copy` trait +LL | for _ in 0..10 { + | -------------- inside of this loop +LL | let handler = std::thread::spawn(use || { + | __________________________________________-^^^^^ +LL | | +LL | | drop((x.0, x.1, x.2)); + | | --- use occurs due to use in closure +LL | | }); + | |_________- value moved here, in previous iteration of loop + | +help: consider moving the expression out of the loop so it is only moved once + | +LL ~ let mut value = std::thread::spawn(use || { +LL + +LL + drop((x.0, x.1, x.2)); +LL + }); +LL ~ for _ in 0..10 { +LL ~ let handler = value; + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/ergonomic-clones/closure/spawn-thread.rs b/tests/ui/ergonomic-clones/closure/spawn-thread.rs new file mode 100644 index 000000000000..289d446c6e6f --- /dev/null +++ b/tests/ui/ergonomic-clones/closure/spawn-thread.rs @@ -0,0 +1,50 @@ +//@ revisions: edition2018 edition2024 +//@ [edition2018] edition: 2018 +//@ [edition2024] edition: 2024 +//@ [edition2024] check-pass + +#![feature(ergonomic_clones)] +#![allow(incomplete_features)] + +use std::sync::Arc; + +fn foo() { + // The type is a tuple and doesn't implement UseCloned + let x = (Arc::new("foo".to_owned()), Arc::new(vec![1, 2, 3]), Arc::new(1)); + for _ in 0..10 { + let handler = std::thread::spawn(use || { + //[edition2018]~^ ERROR use of moved value: `x` [E0382] + drop((x.0, x.1, x.2)); + }); + handler.join().unwrap(); + } +} + +fn bar() { + let x = Arc::new("foo".to_owned()); + let y = Arc::new(vec![1, 2, 3]); + let z = Arc::new(1); + + for _ in 0..10 { + let handler = std::thread::spawn(use || { + drop((x, y, z)); + }); + handler.join().unwrap(); + } +} + +fn baz() { + use std::sync::Arc; + use std::thread; + + let five = Arc::new(5); + + for _ in 0..10 { + let handler = thread::spawn(use || { + println!("{five:?}"); + }); + handler.join().unwrap(); + } +} + +fn main() {} diff --git a/tests/ui/ergonomic-clones/dotuse/block.rs b/tests/ui/ergonomic-clones/dotuse/block.rs new file mode 100644 index 000000000000..2e423c67d02b --- /dev/null +++ b/tests/ui/ergonomic-clones/dotuse/block.rs @@ -0,0 +1,11 @@ +//@ check-pass + +#![feature(ergonomic_clones)] +#![allow(incomplete_features)] + +fn use_block_test(x: i32) -> i32 { + let x = { let x = x + 1; x }.use; + x +} + +fn main() {} diff --git a/tests/ui/error-codes/E0063.rs b/tests/ui/error-codes/E0063.rs index 48c9c13f018f..2ef09b0a426a 100644 --- a/tests/ui/error-codes/E0063.rs +++ b/tests/ui/error-codes/E0063.rs @@ -32,7 +32,7 @@ fn main() { let x = PluralFoo {x: 1}; //~^ ERROR missing fields `y` and `z` in initializer of `PluralFoo` let y = TruncatedFoo{x:1}; - //~^ missing fields `a`, `b`, `y` and 1 other field in initializer of `TruncatedFoo` + //~^ ERROR missing fields `a`, `b`, `y` and 1 other field in initializer of `TruncatedFoo` let z = TruncatedPluralFoo{x:1}; //~^ ERROR missing fields `a`, `b`, `c` and 2 other fields in initializer of `TruncatedPluralFoo` } diff --git a/tests/ui/error-codes/E0092.rs b/tests/ui/error-codes/E0092.rs index ddaace98bd4a..19a7c65a48ed 100644 --- a/tests/ui/error-codes/E0092.rs +++ b/tests/ui/error-codes/E0092.rs @@ -1,7 +1,6 @@ #![feature(intrinsics)] -extern "rust-intrinsic" { - fn atomic_foo(); //~ ERROR E0092 -} -fn main() { -} +#[rustc_intrinsic] +unsafe fn atomic_foo(); //~ ERROR E0092 + +fn main() {} diff --git a/tests/ui/error-codes/E0092.stderr b/tests/ui/error-codes/E0092.stderr index 4ff2e6f077d2..003c989fd596 100644 --- a/tests/ui/error-codes/E0092.stderr +++ b/tests/ui/error-codes/E0092.stderr @@ -1,8 +1,8 @@ error[E0092]: unrecognized atomic operation function: `foo` - --> $DIR/E0092.rs:3:5 + --> $DIR/E0092.rs:4:11 | -LL | fn atomic_foo(); - | ^^^^^^^^^^^^^^^^ unrecognized atomic operation +LL | unsafe fn atomic_foo(); + | ^^^^^^^^^^ unrecognized atomic operation error: aborting due to 1 previous error diff --git a/tests/ui/error-codes/E0093.rs b/tests/ui/error-codes/E0093.rs index a2f0b1ae4437..24df7a9a32b9 100644 --- a/tests/ui/error-codes/E0093.rs +++ b/tests/ui/error-codes/E0093.rs @@ -1,8 +1,7 @@ #![feature(intrinsics)] -extern "rust-intrinsic" { - fn foo(); - //~^ ERROR E0093 -} -fn main() { -} +#[rustc_intrinsic] +unsafe fn foo(); +//~^ ERROR E0093 + +fn main() {} diff --git a/tests/ui/error-codes/E0093.stderr b/tests/ui/error-codes/E0093.stderr index 51c367b343ab..d81bf53976ae 100644 --- a/tests/ui/error-codes/E0093.stderr +++ b/tests/ui/error-codes/E0093.stderr @@ -1,8 +1,8 @@ error[E0093]: unrecognized intrinsic function: `foo` - --> $DIR/E0093.rs:3:5 + --> $DIR/E0093.rs:4:11 | -LL | fn foo(); - | ^^^^^^^^^ unrecognized intrinsic +LL | unsafe fn foo(); + | ^^^ unrecognized intrinsic | = help: if you're adding an intrinsic, be sure to update `check_intrinsic_type` diff --git a/tests/ui/error-codes/E0152-duplicate-lang-items.rs b/tests/ui/error-codes/E0152-duplicate-lang-items.rs index 089810b1ad24..f707b72f9b2b 100644 --- a/tests/ui/error-codes/E0152-duplicate-lang-items.rs +++ b/tests/ui/error-codes/E0152-duplicate-lang-items.rs @@ -3,8 +3,9 @@ //! //! Issue: -//@ error-pattern: first defined in crate `std` //@ normalize-stderr: "loaded from .*libstd-.*.rlib" -> "loaded from SYSROOT/libstd-*.rlib" +//@ dont-require-annotations: NOTE + #![feature(lang_items)] extern crate core; @@ -14,6 +15,7 @@ use core::panic::PanicInfo; #[lang = "panic_impl"] fn panic_impl(info: &PanicInfo) -> ! { //~^ ERROR: found duplicate lang item `panic_impl` + //~| NOTE first defined in crate `std` loop {} } diff --git a/tests/ui/error-codes/E0152-duplicate-lang-items.stderr b/tests/ui/error-codes/E0152-duplicate-lang-items.stderr index 3c3d64322f3c..2fe0d18fc2f4 100644 --- a/tests/ui/error-codes/E0152-duplicate-lang-items.stderr +++ b/tests/ui/error-codes/E0152-duplicate-lang-items.stderr @@ -1,8 +1,9 @@ error[E0152]: found duplicate lang item `panic_impl` - --> $DIR/E0152-duplicate-lang-items.rs:15:1 + --> $DIR/E0152-duplicate-lang-items.rs:16:1 | LL | / fn panic_impl(info: &PanicInfo) -> ! { LL | | +LL | | LL | | loop {} LL | | } | |_^ diff --git a/tests/ui/error-codes/E0186.rs b/tests/ui/error-codes/E0186.rs index 83ef78ef2c03..9b507f9b9882 100644 --- a/tests/ui/error-codes/E0186.rs +++ b/tests/ui/error-codes/E0186.rs @@ -1,12 +1,12 @@ trait Foo { - fn foo(&self); //~ `&self` used in trait + fn foo(&self); //~ NOTE `&self` used in trait } struct Bar; impl Foo for Bar { fn foo() {} //~ ERROR E0186 - //~^ expected `&self` in impl + //~^ NOTE expected `&self` in impl } fn main() { diff --git a/tests/ui/error-codes/E0261.rs b/tests/ui/error-codes/E0261.rs index f05e09aa0da6..e37eab9501ed 100644 --- a/tests/ui/error-codes/E0261.rs +++ b/tests/ui/error-codes/E0261.rs @@ -1,9 +1,9 @@ fn foo(x: &'a str) { } //~ ERROR E0261 - //~| undeclared lifetime + //~| NOTE undeclared lifetime struct Foo { x: &'a str, //~ ERROR E0261 - //~| undeclared lifetime + //~| NOTE undeclared lifetime } fn main() {} diff --git a/tests/ui/error-codes/E0262.rs b/tests/ui/error-codes/E0262.rs index 55264f1387f8..460ea95148c4 100644 --- a/tests/ui/error-codes/E0262.rs +++ b/tests/ui/error-codes/E0262.rs @@ -1,4 +1,4 @@ fn foo<'static>(x: &'static str) { } //~ ERROR E0262 - //~| 'static is a reserved lifetime name + //~| NOTE 'static is a reserved lifetime name fn main() {} diff --git a/tests/ui/error-codes/E0516.rs b/tests/ui/error-codes/E0516.rs index 834bb630989f..f81b98cdadc8 100644 --- a/tests/ui/error-codes/E0516.rs +++ b/tests/ui/error-codes/E0516.rs @@ -1,4 +1,4 @@ fn main() { let x: typeof(92) = 92; //~ ERROR E0516 - //~| reserved keyword + //~| NOTE reserved keyword } diff --git a/tests/ui/error-codes/E0597.rs b/tests/ui/error-codes/E0597.rs index 7217e351281d..ebe42f54212f 100644 --- a/tests/ui/error-codes/E0597.rs +++ b/tests/ui/error-codes/E0597.rs @@ -6,7 +6,7 @@ fn main() { let mut x = Foo { x: None }; let y = 0; x.x = Some(&y); - //~^ `y` does not live long enough [E0597] + //~^ ERROR `y` does not live long enough [E0597] } impl<'a> Drop for Foo<'a> { fn drop(&mut self) { } } diff --git a/tests/ui/error-codes/E0602.rs b/tests/ui/error-codes/E0602.rs index cba15bb92d45..381bd1ffb54c 100644 --- a/tests/ui/error-codes/E0602.rs +++ b/tests/ui/error-codes/E0602.rs @@ -1,11 +1,11 @@ //@ compile-flags:-D bogus //@ check-pass - -//@ error-pattern:requested on the command line with `-D bogus` -//@ error-pattern:`#[warn(unknown_lints)]` on by default +//@ dont-require-annotations: NOTE fn main() {} //~? WARN unknown lint: `bogus` //~? WARN unknown lint: `bogus` //~? WARN unknown lint: `bogus` +//~? NOTE requested on the command line with `-D bogus` +//~? NOTE `#[warn(unknown_lints)]` on by default diff --git a/tests/ui/error-codes/E0606.rs b/tests/ui/error-codes/E0606.rs index 6f6c6513846c..2d430fcdc169 100644 --- a/tests/ui/error-codes/E0606.rs +++ b/tests/ui/error-codes/E0606.rs @@ -1,4 +1,4 @@ fn main() { let x = &(&0u8 as u8); //~ ERROR E0606 - x as u8; //~ casting `&u8` as `u8` is invalid [E0606] + x as u8; //~ ERROR casting `&u8` as `u8` is invalid [E0606] } diff --git a/tests/ui/error-codes/E0622.rs b/tests/ui/error-codes/E0622.rs deleted file mode 100644 index 08c6d1712960..000000000000 --- a/tests/ui/error-codes/E0622.rs +++ /dev/null @@ -1,6 +0,0 @@ -#![feature(intrinsics)] -extern "rust-intrinsic" { - pub static atomic_singlethreadfence_seqcst : unsafe extern "rust-intrinsic" fn(); - //~^ ERROR intrinsic must be a function [E0622] -} -fn main() { unsafe { atomic_singlethreadfence_seqcst(); } } diff --git a/tests/ui/error-codes/E0622.stderr b/tests/ui/error-codes/E0622.stderr deleted file mode 100644 index 739ec984fc60..000000000000 --- a/tests/ui/error-codes/E0622.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0622]: intrinsic must be a function - --> $DIR/E0622.rs:3:5 - | -LL | pub static atomic_singlethreadfence_seqcst : unsafe extern "rust-intrinsic" fn(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected a function - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0622`. diff --git a/tests/ui/errors/pic-linker.rs b/tests/ui/errors/pic-linker.rs index d90989903048..36495ca8fe95 100644 --- a/tests/ui/errors/pic-linker.rs +++ b/tests/ui/errors/pic-linker.rs @@ -5,6 +5,7 @@ //@ ignore-windows //@ ignore-macos //@ ignore-cross-compile +//@ ignore-aix //@ compile-flags: -Clink-args=-Wl,-z,text //@ run-pass diff --git a/tests/ui/expr/if/attrs/bad-cfg.rs b/tests/ui/expr/if/attrs/bad-cfg.rs index 3f84929a00e4..6e7f4b007a92 100644 --- a/tests/ui/expr/if/attrs/bad-cfg.rs +++ b/tests/ui/expr/if/attrs/bad-cfg.rs @@ -1,5 +1,5 @@ #![feature(stmt_expr_attributes)] fn main() { - let _ = #[cfg(FALSE)] if true {}; //~ ERROR removing an expression + let _ = #[cfg(false)] if true {}; //~ ERROR removing an expression } diff --git a/tests/ui/expr/if/attrs/bad-cfg.stderr b/tests/ui/expr/if/attrs/bad-cfg.stderr index ca0eced267d6..d12f5eeaf5fa 100644 --- a/tests/ui/expr/if/attrs/bad-cfg.stderr +++ b/tests/ui/expr/if/attrs/bad-cfg.stderr @@ -1,7 +1,7 @@ error: removing an expression is not supported in this position --> $DIR/bad-cfg.rs:4:13 | -LL | let _ = #[cfg(FALSE)] if true {}; +LL | let _ = #[cfg(false)] if true {}; | ^^^^^^^^^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/expr/if/attrs/cfg-false-if-attr.rs b/tests/ui/expr/if/attrs/cfg-false-if-attr.rs index c139b347d998..e6c83b86cb77 100644 --- a/tests/ui/expr/if/attrs/cfg-false-if-attr.rs +++ b/tests/ui/expr/if/attrs/cfg-false-if-attr.rs @@ -1,12 +1,12 @@ //@ check-pass -#[cfg(FALSE)] +#[cfg(false)] fn simple_attr() { #[attr] if true {} #[allow_warnings] if true {} } -#[cfg(FALSE)] +#[cfg(false)] fn if_else_chain() { #[first_attr] if true { } else if false { @@ -14,20 +14,20 @@ fn if_else_chain() { } } -#[cfg(FALSE)] +#[cfg(false)] fn if_let() { #[attr] if let Some(_) = Some(true) {} } fn bar() { - #[cfg(FALSE)] + #[cfg(false)] if true { - let x: () = true; // Should not error due to the #[cfg(FALSE)] + let x: () = true; // Should not error due to the #[cfg(false)] } - #[cfg_attr(not(FALSE), cfg(FALSE))] + #[cfg_attr(not(FALSE), cfg(false))] if true { - let a: () = true; // Should not error due to the applied #[cfg(FALSE)] + let a: () = true; // Should not error due to the applied #[cfg(false)] } } diff --git a/tests/ui/expr/if/attrs/else-attrs.rs b/tests/ui/expr/if/attrs/else-attrs.rs index 85da7cf6bb8c..4010d9d6132b 100644 --- a/tests/ui/expr/if/attrs/else-attrs.rs +++ b/tests/ui/expr/if/attrs/else-attrs.rs @@ -1,11 +1,11 @@ -#[cfg(FALSE)] +#[cfg(false)] fn if_else_parse_error() { if true { } #[attr] else if false { //~ ERROR expected } } -#[cfg(FALSE)] +#[cfg(false)] fn else_attr_ifparse_error() { if true { } else #[attr] if false { //~ ERROR outer attributes are not allowed @@ -13,7 +13,7 @@ fn else_attr_ifparse_error() { } } -#[cfg(FALSE)] +#[cfg(false)] fn else_parse_error() { if true { } else if false { diff --git a/tests/ui/expr/if/attrs/gate-whole-expr.rs b/tests/ui/expr/if/attrs/gate-whole-expr.rs index bab01592c247..885909016b5e 100644 --- a/tests/ui/expr/if/attrs/gate-whole-expr.rs +++ b/tests/ui/expr/if/attrs/gate-whole-expr.rs @@ -3,7 +3,7 @@ fn main() { let x = 1; - #[cfg(FALSE)] + #[cfg(false)] if false { x = 2; } else if true { diff --git a/tests/ui/expr/if/attrs/let-chains-attr.rs b/tests/ui/expr/if/attrs/let-chains-attr.rs index b3dbd53e5798..2cf1b169f069 100644 --- a/tests/ui/expr/if/attrs/let-chains-attr.rs +++ b/tests/ui/expr/if/attrs/let-chains-attr.rs @@ -2,7 +2,7 @@ #![feature(let_chains)] -#[cfg(FALSE)] +#[cfg(false)] fn foo() { #[attr] if let Some(_) = Some(true) && let Ok(_) = Ok(1) { diff --git a/tests/ui/extern-flag/invalid-crate-name-dashed.rs b/tests/ui/extern-flag/invalid-crate-name-dashed.rs index b336cc84569e..bbf473cc5142 100644 --- a/tests/ui/extern-flag/invalid-crate-name-dashed.rs +++ b/tests/ui/extern-flag/invalid-crate-name-dashed.rs @@ -1,5 +1,4 @@ //@ compile-flags: --extern=my-awesome-library=libawesome.rlib -//@ error-pattern: consider replacing the dashes with underscores: `my_awesome_library` // In a sense, this is a regression test for issue #113035. We no longer suggest // `pub use my-awesome-library::*;` (sic!) as we outright ban this crate name. @@ -9,3 +8,4 @@ pub use my_awesome_library::*; fn main() {} //~? ERROR crate name `my-awesome-library` passed to `--extern` is not a valid ASCII identifier +//~? HELP consider replacing the dashes with underscores: `my_awesome_library` diff --git a/tests/ui/extern/extern-main-issue-86110.rs b/tests/ui/extern/extern-main-issue-86110.rs index 83af7a14ccc7..007d13717040 100644 --- a/tests/ui/extern/extern-main-issue-86110.rs +++ b/tests/ui/extern/extern-main-issue-86110.rs @@ -2,6 +2,6 @@ extern "C" { fn missing(); fn main(); - //~^ the `main` function cannot be declared in an `extern` block + //~^ ERROR the `main` function cannot be declared in an `extern` block fn missing2(); } diff --git a/tests/ui/extern/extern-with-type-bounds.rs b/tests/ui/extern/extern-with-type-bounds.rs deleted file mode 100644 index 3fbddfc99a6f..000000000000 --- a/tests/ui/extern/extern-with-type-bounds.rs +++ /dev/null @@ -1,21 +0,0 @@ -#![feature(intrinsics, rustc_attrs)] - -// Intrinsics are the only (?) extern blocks supporting generics. -// Once intrinsics have to be declared via `#[rustc_intrinsic]`, -// the entire support for generics in extern fn can probably be removed. - -extern "rust-intrinsic" { - // Silent bounds made explicit to make sure they are actually - // resolved. - fn transmute(val: T) -> U; - - // Bounds aren't checked right now, so this should work - // even though it's incorrect. - fn size_of_val(x: *const T) -> usize; - - // Unresolved bounds should still error. - fn align_of() -> usize; - //~^ ERROR cannot find trait `NoSuchTrait` in this scope -} - -fn main() {} diff --git a/tests/ui/extern/extern-with-type-bounds.stderr b/tests/ui/extern/extern-with-type-bounds.stderr deleted file mode 100644 index 893947e831fd..000000000000 --- a/tests/ui/extern/extern-with-type-bounds.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0405]: cannot find trait `NoSuchTrait` in this scope - --> $DIR/extern-with-type-bounds.rs:17:20 - | -LL | fn align_of() -> usize; - | ^^^^^^^^^^^ not found in this scope - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0405`. diff --git a/tests/ui/extern/issue-112363-extern-item-where-clauses-debug-ice.rs b/tests/ui/extern/issue-112363-extern-item-where-clauses-debug-ice.rs index 17e08f511d71..6a4b7814ef18 100644 --- a/tests/ui/extern/issue-112363-extern-item-where-clauses-debug-ice.rs +++ b/tests/ui/extern/issue-112363-extern-item-where-clauses-debug-ice.rs @@ -1,10 +1,10 @@ extern "C" { type Item = [T] where [T]: Sized; - //~^ incorrect `type` inside `extern` block - //~| `type`s inside `extern` blocks cannot have `where` clauses - //~| cannot find type `T` in this scope - //~| cannot find type `T` in this scope - //~| extern types are experimental + //~^ ERROR incorrect `type` inside `extern` block + //~| ERROR `type`s inside `extern` blocks cannot have `where` clauses + //~| ERROR cannot find type `T` in this scope + //~| ERROR cannot find type `T` in this scope + //~| ERROR extern types are experimental } fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-abi.rs b/tests/ui/feature-gates/feature-gate-abi.rs index 2af623734ee8..bafd3643788e 100644 --- a/tests/ui/feature-gates/feature-gate-abi.rs +++ b/tests/ui/feature-gates/feature-gate-abi.rs @@ -8,19 +8,10 @@ extern crate minicore; use minicore::*; -// Functions -extern "rust-intrinsic" fn f1() {} //~ ERROR extern "rust-intrinsic" ABI is an implementation detail - //~^ ERROR intrinsic must be in -extern "rust-intrinsic" fn f2() {} //~ ERROR extern "rust-intrinsic" ABI is an implementation detail - //~^ ERROR intrinsic must be in extern "rust-call" fn f4(_: ()) {} //~ ERROR extern "rust-call" ABI is experimental and subject to change // Methods in trait definition trait Tr { - extern "rust-intrinsic" fn m1(); //~ ERROR extern "rust-intrinsic" ABI is an implementation detail - //~^ ERROR intrinsic must be in - extern "rust-intrinsic" fn m2(); //~ ERROR extern "rust-intrinsic" ABI is an implementation detail - //~^ ERROR intrinsic must be in extern "rust-call" fn m4(_: ()); //~ ERROR extern "rust-call" ABI is experimental and subject to change extern "rust-call" fn dm4(_: ()) {} //~ ERROR extern "rust-call" ABI is experimental and subject to change @@ -30,28 +21,16 @@ struct S; // Methods in trait impl impl Tr for S { - extern "rust-intrinsic" fn m1() {} //~ ERROR extern "rust-intrinsic" ABI is an implementation detail - //~^ ERROR intrinsic must be in - extern "rust-intrinsic" fn m2() {} //~ ERROR extern "rust-intrinsic" ABI is an implementation detail - //~^ ERROR intrinsic must be in extern "rust-call" fn m4(_: ()) {} //~ ERROR extern "rust-call" ABI is experimental and subject to change } // Methods in inherent impl impl S { - extern "rust-intrinsic" fn im1() {} //~ ERROR extern "rust-intrinsic" ABI is an implementation detail - //~^ ERROR intrinsic must be in - extern "rust-intrinsic" fn im2() {} //~ ERROR extern "rust-intrinsic" ABI is an implementation detail - //~^ ERROR intrinsic must be in extern "rust-call" fn im4(_: ()) {} //~ ERROR extern "rust-call" ABI is experimental and subject to change } // Function pointer types -type A1 = extern "rust-intrinsic" fn(); //~ ERROR extern "rust-intrinsic" ABI is an implementation detail -type A2 = extern "rust-intrinsic" fn(); //~ ERROR extern "rust-intrinsic" ABI is an implementation detail type A4 = extern "rust-call" fn(_: ()); //~ ERROR extern "rust-call" ABI is experimental and subject to change // Foreign modules -extern "rust-intrinsic" {} //~ ERROR extern "rust-intrinsic" ABI is an implementation detail -extern "rust-intrinsic" {} //~ ERROR extern "rust-intrinsic" ABI is an implementation detail extern "rust-call" {} //~ ERROR extern "rust-call" ABI is experimental and subject to change diff --git a/tests/ui/feature-gates/feature-gate-abi.stderr b/tests/ui/feature-gates/feature-gate-abi.stderr index a974c0099cbd..7897a60b34f4 100644 --- a/tests/ui/feature-gates/feature-gate-abi.stderr +++ b/tests/ui/feature-gates/feature-gate-abi.stderr @@ -1,23 +1,5 @@ -error[E0658]: the extern "rust-intrinsic" ABI is an implementation detail and perma-unstable - --> $DIR/feature-gate-abi.rs:12:8 - | -LL | extern "rust-intrinsic" fn f1() {} - | ^^^^^^^^^^^^^^^^ - | - = help: add `#![feature(intrinsics)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: the extern "rust-intrinsic" ABI is an implementation detail and perma-unstable - --> $DIR/feature-gate-abi.rs:14:8 - | -LL | extern "rust-intrinsic" fn f2() {} - | ^^^^^^^^^^^^^^^^ - | - = help: add `#![feature(intrinsics)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - error[E0658]: the extern "rust-call" ABI is experimental and subject to change - --> $DIR/feature-gate-abi.rs:16:8 + --> $DIR/feature-gate-abi.rs:11:8 | LL | extern "rust-call" fn f4(_: ()) {} | ^^^^^^^^^^^ @@ -26,26 +8,8 @@ LL | extern "rust-call" fn f4(_: ()) {} = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error[E0658]: the extern "rust-intrinsic" ABI is an implementation detail and perma-unstable - --> $DIR/feature-gate-abi.rs:20:12 - | -LL | extern "rust-intrinsic" fn m1(); - | ^^^^^^^^^^^^^^^^ - | - = help: add `#![feature(intrinsics)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: the extern "rust-intrinsic" ABI is an implementation detail and perma-unstable - --> $DIR/feature-gate-abi.rs:22:12 - | -LL | extern "rust-intrinsic" fn m2(); - | ^^^^^^^^^^^^^^^^ - | - = help: add `#![feature(intrinsics)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - error[E0658]: the extern "rust-call" ABI is experimental and subject to change - --> $DIR/feature-gate-abi.rs:24:12 + --> $DIR/feature-gate-abi.rs:15:12 | LL | extern "rust-call" fn m4(_: ()); | ^^^^^^^^^^^ @@ -55,7 +19,7 @@ LL | extern "rust-call" fn m4(_: ()); = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the extern "rust-call" ABI is experimental and subject to change - --> $DIR/feature-gate-abi.rs:26:12 + --> $DIR/feature-gate-abi.rs:17:12 | LL | extern "rust-call" fn dm4(_: ()) {} | ^^^^^^^^^^^ @@ -64,26 +28,8 @@ LL | extern "rust-call" fn dm4(_: ()) {} = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error[E0658]: the extern "rust-intrinsic" ABI is an implementation detail and perma-unstable - --> $DIR/feature-gate-abi.rs:33:12 - | -LL | extern "rust-intrinsic" fn m1() {} - | ^^^^^^^^^^^^^^^^ - | - = help: add `#![feature(intrinsics)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: the extern "rust-intrinsic" ABI is an implementation detail and perma-unstable - --> $DIR/feature-gate-abi.rs:35:12 - | -LL | extern "rust-intrinsic" fn m2() {} - | ^^^^^^^^^^^^^^^^ - | - = help: add `#![feature(intrinsics)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - error[E0658]: the extern "rust-call" ABI is experimental and subject to change - --> $DIR/feature-gate-abi.rs:37:12 + --> $DIR/feature-gate-abi.rs:24:12 | LL | extern "rust-call" fn m4(_: ()) {} | ^^^^^^^^^^^ @@ -92,26 +38,8 @@ LL | extern "rust-call" fn m4(_: ()) {} = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error[E0658]: the extern "rust-intrinsic" ABI is an implementation detail and perma-unstable - --> $DIR/feature-gate-abi.rs:42:12 - | -LL | extern "rust-intrinsic" fn im1() {} - | ^^^^^^^^^^^^^^^^ - | - = help: add `#![feature(intrinsics)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: the extern "rust-intrinsic" ABI is an implementation detail and perma-unstable - --> $DIR/feature-gate-abi.rs:44:12 - | -LL | extern "rust-intrinsic" fn im2() {} - | ^^^^^^^^^^^^^^^^ - | - = help: add `#![feature(intrinsics)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - error[E0658]: the extern "rust-call" ABI is experimental and subject to change - --> $DIR/feature-gate-abi.rs:46:12 + --> $DIR/feature-gate-abi.rs:29:12 | LL | extern "rust-call" fn im4(_: ()) {} | ^^^^^^^^^^^ @@ -120,26 +48,8 @@ LL | extern "rust-call" fn im4(_: ()) {} = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error[E0658]: the extern "rust-intrinsic" ABI is an implementation detail and perma-unstable - --> $DIR/feature-gate-abi.rs:50:18 - | -LL | type A1 = extern "rust-intrinsic" fn(); - | ^^^^^^^^^^^^^^^^ - | - = help: add `#![feature(intrinsics)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: the extern "rust-intrinsic" ABI is an implementation detail and perma-unstable - --> $DIR/feature-gate-abi.rs:51:18 - | -LL | type A2 = extern "rust-intrinsic" fn(); - | ^^^^^^^^^^^^^^^^ - | - = help: add `#![feature(intrinsics)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - error[E0658]: the extern "rust-call" ABI is experimental and subject to change - --> $DIR/feature-gate-abi.rs:52:18 + --> $DIR/feature-gate-abi.rs:33:18 | LL | type A4 = extern "rust-call" fn(_: ()); | ^^^^^^^^^^^ @@ -148,26 +58,8 @@ LL | type A4 = extern "rust-call" fn(_: ()); = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error[E0658]: the extern "rust-intrinsic" ABI is an implementation detail and perma-unstable - --> $DIR/feature-gate-abi.rs:55:8 - | -LL | extern "rust-intrinsic" {} - | ^^^^^^^^^^^^^^^^ - | - = help: add `#![feature(intrinsics)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: the extern "rust-intrinsic" ABI is an implementation detail and perma-unstable - --> $DIR/feature-gate-abi.rs:56:8 - | -LL | extern "rust-intrinsic" {} - | ^^^^^^^^^^^^^^^^ - | - = help: add `#![feature(intrinsics)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - error[E0658]: the extern "rust-call" ABI is experimental and subject to change - --> $DIR/feature-gate-abi.rs:57:8 + --> $DIR/feature-gate-abi.rs:36:8 | LL | extern "rust-call" {} | ^^^^^^^^^^^ @@ -176,54 +68,6 @@ LL | extern "rust-call" {} = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: intrinsic must be in `extern "rust-intrinsic" { ... }` block - --> $DIR/feature-gate-abi.rs:20:32 - | -LL | extern "rust-intrinsic" fn m1(); - | ^^ - -error: intrinsic must be in `extern "rust-intrinsic" { ... }` block - --> $DIR/feature-gate-abi.rs:22:32 - | -LL | extern "rust-intrinsic" fn m2(); - | ^^ - -error: intrinsic must be in `extern "rust-intrinsic" { ... }` block - --> $DIR/feature-gate-abi.rs:12:33 - | -LL | extern "rust-intrinsic" fn f1() {} - | ^^ - -error: intrinsic must be in `extern "rust-intrinsic" { ... }` block - --> $DIR/feature-gate-abi.rs:14:33 - | -LL | extern "rust-intrinsic" fn f2() {} - | ^^ - -error: intrinsic must be in `extern "rust-intrinsic" { ... }` block - --> $DIR/feature-gate-abi.rs:33:37 - | -LL | extern "rust-intrinsic" fn m1() {} - | ^^ - -error: intrinsic must be in `extern "rust-intrinsic" { ... }` block - --> $DIR/feature-gate-abi.rs:35:37 - | -LL | extern "rust-intrinsic" fn m2() {} - | ^^ - -error: intrinsic must be in `extern "rust-intrinsic" { ... }` block - --> $DIR/feature-gate-abi.rs:42:38 - | -LL | extern "rust-intrinsic" fn im1() {} - | ^^ - -error: intrinsic must be in `extern "rust-intrinsic" { ... }` block - --> $DIR/feature-gate-abi.rs:44:38 - | -LL | extern "rust-intrinsic" fn im2() {} - | ^^ - -error: aborting due to 27 previous errors +error: aborting due to 7 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-c_variadic.rs b/tests/ui/feature-gates/feature-gate-c_variadic.rs index 8b40c36c7db5..f189f02a26dd 100644 --- a/tests/ui/feature-gates/feature-gate-c_variadic.rs +++ b/tests/ui/feature-gates/feature-gate-c_variadic.rs @@ -1,4 +1,4 @@ #![crate_type="lib"] pub unsafe extern "C" fn test(_: i32, ap: ...) { } -//~^ C-variadic functions are unstable +//~^ ERROR C-variadic functions are unstable diff --git a/tests/ui/feature-gates/feature-gate-cfg-boolean-literals.rs b/tests/ui/feature-gates/feature-gate-cfg-boolean-literals.rs deleted file mode 100644 index 6784b4450490..000000000000 --- a/tests/ui/feature-gates/feature-gate-cfg-boolean-literals.rs +++ /dev/null @@ -1,10 +0,0 @@ -#[cfg(true)] //~ ERROR `cfg(true)` is experimental -fn foo() {} - -#[cfg_attr(true, cfg(false))] //~ ERROR `cfg(true)` is experimental -//~^ ERROR `cfg(false)` is experimental -fn foo() {} - -fn main() { - cfg!(false); //~ ERROR `cfg(false)` is experimental -} diff --git a/tests/ui/feature-gates/feature-gate-cfg-boolean-literals.stderr b/tests/ui/feature-gates/feature-gate-cfg-boolean-literals.stderr deleted file mode 100644 index 64491464f1d4..000000000000 --- a/tests/ui/feature-gates/feature-gate-cfg-boolean-literals.stderr +++ /dev/null @@ -1,43 +0,0 @@ -error[E0658]: `cfg(true)` is experimental and subject to change - --> $DIR/feature-gate-cfg-boolean-literals.rs:1:7 - | -LL | #[cfg(true)] - | ^^^^ - | - = note: see issue #131204 for more information - = help: add `#![feature(cfg_boolean_literals)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: `cfg(true)` is experimental and subject to change - --> $DIR/feature-gate-cfg-boolean-literals.rs:4:12 - | -LL | #[cfg_attr(true, cfg(false))] - | ^^^^ - | - = note: see issue #131204 for more information - = help: add `#![feature(cfg_boolean_literals)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: `cfg(false)` is experimental and subject to change - --> $DIR/feature-gate-cfg-boolean-literals.rs:4:22 - | -LL | #[cfg_attr(true, cfg(false))] - | ^^^^^ - | - = note: see issue #131204 for more information - = help: add `#![feature(cfg_boolean_literals)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: `cfg(false)` is experimental and subject to change - --> $DIR/feature-gate-cfg-boolean-literals.rs:9:10 - | -LL | cfg!(false); - | ^^^^^ - | - = note: see issue #131204 for more information - = help: add `#![feature(cfg_boolean_literals)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error: aborting due to 4 previous errors - -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-cfg-emscripten-wasm-eh.rs b/tests/ui/feature-gates/feature-gate-cfg-emscripten-wasm-eh.rs index cff98b43fe74..232061e239c9 100644 --- a/tests/ui/feature-gates/feature-gate-cfg-emscripten-wasm-eh.rs +++ b/tests/ui/feature-gates/feature-gate-cfg-emscripten-wasm-eh.rs @@ -1,4 +1,4 @@ //@ compile-flags: --check-cfg=cfg(emscripten_wasm_eh) #[cfg(not(emscripten_wasm_eh))] -//~^ `cfg(emscripten_wasm_eh)` is experimental +//~^ ERROR `cfg(emscripten_wasm_eh)` is experimental fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-cfg-sanitizer_cfi.rs b/tests/ui/feature-gates/feature-gate-cfg-sanitizer_cfi.rs index 76d96de750a6..1419a978138a 100644 --- a/tests/ui/feature-gates/feature-gate-cfg-sanitizer_cfi.rs +++ b/tests/ui/feature-gates/feature-gate-cfg-sanitizer_cfi.rs @@ -1,9 +1,9 @@ #[cfg(sanitizer_cfi_generalize_pointers)] -//~^ `cfg(sanitizer_cfi_generalize_pointers)` is experimental +//~^ ERROR `cfg(sanitizer_cfi_generalize_pointers)` is experimental fn foo() {} #[cfg(sanitizer_cfi_normalize_integers)] -//~^ `cfg(sanitizer_cfi_normalize_integers)` is experimental +//~^ ERROR `cfg(sanitizer_cfi_normalize_integers)` is experimental fn bar() {} fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-cfg_sanitize.rs b/tests/ui/feature-gates/feature-gate-cfg_sanitize.rs index c3e7cc9ed8a9..0933f43e76b6 100644 --- a/tests/ui/feature-gates/feature-gate-cfg_sanitize.rs +++ b/tests/ui/feature-gates/feature-gate-cfg_sanitize.rs @@ -1,3 +1,3 @@ #[cfg(not(sanitize = "thread"))] -//~^ `cfg(sanitize)` is experimental +//~^ ERROR `cfg(sanitize)` is experimental fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-closure_track_caller.rs b/tests/ui/feature-gates/feature-gate-closure_track_caller.rs index d90fb765a237..d7cfc13cae55 100644 --- a/tests/ui/feature-gates/feature-gate-closure_track_caller.rs +++ b/tests/ui/feature-gates/feature-gate-closure_track_caller.rs @@ -3,7 +3,7 @@ #![feature(coroutines)] fn main() { - let _closure = #[track_caller] || {}; //~ `#[track_caller]` on closures - let _coroutine = #[coroutine] #[track_caller] || { yield; }; //~ `#[track_caller]` on closures - let _future = #[track_caller] async {}; //~ `#[track_caller]` on closures + let _closure = #[track_caller] || {}; //~ ERROR `#[track_caller]` on closures + let _coroutine = #[coroutine] #[track_caller] || { yield; }; //~ ERROR `#[track_caller]` on closures + let _future = #[track_caller] async {}; //~ ERROR `#[track_caller]` on closures } diff --git a/tests/ui/feature-gates/feature-gate-coroutines.rs b/tests/ui/feature-gates/feature-gate-coroutines.rs index f20dc56f1229..b37a61d9105f 100644 --- a/tests/ui/feature-gates/feature-gate-coroutines.rs +++ b/tests/ui/feature-gates/feature-gate-coroutines.rs @@ -12,7 +12,7 @@ fn main() { //~^^ ERROR `yield` can only be used } -#[cfg(FALSE)] +#[cfg(false)] fn foo() { // Ok in 2024 edition yield; //~ ERROR yield syntax is experimental diff --git a/tests/ui/feature-gates/feature-gate-custom_mir.rs b/tests/ui/feature-gates/feature-gate-custom_mir.rs index e100df08ee70..4d713c524b33 100644 --- a/tests/ui/feature-gates/feature-gate-custom_mir.rs +++ b/tests/ui/feature-gates/feature-gate-custom_mir.rs @@ -1,13 +1,13 @@ #![feature(core_intrinsics)] extern crate core; -use core::intrinsics::mir::*; //~ custom_mir +use core::intrinsics::mir::*; //~ ERROR custom_mir #[custom_mir(dialect = "built")] //~ ERROR the `#[custom_mir]` attribute is just used for the Rust test suite pub fn foo(_x: i32) -> i32 { mir! { { - Return() //~ custom_mir + Return() //~ ERROR custom_mir } } } diff --git a/tests/ui/feature-gates/feature-gate-deref_patterns.rs b/tests/ui/feature-gates/feature-gate-deref_patterns.rs index b43001f2d53f..53b4301f10c0 100644 --- a/tests/ui/feature-gates/feature-gate-deref_patterns.rs +++ b/tests/ui/feature-gates/feature-gate-deref_patterns.rs @@ -4,6 +4,6 @@ fn main() { println!("x: {}", x); // `box` syntax is allowed to be cfg-ed out for historical reasons (#65742). - #[cfg(FALSE)] + #[cfg(false)] let box _x = Box::new('c'); } diff --git a/tests/ui/feature-gates/feature-gate-explicit-extern-abis.current.fixed b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.current.fixed new file mode 100644 index 000000000000..525f78d162fc --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.current.fixed @@ -0,0 +1,45 @@ +// The purpose of this feature gate is to make something into a hard error in a +// future edition. Consequently, this test differs from most other feature gate +// tests. Instead of verifying that an error occurs when the feature gate is +// missing, it ensures that the hard error is only produced with the feature +// gate is present in the `future` edition -- and otherwise that only a warning +// is emitted. + +//@ revisions: current current_feature future future_feature + +//@ [current] run-rustfix +//@ [current] check-pass + +//@ [current_feature] run-rustfix +//@ [current_feature] check-pass + +//@ [future] edition: future +//@ [future] compile-flags: -Z unstable-options +//@ [future] run-rustfix +//@ [future] check-pass + +//@ [future_feature] edition: future +//@ [future_feature] compile-flags: -Z unstable-options + +#![cfg_attr(future_feature, feature(explicit_extern_abis))] +#![cfg_attr(current_feature, feature(explicit_extern_abis))] + +extern "C" fn _foo() {} +//[current]~^ WARN `extern` declarations without an explicit ABI are deprecated +//[current_feature]~^^ WARN `extern` declarations without an explicit ABI are deprecated +//[future]~^^^ WARN `extern` declarations without an explicit ABI are deprecated +//[future_feature]~^^^^ ERROR `extern` declarations without an explicit ABI are disallowed + +unsafe extern "C" fn _bar() {} +//[current]~^ WARN `extern` declarations without an explicit ABI are deprecated +//[current_feature]~^^ WARN `extern` declarations without an explicit ABI are deprecated +//[future]~^^^ WARN `extern` declarations without an explicit ABI are deprecated +//[future_feature]~^^^^ ERROR `extern` declarations without an explicit ABI are disallowed + +unsafe extern "C" {} +//[current]~^ WARN `extern` declarations without an explicit ABI are deprecated +//[current_feature]~^^ WARN `extern` declarations without an explicit ABI are deprecated +//[future]~^^^ WARN `extern` declarations without an explicit ABI are deprecated +//[future_feature]~^^^^ ERROR `extern` declarations without an explicit ABI are disallowed + +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-explicit-extern-abis.current.stderr b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.current.stderr new file mode 100644 index 000000000000..cf927807c7c3 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.current.stderr @@ -0,0 +1,22 @@ +warning: `extern` declarations without an explicit ABI are deprecated + --> $DIR/feature-gate-explicit-extern-abis.rs:27:1 + | +LL | extern fn _foo() {} + | ^^^^^^ help: explicitly specify the "C" ABI: `extern "C"` + | + = note: `#[warn(missing_abi)]` on by default + +warning: `extern` declarations without an explicit ABI are deprecated + --> $DIR/feature-gate-explicit-extern-abis.rs:33:8 + | +LL | unsafe extern fn _bar() {} + | ^^^^^^ help: explicitly specify the "C" ABI: `extern "C"` + +warning: `extern` declarations without an explicit ABI are deprecated + --> $DIR/feature-gate-explicit-extern-abis.rs:39:8 + | +LL | unsafe extern {} + | ^^^^^^ help: explicitly specify the "C" ABI: `extern "C"` + +warning: 3 warnings emitted + diff --git a/tests/ui/feature-gates/feature-gate-explicit-extern-abis.current_feature.fixed b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.current_feature.fixed new file mode 100644 index 000000000000..525f78d162fc --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.current_feature.fixed @@ -0,0 +1,45 @@ +// The purpose of this feature gate is to make something into a hard error in a +// future edition. Consequently, this test differs from most other feature gate +// tests. Instead of verifying that an error occurs when the feature gate is +// missing, it ensures that the hard error is only produced with the feature +// gate is present in the `future` edition -- and otherwise that only a warning +// is emitted. + +//@ revisions: current current_feature future future_feature + +//@ [current] run-rustfix +//@ [current] check-pass + +//@ [current_feature] run-rustfix +//@ [current_feature] check-pass + +//@ [future] edition: future +//@ [future] compile-flags: -Z unstable-options +//@ [future] run-rustfix +//@ [future] check-pass + +//@ [future_feature] edition: future +//@ [future_feature] compile-flags: -Z unstable-options + +#![cfg_attr(future_feature, feature(explicit_extern_abis))] +#![cfg_attr(current_feature, feature(explicit_extern_abis))] + +extern "C" fn _foo() {} +//[current]~^ WARN `extern` declarations without an explicit ABI are deprecated +//[current_feature]~^^ WARN `extern` declarations without an explicit ABI are deprecated +//[future]~^^^ WARN `extern` declarations without an explicit ABI are deprecated +//[future_feature]~^^^^ ERROR `extern` declarations without an explicit ABI are disallowed + +unsafe extern "C" fn _bar() {} +//[current]~^ WARN `extern` declarations without an explicit ABI are deprecated +//[current_feature]~^^ WARN `extern` declarations without an explicit ABI are deprecated +//[future]~^^^ WARN `extern` declarations without an explicit ABI are deprecated +//[future_feature]~^^^^ ERROR `extern` declarations without an explicit ABI are disallowed + +unsafe extern "C" {} +//[current]~^ WARN `extern` declarations without an explicit ABI are deprecated +//[current_feature]~^^ WARN `extern` declarations without an explicit ABI are deprecated +//[future]~^^^ WARN `extern` declarations without an explicit ABI are deprecated +//[future_feature]~^^^^ ERROR `extern` declarations without an explicit ABI are disallowed + +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-explicit-extern-abis.current_feature.stderr b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.current_feature.stderr new file mode 100644 index 000000000000..cf927807c7c3 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.current_feature.stderr @@ -0,0 +1,22 @@ +warning: `extern` declarations without an explicit ABI are deprecated + --> $DIR/feature-gate-explicit-extern-abis.rs:27:1 + | +LL | extern fn _foo() {} + | ^^^^^^ help: explicitly specify the "C" ABI: `extern "C"` + | + = note: `#[warn(missing_abi)]` on by default + +warning: `extern` declarations without an explicit ABI are deprecated + --> $DIR/feature-gate-explicit-extern-abis.rs:33:8 + | +LL | unsafe extern fn _bar() {} + | ^^^^^^ help: explicitly specify the "C" ABI: `extern "C"` + +warning: `extern` declarations without an explicit ABI are deprecated + --> $DIR/feature-gate-explicit-extern-abis.rs:39:8 + | +LL | unsafe extern {} + | ^^^^^^ help: explicitly specify the "C" ABI: `extern "C"` + +warning: 3 warnings emitted + diff --git a/tests/ui/feature-gates/feature-gate-explicit-extern-abis.future.fixed b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.future.fixed new file mode 100644 index 000000000000..525f78d162fc --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.future.fixed @@ -0,0 +1,45 @@ +// The purpose of this feature gate is to make something into a hard error in a +// future edition. Consequently, this test differs from most other feature gate +// tests. Instead of verifying that an error occurs when the feature gate is +// missing, it ensures that the hard error is only produced with the feature +// gate is present in the `future` edition -- and otherwise that only a warning +// is emitted. + +//@ revisions: current current_feature future future_feature + +//@ [current] run-rustfix +//@ [current] check-pass + +//@ [current_feature] run-rustfix +//@ [current_feature] check-pass + +//@ [future] edition: future +//@ [future] compile-flags: -Z unstable-options +//@ [future] run-rustfix +//@ [future] check-pass + +//@ [future_feature] edition: future +//@ [future_feature] compile-flags: -Z unstable-options + +#![cfg_attr(future_feature, feature(explicit_extern_abis))] +#![cfg_attr(current_feature, feature(explicit_extern_abis))] + +extern "C" fn _foo() {} +//[current]~^ WARN `extern` declarations without an explicit ABI are deprecated +//[current_feature]~^^ WARN `extern` declarations without an explicit ABI are deprecated +//[future]~^^^ WARN `extern` declarations without an explicit ABI are deprecated +//[future_feature]~^^^^ ERROR `extern` declarations without an explicit ABI are disallowed + +unsafe extern "C" fn _bar() {} +//[current]~^ WARN `extern` declarations without an explicit ABI are deprecated +//[current_feature]~^^ WARN `extern` declarations without an explicit ABI are deprecated +//[future]~^^^ WARN `extern` declarations without an explicit ABI are deprecated +//[future_feature]~^^^^ ERROR `extern` declarations without an explicit ABI are disallowed + +unsafe extern "C" {} +//[current]~^ WARN `extern` declarations without an explicit ABI are deprecated +//[current_feature]~^^ WARN `extern` declarations without an explicit ABI are deprecated +//[future]~^^^ WARN `extern` declarations without an explicit ABI are deprecated +//[future_feature]~^^^^ ERROR `extern` declarations without an explicit ABI are disallowed + +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-explicit-extern-abis.future.stderr b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.future.stderr new file mode 100644 index 000000000000..cf927807c7c3 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.future.stderr @@ -0,0 +1,22 @@ +warning: `extern` declarations without an explicit ABI are deprecated + --> $DIR/feature-gate-explicit-extern-abis.rs:27:1 + | +LL | extern fn _foo() {} + | ^^^^^^ help: explicitly specify the "C" ABI: `extern "C"` + | + = note: `#[warn(missing_abi)]` on by default + +warning: `extern` declarations without an explicit ABI are deprecated + --> $DIR/feature-gate-explicit-extern-abis.rs:33:8 + | +LL | unsafe extern fn _bar() {} + | ^^^^^^ help: explicitly specify the "C" ABI: `extern "C"` + +warning: `extern` declarations without an explicit ABI are deprecated + --> $DIR/feature-gate-explicit-extern-abis.rs:39:8 + | +LL | unsafe extern {} + | ^^^^^^ help: explicitly specify the "C" ABI: `extern "C"` + +warning: 3 warnings emitted + diff --git a/tests/ui/feature-gates/feature-gate-explicit-extern-abis.future_feature.stderr b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.future_feature.stderr new file mode 100644 index 000000000000..096a6f434169 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.future_feature.stderr @@ -0,0 +1,26 @@ +error: `extern` declarations without an explicit ABI are disallowed + --> $DIR/feature-gate-explicit-extern-abis.rs:27:1 + | +LL | extern fn _foo() {} + | ^^^^^^ help: specify an ABI: `extern ""` + | + = help: prior to Rust 2024, a default ABI was inferred + +error: `extern` declarations without an explicit ABI are disallowed + --> $DIR/feature-gate-explicit-extern-abis.rs:33:8 + | +LL | unsafe extern fn _bar() {} + | ^^^^^^ help: specify an ABI: `extern ""` + | + = help: prior to Rust 2024, a default ABI was inferred + +error: `extern` declarations without an explicit ABI are disallowed + --> $DIR/feature-gate-explicit-extern-abis.rs:39:8 + | +LL | unsafe extern {} + | ^^^^^^ help: specify an ABI: `extern ""` + | + = help: prior to Rust 2024, a default ABI was inferred + +error: aborting due to 3 previous errors + diff --git a/tests/ui/feature-gates/feature-gate-explicit-extern-abis.rs b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.rs new file mode 100644 index 000000000000..379c45f58990 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.rs @@ -0,0 +1,45 @@ +// The purpose of this feature gate is to make something into a hard error in a +// future edition. Consequently, this test differs from most other feature gate +// tests. Instead of verifying that an error occurs when the feature gate is +// missing, it ensures that the hard error is only produced with the feature +// gate is present in the `future` edition -- and otherwise that only a warning +// is emitted. + +//@ revisions: current current_feature future future_feature + +//@ [current] run-rustfix +//@ [current] check-pass + +//@ [current_feature] run-rustfix +//@ [current_feature] check-pass + +//@ [future] edition: future +//@ [future] compile-flags: -Z unstable-options +//@ [future] run-rustfix +//@ [future] check-pass + +//@ [future_feature] edition: future +//@ [future_feature] compile-flags: -Z unstable-options + +#![cfg_attr(future_feature, feature(explicit_extern_abis))] +#![cfg_attr(current_feature, feature(explicit_extern_abis))] + +extern fn _foo() {} +//[current]~^ WARN `extern` declarations without an explicit ABI are deprecated +//[current_feature]~^^ WARN `extern` declarations without an explicit ABI are deprecated +//[future]~^^^ WARN `extern` declarations without an explicit ABI are deprecated +//[future_feature]~^^^^ ERROR `extern` declarations without an explicit ABI are disallowed + +unsafe extern fn _bar() {} +//[current]~^ WARN `extern` declarations without an explicit ABI are deprecated +//[current_feature]~^^ WARN `extern` declarations without an explicit ABI are deprecated +//[future]~^^^ WARN `extern` declarations without an explicit ABI are deprecated +//[future_feature]~^^^^ ERROR `extern` declarations without an explicit ABI are disallowed + +unsafe extern {} +//[current]~^ WARN `extern` declarations without an explicit ABI are deprecated +//[current_feature]~^^ WARN `extern` declarations without an explicit ABI are deprecated +//[future]~^^^ WARN `extern` declarations without an explicit ABI are deprecated +//[future_feature]~^^^^ ERROR `extern` declarations without an explicit ABI are disallowed + +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-ffi_const.rs b/tests/ui/feature-gates/feature-gate-ffi_const.rs index 9f3d783ccd69..35f91b99a6f4 100644 --- a/tests/ui/feature-gates/feature-gate-ffi_const.rs +++ b/tests/ui/feature-gates/feature-gate-ffi_const.rs @@ -1,6 +1,6 @@ #![crate_type = "lib"] extern "C" { - #[ffi_const] //~ ERROR the `#[ffi_const]` attribute is an experimental feature + #[unsafe(ffi_const)] //~ ERROR the `#[ffi_const]` attribute is an experimental feature pub fn foo(); } diff --git a/tests/ui/feature-gates/feature-gate-ffi_const.stderr b/tests/ui/feature-gates/feature-gate-ffi_const.stderr index d083b826d6e1..7e8c941be07d 100644 --- a/tests/ui/feature-gates/feature-gate-ffi_const.stderr +++ b/tests/ui/feature-gates/feature-gate-ffi_const.stderr @@ -1,8 +1,8 @@ error[E0658]: the `#[ffi_const]` attribute is an experimental feature --> $DIR/feature-gate-ffi_const.rs:4:5 | -LL | #[ffi_const] - | ^^^^^^^^^^^^ +LL | #[unsafe(ffi_const)] + | ^^^^^^^^^^^^^^^^^^^^ | = note: see issue #58328 for more information = help: add `#![feature(ffi_const)]` to the crate attributes to enable diff --git a/tests/ui/feature-gates/feature-gate-ffi_pure.rs b/tests/ui/feature-gates/feature-gate-ffi_pure.rs index b0dfa01ff4c2..0f1288b234e4 100644 --- a/tests/ui/feature-gates/feature-gate-ffi_pure.rs +++ b/tests/ui/feature-gates/feature-gate-ffi_pure.rs @@ -1,6 +1,6 @@ #![crate_type = "lib"] extern "C" { - #[ffi_pure] //~ ERROR the `#[ffi_pure]` attribute is an experimental feature + #[unsafe(ffi_pure)] //~ ERROR the `#[ffi_pure]` attribute is an experimental feature pub fn foo(); } diff --git a/tests/ui/feature-gates/feature-gate-ffi_pure.stderr b/tests/ui/feature-gates/feature-gate-ffi_pure.stderr index 6544d450eeb9..cf923536d6c5 100644 --- a/tests/ui/feature-gates/feature-gate-ffi_pure.stderr +++ b/tests/ui/feature-gates/feature-gate-ffi_pure.stderr @@ -1,8 +1,8 @@ error[E0658]: the `#[ffi_pure]` attribute is an experimental feature --> $DIR/feature-gate-ffi_pure.rs:4:5 | -LL | #[ffi_pure] - | ^^^^^^^^^^^ +LL | #[unsafe(ffi_pure)] + | ^^^^^^^^^^^^^^^^^^^ | = note: see issue #58329 for more information = help: add `#![feature(ffi_pure)]` to the crate attributes to enable diff --git a/tests/ui/feature-gates/feature-gate-freeze-impls.rs b/tests/ui/feature-gates/feature-gate-freeze-impls.rs index c14c9494874a..401095dd83ba 100644 --- a/tests/ui/feature-gates/feature-gate-freeze-impls.rs +++ b/tests/ui/feature-gates/feature-gate-freeze-impls.rs @@ -5,11 +5,11 @@ use std::marker::Freeze; struct Foo; unsafe impl Freeze for Foo {} -//~^ explicit impls for the `Freeze` trait are not permitted +//~^ ERROR explicit impls for the `Freeze` trait are not permitted struct Bar; impl !Freeze for Bar {} -//~^ explicit impls for the `Freeze` trait are not permitted +//~^ ERROR explicit impls for the `Freeze` trait are not permitted fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-gen_blocks.rs b/tests/ui/feature-gates/feature-gate-gen_blocks.rs index 01fd922b0e99..989daf471bcb 100644 --- a/tests/ui/feature-gates/feature-gate-gen_blocks.rs +++ b/tests/ui/feature-gates/feature-gate-gen_blocks.rs @@ -17,7 +17,7 @@ fn test_async_gen() { fn main() {} -#[cfg(FALSE)] +#[cfg(false)] fn foo() { gen {}; //[e2024]~^ ERROR: gen blocks are experimental diff --git a/tests/ui/feature-gates/feature-gate-guard-patterns.rs b/tests/ui/feature-gates/feature-gate-guard-patterns.rs index 52ed89e668b1..74fb5817081c 100644 --- a/tests/ui/feature-gates/feature-gate-guard-patterns.rs +++ b/tests/ui/feature-gates/feature-gate-guard-patterns.rs @@ -30,7 +30,7 @@ fn other_guards_dont() { while let (x if guard(x)) = 0 {} //~^ ERROR: guard patterns are experimental - #[cfg(FALSE)] + #[cfg(false)] while let (x if guard(x)) = 0 {} //~^ ERROR: guard patterns are experimental } diff --git a/tests/ui/feature-gates/feature-gate-intrinsics.rs b/tests/ui/feature-gates/feature-gate-intrinsics.rs index 65806a0223e7..b7ebba672728 100644 --- a/tests/ui/feature-gates/feature-gate-intrinsics.rs +++ b/tests/ui/feature-gates/feature-gate-intrinsics.rs @@ -1,8 +1,5 @@ -extern "rust-intrinsic" { //~ ERROR "rust-intrinsic" ABI is an implementation detail - fn bar(); //~ ERROR unrecognized intrinsic function: `bar` -} - -extern "rust-intrinsic" fn baz() {} //~ ERROR "rust-intrinsic" ABI is an implementation detail -//~^ ERROR intrinsic must be in +#[rustc_intrinsic] +//~^ ERROR the `#[rustc_intrinsic]` attribute is used to declare intrinsics as function items +fn bar(); fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-intrinsics.stderr b/tests/ui/feature-gates/feature-gate-intrinsics.stderr index 97246f05258f..a7a725883a92 100644 --- a/tests/ui/feature-gates/feature-gate-intrinsics.stderr +++ b/tests/ui/feature-gates/feature-gate-intrinsics.stderr @@ -1,36 +1,12 @@ -error[E0658]: the extern "rust-intrinsic" ABI is an implementation detail and perma-unstable - --> $DIR/feature-gate-intrinsics.rs:1:8 +error[E0658]: the `#[rustc_intrinsic]` attribute is used to declare intrinsics as function items + --> $DIR/feature-gate-intrinsics.rs:1:1 | -LL | extern "rust-intrinsic" { - | ^^^^^^^^^^^^^^^^ +LL | #[rustc_intrinsic] + | ^^^^^^^^^^^^^^^^^^ | = help: add `#![feature(intrinsics)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error[E0658]: the extern "rust-intrinsic" ABI is an implementation detail and perma-unstable - --> $DIR/feature-gate-intrinsics.rs:5:8 - | -LL | extern "rust-intrinsic" fn baz() {} - | ^^^^^^^^^^^^^^^^ - | - = help: add `#![feature(intrinsics)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date +error: aborting due to 1 previous error -error[E0093]: unrecognized intrinsic function: `bar` - --> $DIR/feature-gate-intrinsics.rs:2:5 - | -LL | fn bar(); - | ^^^^^^^^^ unrecognized intrinsic - | - = help: if you're adding an intrinsic, be sure to update `check_intrinsic_type` - -error: intrinsic must be in `extern "rust-intrinsic" { ... }` block - --> $DIR/feature-gate-intrinsics.rs:5:34 - | -LL | extern "rust-intrinsic" fn baz() {} - | ^^ - -error: aborting due to 4 previous errors - -Some errors have detailed explanations: E0093, E0658. -For more information about an error, try `rustc --explain E0093`. +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-mut-ref.rs b/tests/ui/feature-gates/feature-gate-mut-ref.rs index 806b25de66ff..752ae35d8a9a 100644 --- a/tests/ui/feature-gates/feature-gate-mut-ref.rs +++ b/tests/ui/feature-gates/feature-gate-mut-ref.rs @@ -6,8 +6,8 @@ fn main() { let mut ref mut z = 14; //~ ERROR [E0658] z = &mut 15; - #[cfg(FALSE)] + #[cfg(false)] let mut ref x = 10; //~ ERROR [E0658] - #[cfg(FALSE)] + #[cfg(false)] let mut ref mut y = 10; //~ ERROR [E0658] } diff --git a/tests/ui/feature-gates/feature-gate-naked_functions.rs b/tests/ui/feature-gates/feature-gate-naked_functions.rs index abb55b9a557a..77a67e0696eb 100644 --- a/tests/ui/feature-gates/feature-gate-naked_functions.rs +++ b/tests/ui/feature-gates/feature-gate-naked_functions.rs @@ -4,7 +4,7 @@ use std::arch::naked_asm; //~^ ERROR use of unstable library feature `naked_functions` #[naked] -//~^ the `#[naked]` attribute is an experimental feature +//~^ ERROR the `#[naked]` attribute is an experimental feature extern "C" fn naked() { naked_asm!("") //~^ ERROR use of unstable library feature `naked_functions` @@ -12,7 +12,7 @@ extern "C" fn naked() { } #[naked] -//~^ the `#[naked]` attribute is an experimental feature +//~^ ERROR the `#[naked]` attribute is an experimental feature extern "C" fn naked_2() -> isize { naked_asm!("") //~^ ERROR use of unstable library feature `naked_functions` diff --git a/tests/ui/feature-gates/feature-gate-naked_functions_rustic_abi.rs b/tests/ui/feature-gates/feature-gate-naked_functions_rustic_abi.rs new file mode 100644 index 000000000000..c91d83399441 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-naked_functions_rustic_abi.rs @@ -0,0 +1,26 @@ +//@ needs-asm-support +//@ only-x86_64 + +#![feature(naked_functions, rust_cold_cc)] + +use std::arch::naked_asm; + +#[naked] +pub unsafe fn rust_implicit() { + //~^ ERROR `#[naked]` is currently unstable on `extern "Rust"` functions + naked_asm!("ret"); +} + +#[naked] +pub unsafe extern "Rust" fn rust_explicit() { + //~^ ERROR `#[naked]` is currently unstable on `extern "Rust"` functions + naked_asm!("ret"); +} + +#[naked] +pub unsafe extern "rust-cold" fn rust_cold() { + //~^ ERROR `#[naked]` is currently unstable on `extern "rust-cold"` functions + naked_asm!("ret"); +} + +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-naked_functions_rustic_abi.stderr b/tests/ui/feature-gates/feature-gate-naked_functions_rustic_abi.stderr new file mode 100644 index 000000000000..ba45e15ec86b --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-naked_functions_rustic_abi.stderr @@ -0,0 +1,33 @@ +error[E0658]: `#[naked]` is currently unstable on `extern "Rust"` functions + --> $DIR/feature-gate-naked_functions_rustic_abi.rs:9:1 + | +LL | pub unsafe fn rust_implicit() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #138997 for more information + = help: add `#![feature(naked_functions_rustic_abi)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `#[naked]` is currently unstable on `extern "Rust"` functions + --> $DIR/feature-gate-naked_functions_rustic_abi.rs:15:1 + | +LL | pub unsafe extern "Rust" fn rust_explicit() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #138997 for more information + = help: add `#![feature(naked_functions_rustic_abi)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `#[naked]` is currently unstable on `extern "rust-cold"` functions + --> $DIR/feature-gate-naked_functions_rustic_abi.rs:21:1 + | +LL | pub unsafe extern "rust-cold" fn rust_cold() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #138997 for more information + = help: add `#![feature(naked_functions_rustic_abi)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-never_patterns.rs b/tests/ui/feature-gates/feature-gate-never_patterns.rs index d23405ada2d4..2cb0b5a6679d 100644 --- a/tests/ui/feature-gates/feature-gate-never_patterns.rs +++ b/tests/ui/feature-gates/feature-gate-never_patterns.rs @@ -15,12 +15,12 @@ fn main() { //~^ ERROR `!` patterns are experimental } // Check that the gate operates even behind `cfg`. - #[cfg(FALSE)] + #[cfg(false)] match *ptr { ! //~^ ERROR `!` patterns are experimental } - #[cfg(FALSE)] + #[cfg(false)] match *ptr { ! => {} //~^ ERROR `!` patterns are experimental @@ -60,13 +60,13 @@ fn main() { // Check that the gate operates even behind `cfg`. match Some(0) { None => {} - #[cfg(FALSE)] + #[cfg(false)] Some(_) //~^ ERROR `match` arm with no body } match Some(0) { _ => {} - #[cfg(FALSE)] + #[cfg(false)] Some(_) if false //~^ ERROR `match` arm with no body } diff --git a/tests/ui/feature-gates/feature-gate-new_range.rs b/tests/ui/feature-gates/feature-gate-new_range.rs index ecb73546d6a6..32eeb0424b64 100644 --- a/tests/ui/feature-gates/feature-gate-new_range.rs +++ b/tests/ui/feature-gates/feature-gate-new_range.rs @@ -2,9 +2,9 @@ fn main() { let a: core::range::RangeFrom = 1..; - //~^ mismatched types + //~^ ERROR mismatched types let b: core::range::Range = 2..3; - //~^ mismatched types + //~^ ERROR mismatched types let c: core::range::RangeInclusive = 4..=5; - //~^ mismatched types + //~^ ERROR mismatched types } diff --git a/tests/ui/feature-gates/feature-gate-no_sanitize.rs b/tests/ui/feature-gates/feature-gate-no_sanitize.rs index 66a9263e13a5..5ac014f1c5bf 100644 --- a/tests/ui/feature-gates/feature-gate-no_sanitize.rs +++ b/tests/ui/feature-gates/feature-gate-no_sanitize.rs @@ -1,4 +1,4 @@ #[no_sanitize(address)] -//~^ the `#[no_sanitize]` attribute is an experimental feature +//~^ ERROR the `#[no_sanitize]` attribute is an experimental feature fn main() { } diff --git a/tests/ui/feature-gates/feature-gate-postfix_match.rs b/tests/ui/feature-gates/feature-gate-postfix_match.rs index dce7e81a9ae4..2226816e5ea7 100644 --- a/tests/ui/feature-gates/feature-gate-postfix_match.rs +++ b/tests/ui/feature-gates/feature-gate-postfix_match.rs @@ -9,7 +9,7 @@ fn main() { }; // Test that the gate works behind a cfg - #[cfg(FALSE)] + #[cfg(false)] val.match { //~ ERROR postfix match is experimental Some(42) => "the answer to life, the universe, and everything", _ => "might be the answer to something" diff --git a/tests/ui/feature-gates/feature-gate-rustc_const_unstable.rs b/tests/ui/feature-gates/feature-gate-rustc_const_unstable.rs index d7daaaaa101e..522db1643fd4 100644 --- a/tests/ui/feature-gates/feature-gate-rustc_const_unstable.rs +++ b/tests/ui/feature-gates/feature-gate-rustc_const_unstable.rs @@ -1,6 +1,6 @@ // Test internal const fn feature gate. -#[rustc_const_unstable(feature="fzzzzzt")] //~ stability attributes may not be used outside +#[rustc_const_unstable(feature="fzzzzzt")] //~ ERROR stability attributes may not be used outside pub const fn bazinga() {} fn main() { diff --git a/tests/ui/feature-gates/feature-gate-super-let.rs b/tests/ui/feature-gates/feature-gate-super-let.rs index cfe92a42669d..7be080039133 100644 --- a/tests/ui/feature-gates/feature-gate-super-let.rs +++ b/tests/ui/feature-gates/feature-gate-super-let.rs @@ -2,3 +2,10 @@ fn main() { super let a = 1; //~^ ERROR `super let` is experimental } + +// Check that it also isn't accepted in cfg'd out code. +#[cfg(any())] +fn a() { + super let a = 1; + //~^ ERROR `super let` is experimental +} diff --git a/tests/ui/feature-gates/feature-gate-super-let.stderr b/tests/ui/feature-gates/feature-gate-super-let.stderr index a64e1b374f9c..4d088594f6df 100644 --- a/tests/ui/feature-gates/feature-gate-super-let.stderr +++ b/tests/ui/feature-gates/feature-gate-super-let.stderr @@ -8,6 +8,16 @@ LL | super let a = 1; = help: add `#![feature(super_let)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: aborting due to 1 previous error +error[E0658]: `super let` is experimental + --> $DIR/feature-gate-super-let.rs:9:5 + | +LL | super let a = 1; + | ^^^^^ + | + = note: see issue #139076 for more information + = help: add `#![feature(super_let)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-try_blocks.rs b/tests/ui/feature-gates/feature-gate-try_blocks.rs index f565dd014de8..90816293624a 100644 --- a/tests/ui/feature-gates/feature-gate-try_blocks.rs +++ b/tests/ui/feature-gates/feature-gate-try_blocks.rs @@ -1,4 +1,4 @@ -//@ compile-flags: --edition 2018 +//@ edition: 2018 pub fn main() { let try_result: Option<_> = try { //~ ERROR `try` expression is experimental diff --git a/tests/ui/feature-gates/feature-gate-unsafe_pin_internals.rs b/tests/ui/feature-gates/feature-gate-unsafe_pin_internals.rs deleted file mode 100644 index deb5a2f691b8..000000000000 --- a/tests/ui/feature-gates/feature-gate-unsafe_pin_internals.rs +++ /dev/null @@ -1,16 +0,0 @@ -//@ edition:2018 -#![forbid(internal_features, unsafe_code)] -#![feature(unsafe_pin_internals)] -//~^ ERROR the feature `unsafe_pin_internals` is internal to the compiler or standard library - -use core::{marker::PhantomPinned, pin::Pin}; - -/// The `unsafe_pin_internals` is indeed unsound. -fn non_unsafe_pin_new_unchecked(pointer: &mut T) -> Pin<&mut T> { - Pin { __pointer: pointer } -} - -fn main() { - let mut self_referential = PhantomPinned; - let _: Pin<&mut PhantomPinned> = non_unsafe_pin_new_unchecked(&mut self_referential); -} diff --git a/tests/ui/feature-gates/feature-gate-unsafe_pin_internals.stderr b/tests/ui/feature-gates/feature-gate-unsafe_pin_internals.stderr deleted file mode 100644 index fc9bcd90e52e..000000000000 --- a/tests/ui/feature-gates/feature-gate-unsafe_pin_internals.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error: the feature `unsafe_pin_internals` is internal to the compiler or standard library - --> $DIR/feature-gate-unsafe_pin_internals.rs:3:12 - | -LL | #![feature(unsafe_pin_internals)] - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: using it is strongly discouraged -note: the lint level is defined here - --> $DIR/feature-gate-unsafe_pin_internals.rs:2:11 - | -LL | #![forbid(internal_features, unsafe_code)] - | ^^^^^^^^^^^^^^^^^ - -error: aborting due to 1 previous error - diff --git a/tests/ui/feature-gates/feature-gate-yeet_expr-in-cfg.rs b/tests/ui/feature-gates/feature-gate-yeet_expr-in-cfg.rs index 33fda822baad..73a17c12035d 100644 --- a/tests/ui/feature-gates/feature-gate-yeet_expr-in-cfg.rs +++ b/tests/ui/feature-gates/feature-gate-yeet_expr-in-cfg.rs @@ -1,7 +1,7 @@ -//@ compile-flags: --edition 2021 +//@ edition: 2021 pub fn demo() -> Option { - #[cfg(FALSE)] + #[cfg(false)] { do yeet //~ ERROR `do yeet` expression is experimental } @@ -9,7 +9,7 @@ pub fn demo() -> Option { Some(1) } -#[cfg(FALSE)] +#[cfg(false)] pub fn alternative() -> Result<(), String> { do yeet "hello"; //~ ERROR `do yeet` expression is experimental } diff --git a/tests/ui/feature-gates/feature-gate-yeet_expr.rs b/tests/ui/feature-gates/feature-gate-yeet_expr.rs index 12cc17e1cc89..6604f496917f 100644 --- a/tests/ui/feature-gates/feature-gate-yeet_expr.rs +++ b/tests/ui/feature-gates/feature-gate-yeet_expr.rs @@ -1,4 +1,4 @@ -//@ compile-flags: --edition 2018 +//@ edition: 2018 pub fn demo() -> Option { do yeet //~ ERROR `do yeet` expression is experimental diff --git a/tests/ui/feature-gates/feature-gated-feature-in-macro-arg.rs b/tests/ui/feature-gates/feature-gated-feature-in-macro-arg.rs index 2328798d74c3..44c0f1130f05 100644 --- a/tests/ui/feature-gates/feature-gated-feature-in-macro-arg.rs +++ b/tests/ui/feature-gates/feature-gated-feature-in-macro-arg.rs @@ -5,9 +5,9 @@ fn main() { let a = &[1, 2, 3]; println!("{}", { - extern "rust-intrinsic" { //~ ERROR "rust-intrinsic" ABI is an implementation detail - fn atomic_fence(); - } + #[rustc_intrinsic] //~ ERROR the `#[rustc_intrinsic]` attribute is used to declare intrinsics as function items + unsafe fn atomic_fence(); + atomic_fence(); //~ ERROR: is unsafe 42 }); diff --git a/tests/ui/feature-gates/feature-gated-feature-in-macro-arg.stderr b/tests/ui/feature-gates/feature-gated-feature-in-macro-arg.stderr index 86f88fdff5fc..aaaaeece67a8 100644 --- a/tests/ui/feature-gates/feature-gated-feature-in-macro-arg.stderr +++ b/tests/ui/feature-gates/feature-gated-feature-in-macro-arg.stderr @@ -1,13 +1,13 @@ -error[E0658]: the extern "rust-intrinsic" ABI is an implementation detail and perma-unstable - --> $DIR/feature-gated-feature-in-macro-arg.rs:8:16 +error[E0658]: the `#[rustc_intrinsic]` attribute is used to declare intrinsics as function items + --> $DIR/feature-gated-feature-in-macro-arg.rs:8:9 | -LL | extern "rust-intrinsic" { - | ^^^^^^^^^^^^^^^^ +LL | #[rustc_intrinsic] + | ^^^^^^^^^^^^^^^^^^ | = help: add `#![feature(intrinsics)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error[E0133]: call to unsafe function `main::atomic_fence` is unsafe and requires unsafe function or block +error[E0133]: call to unsafe function `atomic_fence` is unsafe and requires unsafe function or block --> $DIR/feature-gated-feature-in-macro-arg.rs:11:9 | LL | atomic_fence(); diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs index a196b8ecdb3e..d07201ebbd1a 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs +++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs @@ -174,16 +174,16 @@ mod macro_use { mod inner { #![macro_use] } #[macro_use] fn f() { } - //~^ `#[macro_use]` only has an effect + //~^ WARN `#[macro_use]` only has an effect #[macro_use] struct S; - //~^ `#[macro_use]` only has an effect + //~^ WARN `#[macro_use]` only has an effect #[macro_use] type T = S; - //~^ `#[macro_use]` only has an effect + //~^ WARN `#[macro_use]` only has an effect #[macro_use] impl S { } - //~^ `#[macro_use]` only has an effect + //~^ WARN `#[macro_use]` only has an effect } #[macro_export] diff --git a/tests/ui/feature-gates/soft-syntax-gates-with-errors.rs b/tests/ui/feature-gates/soft-syntax-gates-with-errors.rs index 2aa2ed34020c..87629a5bcce7 100644 --- a/tests/ui/feature-gates/soft-syntax-gates-with-errors.rs +++ b/tests/ui/feature-gates/soft-syntax-gates-with-errors.rs @@ -5,7 +5,7 @@ macro a() {} //~^ ERROR: `macro` is experimental -#[cfg(FALSE)] +#[cfg(false)] macro b() {} macro_rules! identity { @@ -17,13 +17,13 @@ identity! { //~^ ERROR: `macro` is experimental } -#[cfg(FALSE)] +#[cfg(false)] identity! { macro d() {} // No error } identity! { - #[cfg(FALSE)] + #[cfg(false)] macro e() {} } diff --git a/tests/ui/feature-gates/soft-syntax-gates-without-errors.rs b/tests/ui/feature-gates/soft-syntax-gates-without-errors.rs index 056c8fb04f45..72d0bf1ccd52 100644 --- a/tests/ui/feature-gates/soft-syntax-gates-without-errors.rs +++ b/tests/ui/feature-gates/soft-syntax-gates-without-errors.rs @@ -2,7 +2,7 @@ // This file is used to test the behavior of the early-pass syntax warnings. // If macro syntax is stabilized, replace with a different unstable syntax. -#[cfg(FALSE)] +#[cfg(false)] macro b() {} //~^ WARN: `macro` is experimental //~| WARN: unstable syntax @@ -11,13 +11,13 @@ macro_rules! identity { ($($x:tt)*) => ($($x)*); } -#[cfg(FALSE)] +#[cfg(false)] identity! { macro d() {} // No error } identity! { - #[cfg(FALSE)] + #[cfg(false)] macro e() {} //~^ WARN: `macro` is experimental //~| WARN: unstable syntax diff --git a/tests/ui/feature-gates/stmt_expr_attrs_no_feature.rs b/tests/ui/feature-gates/stmt_expr_attrs_no_feature.rs index a160a9bb082d..4523afa7c4bd 100644 --- a/tests/ui/feature-gates/stmt_expr_attrs_no_feature.rs +++ b/tests/ui/feature-gates/stmt_expr_attrs_no_feature.rs @@ -25,7 +25,7 @@ fn main() { // Check that cfg works right -#[cfg(FALSE)] +#[cfg(false)] fn c() { #[rustc_dummy] 5; @@ -37,7 +37,7 @@ fn j() { 5; } -#[cfg_attr(not(FALSE), cfg(FALSE))] +#[cfg_attr(not(FALSE), cfg(false))] fn d() { #[rustc_dummy] 8; @@ -57,7 +57,7 @@ macro_rules! item_mac { #[rustc_dummy] 42; - #[cfg(FALSE)] + #[cfg(false)] fn f() { #[rustc_dummy] 5; @@ -69,7 +69,7 @@ macro_rules! item_mac { 5; } - #[cfg_attr(not(FALSE), cfg(FALSE))] + #[cfg_attr(not(FALSE), cfg(false))] fn g() { #[rustc_dummy] 8; @@ -90,42 +90,42 @@ item_mac!(e); // check that the gate visitor works right: extern "C" { - #[cfg(FALSE)] + #[cfg(false)] fn x(a: [u8; #[rustc_dummy] 5]); fn y(a: [u8; #[rustc_dummy] 5]); //~ ERROR attributes on expressions are experimental } struct Foo; impl Foo { - #[cfg(FALSE)] + #[cfg(false)] const X: u8 = #[rustc_dummy] 5; const Y: u8 = #[rustc_dummy] 5; //~ ERROR attributes on expressions are experimental } trait Bar { - #[cfg(FALSE)] + #[cfg(false)] const X: [u8; #[rustc_dummy] 5]; const Y: [u8; #[rustc_dummy] 5]; //~ ERROR attributes on expressions are experimental } struct Joyce { - #[cfg(FALSE)] + #[cfg(false)] field: [u8; #[rustc_dummy] 5], field2: [u8; #[rustc_dummy] 5] //~ ERROR attributes on expressions are experimental } struct Walky( - #[cfg(FALSE)] [u8; #[rustc_dummy] 5], + #[cfg(false)] [u8; #[rustc_dummy] 5], [u8; #[rustc_dummy] 5] //~ ERROR attributes on expressions are experimental ); enum Mike { Happy( - #[cfg(FALSE)] [u8; #[rustc_dummy] 5], + #[cfg(false)] [u8; #[rustc_dummy] 5], [u8; #[rustc_dummy] 5] //~ ERROR attributes on expressions are experimental ), Angry { - #[cfg(FALSE)] + #[cfg(false)] field: [u8; #[rustc_dummy] 5], field2: [u8; #[rustc_dummy] 5] //~ ERROR attributes on expressions are experimental } @@ -133,7 +133,7 @@ enum Mike { fn pat() { match 5 { - #[cfg(FALSE)] + #[cfg(false)] 5 => #[rustc_dummy] (), 6 => #[rustc_dummy] (), //~ ERROR attributes on expressions are experimental _ => (), diff --git a/tests/ui/ffi-attrs/ffi_const.rs b/tests/ui/ffi-attrs/ffi_const.rs index aa20a4d4c653..dddc862b0fa6 100644 --- a/tests/ui/ffi-attrs/ffi_const.rs +++ b/tests/ui/ffi-attrs/ffi_const.rs @@ -1,15 +1,18 @@ #![feature(ffi_const)] #![crate_type = "lib"] -#[ffi_const] //~ ERROR `#[ffi_const]` may only be used on foreign functions +#[unsafe(ffi_const)] //~ ERROR `#[ffi_const]` may only be used on foreign functions pub fn foo() {} -#[ffi_const] //~ ERROR `#[ffi_const]` may only be used on foreign functions +#[unsafe(ffi_const)] //~ ERROR `#[ffi_const]` may only be used on foreign functions macro_rules! bar { - () => () + () => {}; } extern "C" { - #[ffi_const] //~ ERROR `#[ffi_const]` may only be used on foreign functions + #[unsafe(ffi_const)] //~ ERROR `#[ffi_const]` may only be used on foreign functions static INT: i32; + + #[ffi_const] //~ ERROR unsafe attribute used without unsafe + fn bar(); } diff --git a/tests/ui/ffi-attrs/ffi_const.stderr b/tests/ui/ffi-attrs/ffi_const.stderr index 394b98f89712..7f31237539d1 100644 --- a/tests/ui/ffi-attrs/ffi_const.stderr +++ b/tests/ui/ffi-attrs/ffi_const.stderr @@ -1,21 +1,32 @@ +error: unsafe attribute used without unsafe + --> $DIR/ffi_const.rs:16:7 + | +LL | #[ffi_const] + | ^^^^^^^^^ usage of unsafe attribute + | +help: wrap the attribute in `unsafe(...)` + | +LL | #[unsafe(ffi_const)] + | +++++++ + + error[E0756]: `#[ffi_const]` may only be used on foreign functions --> $DIR/ffi_const.rs:4:1 | -LL | #[ffi_const] - | ^^^^^^^^^^^^ +LL | #[unsafe(ffi_const)] + | ^^^^^^^^^^^^^^^^^^^^ error[E0756]: `#[ffi_const]` may only be used on foreign functions --> $DIR/ffi_const.rs:7:1 | -LL | #[ffi_const] - | ^^^^^^^^^^^^ +LL | #[unsafe(ffi_const)] + | ^^^^^^^^^^^^^^^^^^^^ error[E0756]: `#[ffi_const]` may only be used on foreign functions --> $DIR/ffi_const.rs:13:5 | -LL | #[ffi_const] - | ^^^^^^^^^^^^ +LL | #[unsafe(ffi_const)] + | ^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0756`. diff --git a/tests/ui/ffi-attrs/ffi_const2.rs b/tests/ui/ffi-attrs/ffi_const2.rs index 82fe8a9c91dd..8a8de13b1530 100644 --- a/tests/ui/ffi-attrs/ffi_const2.rs +++ b/tests/ui/ffi-attrs/ffi_const2.rs @@ -1,8 +1,8 @@ #![feature(ffi_const, ffi_pure)] extern "C" { - #[ffi_pure] //~ ERROR `#[ffi_const]` function cannot be `#[ffi_pure]` - #[ffi_const] + #[unsafe(ffi_pure)] //~ ERROR `#[ffi_const]` function cannot be `#[ffi_pure]` + #[unsafe(ffi_const)] pub fn baz(); } diff --git a/tests/ui/ffi-attrs/ffi_const2.stderr b/tests/ui/ffi-attrs/ffi_const2.stderr index b8cbc296370d..d4c9bc42ec9e 100644 --- a/tests/ui/ffi-attrs/ffi_const2.stderr +++ b/tests/ui/ffi-attrs/ffi_const2.stderr @@ -1,8 +1,8 @@ error[E0757]: `#[ffi_const]` function cannot be `#[ffi_pure]` --> $DIR/ffi_const2.rs:4:5 | -LL | #[ffi_pure] - | ^^^^^^^^^^^ +LL | #[unsafe(ffi_pure)] + | ^^^^^^^^^^^^^^^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/ffi-attrs/ffi_pure.rs b/tests/ui/ffi-attrs/ffi_pure.rs index 6d2f3a614ec9..1f4812f55cf1 100644 --- a/tests/ui/ffi-attrs/ffi_pure.rs +++ b/tests/ui/ffi-attrs/ffi_pure.rs @@ -1,15 +1,18 @@ #![feature(ffi_pure)] #![crate_type = "lib"] -#[ffi_pure] //~ ERROR `#[ffi_pure]` may only be used on foreign functions +#[unsafe(ffi_pure)] //~ ERROR `#[ffi_pure]` may only be used on foreign functions pub fn foo() {} -#[ffi_pure] //~ ERROR `#[ffi_pure]` may only be used on foreign functions +#[unsafe(ffi_pure)] //~ ERROR `#[ffi_pure]` may only be used on foreign functions macro_rules! bar { - () => () + () => {}; } extern "C" { - #[ffi_pure] //~ ERROR `#[ffi_pure]` may only be used on foreign functions + #[unsafe(ffi_pure)] //~ ERROR `#[ffi_pure]` may only be used on foreign functions static INT: i32; + + #[ffi_pure] //~ ERROR unsafe attribute used without unsafe + fn bar(); } diff --git a/tests/ui/ffi-attrs/ffi_pure.stderr b/tests/ui/ffi-attrs/ffi_pure.stderr index 8b61a4b609fc..bd1177c01e2b 100644 --- a/tests/ui/ffi-attrs/ffi_pure.stderr +++ b/tests/ui/ffi-attrs/ffi_pure.stderr @@ -1,21 +1,32 @@ +error: unsafe attribute used without unsafe + --> $DIR/ffi_pure.rs:16:7 + | +LL | #[ffi_pure] + | ^^^^^^^^ usage of unsafe attribute + | +help: wrap the attribute in `unsafe(...)` + | +LL | #[unsafe(ffi_pure)] + | +++++++ + + error[E0755]: `#[ffi_pure]` may only be used on foreign functions --> $DIR/ffi_pure.rs:4:1 | -LL | #[ffi_pure] - | ^^^^^^^^^^^ +LL | #[unsafe(ffi_pure)] + | ^^^^^^^^^^^^^^^^^^^ error[E0755]: `#[ffi_pure]` may only be used on foreign functions --> $DIR/ffi_pure.rs:7:1 | -LL | #[ffi_pure] - | ^^^^^^^^^^^ +LL | #[unsafe(ffi_pure)] + | ^^^^^^^^^^^^^^^^^^^ error[E0755]: `#[ffi_pure]` may only be used on foreign functions --> $DIR/ffi_pure.rs:13:5 | -LL | #[ffi_pure] - | ^^^^^^^^^^^ +LL | #[unsafe(ffi_pure)] + | ^^^^^^^^^^^^^^^^^^^ -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0755`. diff --git a/tests/ui/filter-block-view-items.rs b/tests/ui/filter-block-view-items.rs index 975ab19ddf25..cb599c272647 100644 --- a/tests/ui/filter-block-view-items.rs +++ b/tests/ui/filter-block-view-items.rs @@ -3,5 +3,5 @@ pub fn main() { // Make sure that this view item is filtered out because otherwise it would // trigger a compilation error - #[cfg(FALSE)] use bar as foo; + #[cfg(false)] use bar as foo; } diff --git a/tests/ui/fn/param-mismatch-foreign.rs b/tests/ui/fn/param-mismatch-foreign.rs index 2ab2bf95448a..eebca29d6c93 100644 --- a/tests/ui/fn/param-mismatch-foreign.rs +++ b/tests/ui/fn/param-mismatch-foreign.rs @@ -1,6 +1,7 @@ extern "C" { fn foo(x: i32, y: u32, z: i32); //~^ NOTE function defined here + //~| NOTE } fn main() { diff --git a/tests/ui/fn/param-mismatch-foreign.stderr b/tests/ui/fn/param-mismatch-foreign.stderr index 835e0a3343e9..fff3283cbb6c 100644 --- a/tests/ui/fn/param-mismatch-foreign.stderr +++ b/tests/ui/fn/param-mismatch-foreign.stderr @@ -1,5 +1,5 @@ error[E0061]: this function takes 3 arguments but 2 arguments were supplied - --> $DIR/param-mismatch-foreign.rs:7:5 + --> $DIR/param-mismatch-foreign.rs:8:5 | LL | foo(1i32, 2i32); | ^^^ ---- argument #2 of type `u32` is missing diff --git a/tests/ui/fn/suggest-return-closure.rs b/tests/ui/fn/suggest-return-closure.rs index 30e25ca8edcc..67be8de92431 100644 --- a/tests/ui/fn/suggest-return-closure.rs +++ b/tests/ui/fn/suggest-return-closure.rs @@ -19,6 +19,7 @@ fn fn_mut() -> _ { let x = String::new(); //~^ HELP: consider changing this to be mutable //~| NOTE binding `x` declared here + //~| SUGGESTION mut |c| { //~ NOTE: value captured here x.push(c); //~^ ERROR: does not live long enough diff --git a/tests/ui/fn/suggest-return-closure.stderr b/tests/ui/fn/suggest-return-closure.stderr index 45c12b548e67..1860d1ca5d92 100644 --- a/tests/ui/fn/suggest-return-closure.stderr +++ b/tests/ui/fn/suggest-return-closure.stderr @@ -21,7 +21,7 @@ LL | fn fn_mut() -> _ { = note: for more information on `Fn` traits and closure types, see https://doc.rust-lang.org/book/ch13-01-closures.html error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types - --> $DIR/suggest-return-closure.rs:32:13 + --> $DIR/suggest-return-closure.rs:33:13 | LL | fn fun() -> _ { | ^ @@ -32,7 +32,7 @@ LL | fn fun() -> _ { = note: for more information on `Fn` traits and closure types, see https://doc.rust-lang.org/book/ch13-01-closures.html error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable - --> $DIR/suggest-return-closure.rs:23:9 + --> $DIR/suggest-return-closure.rs:24:9 | LL | x.push(c); | ^ cannot borrow as mutable @@ -43,7 +43,7 @@ LL | let mut x = String::new(); | +++ error[E0597]: `x` does not live long enough - --> $DIR/suggest-return-closure.rs:23:9 + --> $DIR/suggest-return-closure.rs:24:9 | LL | let x = String::new(); | - binding `x` declared here diff --git a/tests/ui/foreign/issue-74120-lowering-of-ffi-block-bodies.rs b/tests/ui/foreign/issue-74120-lowering-of-ffi-block-bodies.rs index 7f1625c9265a..97cf3e9d51cd 100644 --- a/tests/ui/foreign/issue-74120-lowering-of-ffi-block-bodies.rs +++ b/tests/ui/foreign/issue-74120-lowering-of-ffi-block-bodies.rs @@ -5,7 +5,7 @@ extern "C" { fn f() { - //~^ incorrect function inside `extern` block + //~^ ERROR incorrect function inside `extern` block fn g() {} } } diff --git a/tests/ui/foreign/issue-91370-foreign-fn-block-impl.rs b/tests/ui/foreign/issue-91370-foreign-fn-block-impl.rs index e8634de86ea4..23e08e01e6a6 100644 --- a/tests/ui/foreign/issue-91370-foreign-fn-block-impl.rs +++ b/tests/ui/foreign/issue-91370-foreign-fn-block-impl.rs @@ -3,7 +3,7 @@ extern "C" { //~^ `extern` blocks define existing foreign functions fn f() { - //~^ incorrect function inside `extern` block + //~^ ERROR incorrect function inside `extern` block //~| cannot have a body impl Copy for u8 {} } diff --git a/tests/ui/generic-associated-types/ambig-hr-projection-issue-93340.rs b/tests/ui/generic-associated-types/ambig-hr-projection-issue-93340.rs index 5f2e134109e2..6ba3c4c65d07 100644 --- a/tests/ui/generic-associated-types/ambig-hr-projection-issue-93340.rs +++ b/tests/ui/generic-associated-types/ambig-hr-projection-issue-93340.rs @@ -13,7 +13,7 @@ fn cmp_eq<'a, 'b, A: Scalar, B: Scalar, O: Scalar>(a: A::RefType<'a>, b: B::RefT fn build_expression( ) -> impl Fn(A::RefType<'_>, B::RefType<'_>) -> O { - //[next]~^^ expected a `Fn(::RefType<'_>, ::RefType<'_>)` closure + //[next]~^^ ERROR expected a `Fn(::RefType<'_>, ::RefType<'_>)` closure cmp_eq //~^ ERROR type annotations needed } diff --git a/tests/ui/generic-associated-types/bugs/hrtb-implied-3.rs b/tests/ui/generic-associated-types/bugs/hrtb-implied-3.rs index bc9e6c8aea85..8f2b5bf8f526 100644 --- a/tests/ui/generic-associated-types/bugs/hrtb-implied-3.rs +++ b/tests/ui/generic-associated-types/bugs/hrtb-implied-3.rs @@ -17,7 +17,7 @@ where fn fails(iter: &str) { trivial_bound(iter); - //~^ borrowed data escapes + //~^ ERROR borrowed data escapes } fn main() {} diff --git a/tests/ui/generic-associated-types/collectivity-regression.rs b/tests/ui/generic-associated-types/collectivity-regression.rs index 54154f9d1fc8..d499a9ca8580 100644 --- a/tests/ui/generic-associated-types/collectivity-regression.rs +++ b/tests/ui/generic-associated-types/collectivity-regression.rs @@ -11,7 +11,7 @@ where for<'a> T: Get = ()>, { || { - //~^ `T` does not live long enough + //~^ ERROR `T` does not live long enough // // FIXME(#98437). This regressed at some point and // probably should work. diff --git a/tests/ui/generic-associated-types/const_params_have_right_type.stderr b/tests/ui/generic-associated-types/const_params_have_right_type.stderr index 78992112a7c5..a3d3a66a05c4 100644 --- a/tests/ui/generic-associated-types/const_params_have_right_type.stderr +++ b/tests/ui/generic-associated-types/const_params_have_right_type.stderr @@ -1,4 +1,4 @@ -error[E0053]: type `Foo` has an incompatible generic parameter for trait `Trait` +error[E0053]: associated type `Foo` has an incompatible generic parameter for trait `Trait` --> $DIR/const_params_have_right_type.rs:6:14 | LL | trait Trait { diff --git a/tests/ui/generic-associated-types/gat-in-trait-path.rs b/tests/ui/generic-associated-types/gat-in-trait-path.rs index 24cae213e0aa..7523803eacff 100644 --- a/tests/ui/generic-associated-types/gat-in-trait-path.rs +++ b/tests/ui/generic-associated-types/gat-in-trait-path.rs @@ -20,11 +20,11 @@ impl Foo for Fooer { } fn f(_arg : Box Foo = &'a ()>>) {} -//~^ the trait `Foo` is not dyn compatible +//~^ ERROR the trait `Foo` is not dyn compatible fn main() { let foo = Fooer(5); f(Box::new(foo)); - //~^ the trait `Foo` is not dyn compatible - //~| the trait `Foo` is not dyn compatible + //~^ ERROR the trait `Foo` is not dyn compatible + //~| ERROR the trait `Foo` is not dyn compatible } diff --git a/tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.rs b/tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.rs index 85661c1b8448..294fb6743fbc 100644 --- a/tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.rs +++ b/tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.rs @@ -3,7 +3,7 @@ trait X { } fn foo<'a>(arg: Box>) {} - //~^ ERROR: lifetime in trait object type must be followed by `+` + //~^ ERROR: lifetimes must be followed by `+` to form a trait object type //~| ERROR: parenthesized generic arguments cannot be used //~| ERROR associated type takes 0 generic arguments but 1 generic argument //~| ERROR associated type takes 1 lifetime argument but 0 lifetime arguments diff --git a/tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.stderr b/tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.stderr index 99300ea1cb7f..e18d8198c945 100644 --- a/tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.stderr +++ b/tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.stderr @@ -1,8 +1,13 @@ -error: lifetime in trait object type must be followed by `+` +error: lifetimes must be followed by `+` to form a trait object type --> $DIR/gat-trait-path-parenthesised-args.rs:5:29 | LL | fn foo<'a>(arg: Box>) {} | ^^ + | +help: consider adding a trait bound after the potential lifetime bound + | +LL | fn foo<'a>(arg: Box>) {} + | +++++++++++++ error: parenthesized generic arguments cannot be used in associated type constraints --> $DIR/gat-trait-path-parenthesised-args.rs:5:27 diff --git a/tests/ui/generic-associated-types/impl_bounds.stderr b/tests/ui/generic-associated-types/impl_bounds.stderr index 231c0dd89c52..7847bbd813cd 100644 --- a/tests/ui/generic-associated-types/impl_bounds.stderr +++ b/tests/ui/generic-associated-types/impl_bounds.stderr @@ -57,14 +57,14 @@ note: required for `Fooy` to implement `Copy` | LL | #[derive(Copy, Clone)] | ^^^^ unsatisfied trait bound introduced in this `derive` macro -note: the requirement `Fooy: Copy` appears on the `impl`'s method `d` but not on the corresponding trait's method +note: the requirement `Fooy: Copy` appears on the `impl`'s associated function `d` but not on the corresponding trait's associated function --> $DIR/impl_bounds.rs:7:8 | LL | trait Foo { | --- in this trait ... LL | fn d() where Self: Clone; - | ^ this trait's method doesn't have the requirement `Fooy: Copy` + | ^ this trait's associated function doesn't have the requirement `Fooy: Copy` help: consider restricting type parameter `T` with trait `Copy` | LL | impl Foo for Fooy { diff --git a/tests/ui/generic-associated-types/issue-102114.current.stderr b/tests/ui/generic-associated-types/issue-102114.current.stderr index 03471d08d746..5aace1eeaa2f 100644 --- a/tests/ui/generic-associated-types/issue-102114.current.stderr +++ b/tests/ui/generic-associated-types/issue-102114.current.stderr @@ -1,4 +1,4 @@ -error[E0049]: type `B` has 1 type parameter but its trait declaration has 0 type parameters +error[E0049]: associated type `B` has 1 type parameter but its trait declaration has 0 type parameters --> $DIR/issue-102114.rs:15:12 | LL | type B<'b>; diff --git a/tests/ui/generic-associated-types/issue-102114.next.stderr b/tests/ui/generic-associated-types/issue-102114.next.stderr index 03471d08d746..5aace1eeaa2f 100644 --- a/tests/ui/generic-associated-types/issue-102114.next.stderr +++ b/tests/ui/generic-associated-types/issue-102114.next.stderr @@ -1,4 +1,4 @@ -error[E0049]: type `B` has 1 type parameter but its trait declaration has 0 type parameters +error[E0049]: associated type `B` has 1 type parameter but its trait declaration has 0 type parameters --> $DIR/issue-102114.rs:15:12 | LL | type B<'b>; diff --git a/tests/ui/generic-associated-types/issue-74816.rs b/tests/ui/generic-associated-types/issue-74816.rs index e2f4ddc7485c..6ec0b3261739 100644 --- a/tests/ui/generic-associated-types/issue-74816.rs +++ b/tests/ui/generic-associated-types/issue-74816.rs @@ -11,7 +11,7 @@ trait Trait1 { trait Trait2 { type Associated: Trait1 = Self; //~^ ERROR: the trait bound `Self: Trait1` is not satisfied - //~| the size for values of type `Self` cannot be known + //~| ERROR the size for values of type `Self` cannot be known } impl Trait2 for () {} diff --git a/tests/ui/generic-associated-types/issue-78113-lifetime-mismatch-dyn-trait-box.rs b/tests/ui/generic-associated-types/issue-78113-lifetime-mismatch-dyn-trait-box.rs index 1c94067029da..f913efd75779 100644 --- a/tests/ui/generic-associated-types/issue-78113-lifetime-mismatch-dyn-trait-box.rs +++ b/tests/ui/generic-associated-types/issue-78113-lifetime-mismatch-dyn-trait-box.rs @@ -12,7 +12,7 @@ pub trait B { impl B for () { // `'a` doesn't match implicit `'static`: suggest `'_` - type T<'a> = Box; //~ incompatible lifetime on type + type T<'a> = Box; //~ ERROR incompatible lifetime on type } trait C {} @@ -22,7 +22,7 @@ pub trait D { } impl D for () { // `'a` doesn't match explicit `'static`: we *should* suggest removing `'static` - type T<'a> = Box; //~ incompatible lifetime on type + type T<'a> = Box; //~ ERROR incompatible lifetime on type } trait E {} @@ -32,7 +32,7 @@ pub trait F { } impl F for () { // `'a` doesn't match explicit `'static`: suggest `'_` - type T<'a> = (Box, Box); //~ incompatible lifetime on type + type T<'a> = (Box, Box); //~ ERROR incompatible lifetime on type } fn main() {} diff --git a/tests/ui/generic-associated-types/issue-86787.rs b/tests/ui/generic-associated-types/issue-86787.rs index 88cdd472696b..43c193b91d05 100644 --- a/tests/ui/generic-associated-types/issue-86787.rs +++ b/tests/ui/generic-associated-types/issue-86787.rs @@ -8,7 +8,7 @@ enum Either { pub trait HasChildrenOf { type T; type TRef<'a>; - //~^ missing required + //~^ ERROR missing required fn ref_children<'a>(&'a self) -> Vec>; fn take_children(self) -> Vec; diff --git a/tests/ui/generic-associated-types/issue-88360.fixed b/tests/ui/generic-associated-types/issue-88360.fixed index 2ebc459f1974..f24a86b240b8 100644 --- a/tests/ui/generic-associated-types/issue-88360.fixed +++ b/tests/ui/generic-associated-types/issue-88360.fixed @@ -14,7 +14,7 @@ where { fn copy(&self) -> Self::Gat<'_> where T: Copy { self.test() - //~^ mismatched types + //~^ ERROR mismatched types } } diff --git a/tests/ui/generic-associated-types/issue-88360.rs b/tests/ui/generic-associated-types/issue-88360.rs index 011061dd8613..12c18061d043 100644 --- a/tests/ui/generic-associated-types/issue-88360.rs +++ b/tests/ui/generic-associated-types/issue-88360.rs @@ -14,7 +14,7 @@ where { fn copy(&self) -> Self::Gat<'_> where T: Copy { *self.test() - //~^ mismatched types + //~^ ERROR mismatched types } } diff --git a/tests/ui/generic-associated-types/missing-where-clause-on-trait.rs b/tests/ui/generic-associated-types/missing-where-clause-on-trait.rs index c8a924663110..5354421f4b9b 100644 --- a/tests/ui/generic-associated-types/missing-where-clause-on-trait.rs +++ b/tests/ui/generic-associated-types/missing-where-clause-on-trait.rs @@ -5,7 +5,7 @@ trait Foo { } impl Foo for () { type Assoc<'a, 'b> = () where 'a: 'b; - //~^ impl has stricter requirements than trait + //~^ ERROR impl has stricter requirements than trait } fn main() {} diff --git a/tests/ui/generic-associated-types/parameter_number_and_kind_impl.rs b/tests/ui/generic-associated-types/parameter_number_and_kind_impl.rs index c1381025ac2a..a39a7aacc7b3 100644 --- a/tests/ui/generic-associated-types/parameter_number_and_kind_impl.rs +++ b/tests/ui/generic-associated-types/parameter_number_and_kind_impl.rs @@ -12,11 +12,11 @@ struct Fooy; impl Foo for Fooy { type A = u32; - //~^ ERROR lifetime parameters or bounds on type `A` do not match the trait declaration + //~^ ERROR lifetime parameters or bounds on associated type `A` do not match the trait declaration type B<'a, T> = Vec; //~^ ERROR type `B` has 1 type parameter but its trait declaration has 0 type parameters type C<'a> = u32; - //~^ ERROR lifetime parameters or bounds on type `C` do not match the trait declaration + //~^ ERROR lifetime parameters or bounds on associated type `C` do not match the trait declaration } struct Fooer; @@ -25,7 +25,7 @@ impl Foo for Fooer { type A = u32; //~^ ERROR type `A` has 1 type parameter but its trait declaration has 0 type parameters type B<'a> = u32; - //~^ ERROR lifetime parameters or bounds on type `B` do not match the trait declaration + //~^ ERROR lifetime parameters or bounds on associated type `B` do not match the trait declaration type C = T; //~^ ERROR type `C` has 1 type parameter but its trait declaration has 0 type parameters } diff --git a/tests/ui/generic-associated-types/parameter_number_and_kind_impl.stderr b/tests/ui/generic-associated-types/parameter_number_and_kind_impl.stderr index fdd6d305ab27..f7c4a07589c2 100644 --- a/tests/ui/generic-associated-types/parameter_number_and_kind_impl.stderr +++ b/tests/ui/generic-associated-types/parameter_number_and_kind_impl.stderr @@ -1,13 +1,13 @@ -error[E0195]: lifetime parameters or bounds on type `A` do not match the trait declaration +error[E0195]: lifetime parameters or bounds on associated type `A` do not match the trait declaration --> $DIR/parameter_number_and_kind_impl.rs:14:11 | LL | type A<'a>; - | ---- lifetimes in impl do not match this type in trait + | ---- lifetimes in impl do not match this associated type in trait ... LL | type A = u32; - | ^ lifetimes do not match type in trait + | ^ lifetimes do not match associated type in trait -error[E0049]: type `B` has 1 type parameter but its trait declaration has 0 type parameters +error[E0049]: associated type `B` has 1 type parameter but its trait declaration has 0 type parameters --> $DIR/parameter_number_and_kind_impl.rs:16:12 | LL | type B<'a, 'b>; @@ -20,16 +20,16 @@ LL | type B<'a, T> = Vec; | | | found 1 type parameter -error[E0195]: lifetime parameters or bounds on type `C` do not match the trait declaration +error[E0195]: lifetime parameters or bounds on associated type `C` do not match the trait declaration --> $DIR/parameter_number_and_kind_impl.rs:18:11 | LL | type C; - | - lifetimes in impl do not match this type in trait + | - lifetimes in impl do not match this associated type in trait ... LL | type C<'a> = u32; - | ^^^^ lifetimes do not match type in trait + | ^^^^ lifetimes do not match associated type in trait -error[E0049]: type `A` has 1 type parameter but its trait declaration has 0 type parameters +error[E0049]: associated type `A` has 1 type parameter but its trait declaration has 0 type parameters --> $DIR/parameter_number_and_kind_impl.rs:25:12 | LL | type A<'a>; @@ -38,16 +38,16 @@ LL | type A<'a>; LL | type A = u32; | ^ found 1 type parameter -error[E0195]: lifetime parameters or bounds on type `B` do not match the trait declaration +error[E0195]: lifetime parameters or bounds on associated type `B` do not match the trait declaration --> $DIR/parameter_number_and_kind_impl.rs:27:11 | LL | type B<'a, 'b>; - | -------- lifetimes in impl do not match this type in trait + | -------- lifetimes in impl do not match this associated type in trait ... LL | type B<'a> = u32; - | ^^^^ lifetimes do not match type in trait + | ^^^^ lifetimes do not match associated type in trait -error[E0049]: type `C` has 1 type parameter but its trait declaration has 0 type parameters +error[E0049]: associated type `C` has 1 type parameter but its trait declaration has 0 type parameters --> $DIR/parameter_number_and_kind_impl.rs:29:12 | LL | type C; diff --git a/tests/ui/generic-associated-types/self-outlives-lint.rs b/tests/ui/generic-associated-types/self-outlives-lint.rs index 699b3a8c5092..2e58a72fb5c2 100644 --- a/tests/ui/generic-associated-types/self-outlives-lint.rs +++ b/tests/ui/generic-associated-types/self-outlives-lint.rs @@ -5,7 +5,7 @@ use std::fmt::Debug; // We have a `&'a self`, so we need a `Self: 'a` trait Iterable { type Item<'x>; - //~^ missing required + //~^ ERROR missing required fn iter<'a>(&'a self) -> Self::Item<'a>; } @@ -21,7 +21,7 @@ impl Iterable for T { // We have a `&'a T`, so we need a `T: 'x` trait Deserializer { type Out<'x>; - //~^ missing required + //~^ ERROR missing required fn deserialize<'a>(&self, input: &'a T) -> Self::Out<'a>; } @@ -35,14 +35,14 @@ impl Deserializer for () { // We have a `&'b T` and a `'b: 'a`, so it is implied that `T: 'a`. Therefore, we need a `T: 'x` trait Deserializer2 { type Out<'x>; - //~^ missing required + //~^ ERROR missing required fn deserialize2<'a, 'b: 'a>(&self, input1: &'b T) -> Self::Out<'a>; } // We have a `&'a T` and a `&'b U`, so we need a `T: 'x` and a `U: 'y` trait Deserializer3 { type Out<'x, 'y>; - //~^ missing required + //~^ ERROR missing required fn deserialize2<'a, 'b>(&self, input: &'a T, input2: &'b U) -> Self::Out<'a, 'b>; } @@ -57,7 +57,7 @@ struct Wrap(T); // We pass `Wrap` and we see `&'z Wrap`, so we require `D: 'x` trait Des { type Out<'x, D>; - //~^ missing required + //~^ ERROR missing required fn des<'z, T>(&self, data: &'z Wrap) -> Self::Out<'z, Wrap>; } /* @@ -73,7 +73,7 @@ impl Des for () { // implied bound that `T: 'z`, so we require `D: 'x` trait Des2 { type Out<'x, D>; - //~^ missing required + //~^ ERROR missing required fn des<'z, T>(&self, data: &'z Wrap) -> Self::Out<'z, T>; } /* @@ -88,7 +88,7 @@ impl Des2 for () { // We see `&'z T`, so we require `D: 'x` trait Des3 { type Out<'x, D>; - //~^ missing required + //~^ ERROR missing required fn des<'z, T>(&self, data: &'z T) -> Self::Out<'z, T>; } /* @@ -110,7 +110,7 @@ trait NoGat<'a> { // FIXME: we require two bounds (`where Self: 'a, Self: 'b`) when we should only require one trait TraitLifetime<'a> { type Bar<'b>; - //~^ missing required + //~^ ERROR missing required fn method(&'a self) -> Self::Bar<'a>; } @@ -118,14 +118,14 @@ trait TraitLifetime<'a> { // FIXME: we require two bounds (`where Self: 'a, Self: 'b`) when we should only require one trait TraitLifetimeWhere<'a> where Self: 'a { type Bar<'b>; - //~^ missing required + //~^ ERROR missing required fn method(&'a self) -> Self::Bar<'a>; } // Explicit bound instead of implicit; we want to still error trait ExplicitBound { type Bar<'b>; - //~^ missing required + //~^ ERROR missing required fn method<'b>(&self, token: &'b ()) -> Self::Bar<'b> where Self: 'b; } @@ -138,15 +138,15 @@ trait NotInReturn { // We obviously error for `Iterator`, but we should also error for `Item` trait IterableTwo { type Item<'a>; - //~^ missing required + //~^ ERROR missing required type Iterator<'a>: Iterator>; - //~^ missing required + //~^ ERROR missing required fn iter<'a>(&'a self) -> Self::Iterator<'a>; } trait IterableTwoWhere { type Item<'a>; - //~^ missing required + //~^ ERROR missing required type Iterator<'a>: Iterator> where Self: 'a; fn iter<'a>(&'a self) -> Self::Iterator<'a>; } @@ -155,7 +155,7 @@ trait IterableTwoWhere { // because of `&'x &'y`, so we require that `'b: 'a`. trait RegionOutlives { type Bar<'a, 'b>; - //~^ missing required + //~^ ERROR missing required fn foo<'x, 'y>(&self, input: &'x &'y ()) -> Self::Bar<'x, 'y>; } @@ -171,7 +171,7 @@ impl Foo for () { // Similar to the above, except with explicit bounds trait ExplicitRegionOutlives<'ctx> { type Fut<'out>; - //~^ missing required + //~^ ERROR missing required fn test<'out>(ctx: &'ctx i32) -> Self::Fut<'out> where @@ -211,7 +211,7 @@ trait StaticReturnAndTakes<'a> { // We require bounds when the GAT appears in the inputs trait Input { type Item<'a>; - //~^ missing required + //~^ ERROR missing required fn takes_item<'a>(&'a self, item: Self::Item<'a>); } diff --git a/tests/ui/generic-associated-types/trait-objects.rs b/tests/ui/generic-associated-types/trait-objects.rs index ed324b562e1c..256cfee4c809 100644 --- a/tests/ui/generic-associated-types/trait-objects.rs +++ b/tests/ui/generic-associated-types/trait-objects.rs @@ -6,10 +6,10 @@ trait StreamingIterator { } fn min_size(x: &mut dyn for<'a> StreamingIterator = &'a i32>) -> usize { - //~^ the trait `StreamingIterator` is not dyn compatible + //~^ ERROR the trait `StreamingIterator` is not dyn compatible x.size_hint().0 - //~^ the trait `StreamingIterator` is not dyn compatible - //~| the trait `StreamingIterator` is not dyn compatible + //~^ ERROR the trait `StreamingIterator` is not dyn compatible + //~| ERROR the trait `StreamingIterator` is not dyn compatible } fn main() {} diff --git a/tests/ui/generic-associated-types/type-param-defaults.rs b/tests/ui/generic-associated-types/type-param-defaults.rs index a9c8c5c12d9e..eea54c460734 100644 --- a/tests/ui/generic-associated-types/type-param-defaults.rs +++ b/tests/ui/generic-associated-types/type-param-defaults.rs @@ -4,17 +4,17 @@ trait Trait { type Assoc; - //~^ defaults for type parameters are only allowed + //~^ ERROR defaults for type parameters are only allowed } impl Trait for () { type Assoc = u64; - //~^ defaults for type parameters are only allowed + //~^ ERROR defaults for type parameters are only allowed } impl Trait for u32 { type Assoc = T; - //~^ defaults for type parameters are only allowed + //~^ ERROR defaults for type parameters are only allowed } trait Other {} diff --git a/tests/ui/generic-const-items/assoc-const-missing-type.rs b/tests/ui/generic-const-items/assoc-const-missing-type.rs index 0c94a4262ef4..dde47cf993ea 100644 --- a/tests/ui/generic-const-items/assoc-const-missing-type.rs +++ b/tests/ui/generic-const-items/assoc-const-missing-type.rs @@ -14,7 +14,7 @@ impl Trait for () { //~| ERROR mismatched types const Q = ""; //~^ ERROR missing type for `const` item - //~| ERROR lifetime parameters or bounds on const `Q` do not match the trait declaration + //~| ERROR lifetime parameters or bounds on associated const `Q` do not match the trait declaration } fn main() {} diff --git a/tests/ui/generic-const-items/assoc-const-missing-type.stderr b/tests/ui/generic-const-items/assoc-const-missing-type.stderr index 5af119dffa7c..9f6db575ec23 100644 --- a/tests/ui/generic-const-items/assoc-const-missing-type.stderr +++ b/tests/ui/generic-const-items/assoc-const-missing-type.stderr @@ -15,14 +15,14 @@ error: missing type for `const` item LL | const K = (); | ^ help: provide a type for the associated constant: `()` -error[E0195]: lifetime parameters or bounds on const `Q` do not match the trait declaration +error[E0195]: lifetime parameters or bounds on associated const `Q` do not match the trait declaration --> $DIR/assoc-const-missing-type.rs:15:12 | LL | const Q<'a>: &'a str; - | ---- lifetimes in impl do not match this const in trait + | ---- lifetimes in impl do not match this associated const in trait ... LL | const Q = ""; - | ^ lifetimes do not match const in trait + | ^ lifetimes do not match associated const in trait error: missing type for `const` item --> $DIR/assoc-const-missing-type.rs:15:12 diff --git a/tests/ui/generic-const-items/compare-impl-item.rs b/tests/ui/generic-const-items/compare-impl-item.rs index 21c958a0abec..b301cd0dae0c 100644 --- a/tests/ui/generic-const-items/compare-impl-item.rs +++ b/tests/ui/generic-const-items/compare-impl-item.rs @@ -22,7 +22,7 @@ impl

Trait

for () { const D: u16 = N; //~^ ERROR const `D` has an incompatible generic parameter for trait `Trait` const E: &'static () = &(); - //~^ ERROR lifetime parameters or bounds on const `E` do not match the trait declaration + //~^ ERROR lifetime parameters or bounds on associated const `E` do not match the trait declaration const F: usize = 1024 where diff --git a/tests/ui/generic-const-items/compare-impl-item.stderr b/tests/ui/generic-const-items/compare-impl-item.stderr index 3bf28e9da60f..f7e3ff6501b1 100644 --- a/tests/ui/generic-const-items/compare-impl-item.stderr +++ b/tests/ui/generic-const-items/compare-impl-item.stderr @@ -1,4 +1,4 @@ -error[E0049]: const `A` has 1 type parameter but its trait declaration has 0 type parameters +error[E0049]: associated const `A` has 1 type parameter but its trait declaration has 0 type parameters --> $DIR/compare-impl-item.rs:16:13 | LL | const A: (); @@ -7,7 +7,7 @@ LL | const A: (); LL | const A: () = (); | ^ found 1 type parameter -error[E0049]: const `B` has 1 const parameter but its trait declaration has 2 const parameters +error[E0049]: associated const `B` has 1 const parameter but its trait declaration has 2 const parameters --> $DIR/compare-impl-item.rs:18:13 | LL | const B: u64; @@ -18,7 +18,7 @@ LL | const B: u64; LL | const B: u64 = 0; | ^^^^^^^^^^^^ found 1 const parameter -error[E0049]: const `C` has 0 type parameters but its trait declaration has 1 type parameter +error[E0049]: associated const `C` has 0 type parameters but its trait declaration has 1 type parameter --> $DIR/compare-impl-item.rs:20:13 | LL | const C: T; @@ -27,7 +27,7 @@ LL | const C: T; LL | const C<'a>: &'a str = ""; | ^^ found 0 type parameters -error[E0053]: const `D` has an incompatible generic parameter for trait `Trait` +error[E0053]: associated const `D` has an incompatible generic parameter for trait `Trait` --> $DIR/compare-impl-item.rs:22:13 | LL | trait Trait

{ @@ -42,14 +42,14 @@ LL | impl

Trait

for () { LL | const D: u16 = N; | ^^^^^^^^^^^^ found const parameter of type `u16` -error[E0195]: lifetime parameters or bounds on const `E` do not match the trait declaration +error[E0195]: lifetime parameters or bounds on associated const `E` do not match the trait declaration --> $DIR/compare-impl-item.rs:24:12 | LL | const E<'a>: &'a (); - | ---- lifetimes in impl do not match this const in trait + | ---- lifetimes in impl do not match this associated const in trait ... LL | const E: &'static () = &(); - | ^ lifetimes do not match const in trait + | ^ lifetimes do not match associated const in trait error[E0276]: impl has stricter requirements than trait --> $DIR/compare-impl-item.rs:29:12 diff --git a/tests/ui/generics/single-colon-path-not-const-generics.stderr b/tests/ui/generics/single-colon-path-not-const-generics.stderr index c14a5e62a0c8..9eb62de27561 100644 --- a/tests/ui/generics/single-colon-path-not-const-generics.stderr +++ b/tests/ui/generics/single-colon-path-not-const-generics.stderr @@ -4,7 +4,6 @@ error: path separator must be a double colon LL | a: Vec, | ^ | - = note: if you meant to annotate an expression with a type, the type ascription syntax has been removed, see issue #101728 help: use a double colon instead | LL | a: Vec, diff --git a/tests/ui/half-open-range-patterns/feature-gate-half-open-range-patterns-in-slices.rs b/tests/ui/half-open-range-patterns/feature-gate-half-open-range-patterns-in-slices.rs index a7b0ca6fe4a5..f2c873f3edf1 100644 --- a/tests/ui/half-open-range-patterns/feature-gate-half-open-range-patterns-in-slices.rs +++ b/tests/ui/half-open-range-patterns/feature-gate-half-open-range-patterns-in-slices.rs @@ -1,6 +1,6 @@ fn main() { let xs = [13, 1, 5, 2, 3, 1, 21, 8]; let [a @ 3.., b @ ..3, c @ 4..6, ..] = xs; - //~^ `X..` patterns in slices are experimental + //~^ ERROR `X..` patterns in slices are experimental //~| ERROR: refutable pattern } diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-dotdotdot-bad-syntax.rs b/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-dotdotdot-bad-syntax.rs index 33506a5c444a..01f4340b14ad 100644 --- a/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-dotdotdot-bad-syntax.rs +++ b/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-dotdotdot-bad-syntax.rs @@ -9,7 +9,7 @@ fn main() {} -#[cfg(FALSE)] +#[cfg(false)] fn syntax() { match scrutinee { ...X => {} //~ ERROR range-to patterns with `...` are not allowed diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-no-end.rs b/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-no-end.rs index 2f1ec6589721..24eb99347329 100644 --- a/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-no-end.rs +++ b/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-no-end.rs @@ -3,7 +3,7 @@ fn main() {} -#[cfg(FALSE)] +#[cfg(false)] fn foo() { if let 0... = 1 {} //~ ERROR inclusive range with no end if let 0..= = 1 {} //~ ERROR inclusive range with no end diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-ref-ambiguous-interp.rs b/tests/ui/half-open-range-patterns/half-open-range-pats-ref-ambiguous-interp.rs index 2d63fe078561..6b33ead3f87d 100644 --- a/tests/ui/half-open-range-patterns/half-open-range-pats-ref-ambiguous-interp.rs +++ b/tests/ui/half-open-range-patterns/half-open-range-pats-ref-ambiguous-interp.rs @@ -1,6 +1,6 @@ fn main() {} -#[cfg(FALSE)] +#[cfg(false)] fn syntax() { match &0 { &0.. | _ => {} diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-syntactic-pass.rs b/tests/ui/half-open-range-patterns/half-open-range-pats-syntactic-pass.rs index 4e3fffbef2de..02699e76ad29 100644 --- a/tests/ui/half-open-range-patterns/half-open-range-pats-syntactic-pass.rs +++ b/tests/ui/half-open-range-patterns/half-open-range-pats-syntactic-pass.rs @@ -4,7 +4,7 @@ fn main() {} -#[cfg(FALSE)] +#[cfg(false)] fn syntax() { match scrutinee { X.. | 0.. | 'a'.. | 0.0f32.. => {} diff --git a/tests/ui/half-open-range-patterns/slice_pattern_syntax_problem0.rs b/tests/ui/half-open-range-patterns/slice_pattern_syntax_problem0.rs index aa2690f37776..7bd1c100dc4f 100644 --- a/tests/ui/half-open-range-patterns/slice_pattern_syntax_problem0.rs +++ b/tests/ui/half-open-range-patterns/slice_pattern_syntax_problem0.rs @@ -8,7 +8,7 @@ fn main() { // What if we wanted to pull this apart without individually binding a, b, and c? let [first_three @ ..3, rest @ 2..] = xs; - //~^ pattern requires 2 elements but array has 8 + //~^ ERROR pattern requires 2 elements but array has 8 // This is somewhat unintuitive and makes slice patterns exceedingly verbose. // We want to stabilize half-open RangeFrom (`X..`) patterns // but without banning us from using them for a more efficient slice pattern syntax. diff --git a/tests/ui/half-open-range-patterns/slice_pattern_syntax_problem1.rs b/tests/ui/half-open-range-patterns/slice_pattern_syntax_problem1.rs index 60b056fbcb69..12ceaa8c878c 100644 --- a/tests/ui/half-open-range-patterns/slice_pattern_syntax_problem1.rs +++ b/tests/ui/half-open-range-patterns/slice_pattern_syntax_problem1.rs @@ -2,6 +2,6 @@ fn main() { let xs = [13, 1, 5, 2, 3, 1, 21, 8]; let [a @ 3.., b @ ..3, c @ 4..6, ..] = xs; - //~^ `X..` patterns in slices are experimental + //~^ ERROR `X..` patterns in slices are experimental //~| ERROR: refutable pattern } diff --git a/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.current.stderr b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.current.stderr index 7b9fd6bb4c57..c8394575e71d 100644 --- a/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.current.stderr +++ b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.current.stderr @@ -13,7 +13,7 @@ LL | fn projection_bound Trait<'a, Assoc = usize>>() {} | ^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/candidate-from-env-universe-err-project.rs:53:30 + --> $DIR/candidate-from-env-universe-err-project.rs:52:30 | LL | let _higher_ranked_norm: for<'a> fn(>::Assoc) = |_| (); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other @@ -22,7 +22,7 @@ LL | let _higher_ranked_norm: for<'a> fn(>::Assoc) = |_| (); found associated type `>::Assoc` error[E0308]: mismatched types - --> $DIR/candidate-from-env-universe-err-project.rs:53:30 + --> $DIR/candidate-from-env-universe-err-project.rs:52:30 | LL | let _higher_ranked_norm: for<'a> fn(>::Assoc) = |_| (); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other diff --git a/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.next.stderr b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.next.stderr index 6e0ec5620da0..468dc3b082e5 100644 --- a/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.next.stderr +++ b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.next.stderr @@ -22,38 +22,20 @@ note: required by a bound in `projection_bound` LL | fn projection_bound Trait<'a, Assoc = usize>>() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `projection_bound` -error[E0271]: type mismatch resolving `>::Assoc == usize` - --> $DIR/candidate-from-env-universe-err-project.rs:38:24 - | -LL | projection_bound::(); - | ^ type mismatch resolving `>::Assoc == usize` - | -note: types differ - --> $DIR/candidate-from-env-universe-err-project.rs:14:18 - | -LL | type Assoc = usize; - | ^^^^^ -note: required by a bound in `projection_bound` - --> $DIR/candidate-from-env-universe-err-project.rs:18:42 - | -LL | fn projection_bound Trait<'a, Assoc = usize>>() {} - | ^^^^^^^^^^^^^ required by this bound in `projection_bound` - error: higher-ranked subtype error - --> $DIR/candidate-from-env-universe-err-project.rs:53:30 + --> $DIR/candidate-from-env-universe-err-project.rs:52:30 | LL | let _higher_ranked_norm: for<'a> fn(>::Assoc) = |_| (); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: higher-ranked subtype error - --> $DIR/candidate-from-env-universe-err-project.rs:53:30 + --> $DIR/candidate-from-env-universe-err-project.rs:52:30 | LL | let _higher_ranked_norm: for<'a> fn(>::Assoc) = |_| (); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: aborting due to 5 previous errors +error: aborting due to 4 previous errors -Some errors have detailed explanations: E0271, E0277. -For more information about an error, try `rustc --explain E0271`. +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.rs b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.rs index a77d87f6fa78..d70e39223821 100644 --- a/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.rs +++ b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.rs @@ -36,9 +36,8 @@ fn function2>() { // does not use the leak check when trying the where-bound, causing us // to prefer it over the impl, resulting in a placeholder error. projection_bound::(); - //[next]~^ ERROR type mismatch resolving `>::Assoc == usize` - //[next]~| ERROR the trait bound `for<'a> T: Trait<'a>` is not satisfied - //[current]~^^^ ERROR mismatched types + //[next]~^ ERROR the trait bound `for<'a> T: Trait<'a>` is not satisfied + //[current]~^^ ERROR mismatched types } fn function3>() { diff --git a/tests/ui/higher-ranked/trait-bounds/issue-95034.rs b/tests/ui/higher-ranked/trait-bounds/issue-95034.rs index 53b28c2bea45..f33469796c2f 100644 --- a/tests/ui/higher-ranked/trait-bounds/issue-95034.rs +++ b/tests/ui/higher-ranked/trait-bounds/issue-95034.rs @@ -1,5 +1,6 @@ //@ check-pass -//@ compile-flags: --edition=2021 --crate-type=lib +//@ compile-flags: --crate-type=lib +//@ edition: 2021 use std::{ future::Future, diff --git a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-3.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-3.rs index d84e30f4984e..10bfc954a474 100644 --- a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-3.rs +++ b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-3.rs @@ -23,7 +23,7 @@ impl WithDefault for () { //f(()); // Going through another generic function works fine. call(f, ()); - //~^ expected a + //~^ ERROR expected a } } diff --git a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-3.stderr b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-3.stderr index 64707642eeb0..36264b0d997b 100644 --- a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-3.stderr +++ b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-3.stderr @@ -6,8 +6,8 @@ LL | call(f, ()); | | | required by a bound introduced by this call | - = note: expected a closure with arguments `((),)` - found a closure with arguments `(<_ as ATC<'a>>::Type,)` + = note: expected a closure with signature `for<'a> fn(<_ as ATC<'a>>::Type)` + found a closure with signature `fn(())` note: this is a known limitation of the trait solver that will be lifted in the future --> $DIR/issue-62529-3.rs:25:14 | diff --git a/tests/ui/hygiene/rustc-macro-transparency.rs b/tests/ui/hygiene/rustc-macro-transparency.rs index 5f36993af2f3..1a78a7543cfd 100644 --- a/tests/ui/hygiene/rustc-macro-transparency.rs +++ b/tests/ui/hygiene/rustc-macro-transparency.rs @@ -6,9 +6,9 @@ macro transparent() { let transparent = 0; } #[rustc_macro_transparency = "semitransparent"] -macro semitransparent() { - struct SemiTransparent; - let semitransparent = 0; +macro semiopaque() { + struct SemiOpaque; + let semiopaque = 0; } #[rustc_macro_transparency = "opaque"] macro opaque() { @@ -18,14 +18,14 @@ macro opaque() { fn main() { transparent!(); - semitransparent!(); + semiopaque!(); opaque!(); Transparent; // OK - SemiTransparent; // OK + SemiOpaque; // OK Opaque; //~ ERROR cannot find value `Opaque` in this scope transparent; // OK - semitransparent; //~ ERROR expected value, found macro `semitransparent` + semiopaque; //~ ERROR expected value, found macro `semiopaque` opaque; //~ ERROR expected value, found macro `opaque` } diff --git a/tests/ui/hygiene/rustc-macro-transparency.stderr b/tests/ui/hygiene/rustc-macro-transparency.stderr index 1d2a1e124986..1bea8a0ee4f3 100644 --- a/tests/ui/hygiene/rustc-macro-transparency.stderr +++ b/tests/ui/hygiene/rustc-macro-transparency.stderr @@ -4,17 +4,17 @@ error[E0425]: cannot find value `Opaque` in this scope LL | Opaque; | ^^^^^^ not found in this scope -error[E0423]: expected value, found macro `semitransparent` +error[E0423]: expected value, found macro `semiopaque` --> $DIR/rustc-macro-transparency.rs:29:5 | -LL | struct SemiTransparent; - | ----------------------- similarly named unit struct `SemiTransparent` defined here +LL | struct SemiOpaque; + | ------------------ similarly named unit struct `SemiOpaque` defined here ... -LL | semitransparent; - | ^^^^^^^^^^^^^^^ +LL | semiopaque; + | ^^^^^^^^^^ | | | not a value - | help: a unit struct with a similar name exists: `SemiTransparent` + | help: a unit struct with a similar name exists (notice the capitalization): `SemiOpaque` error[E0423]: expected value, found macro `opaque` --> $DIR/rustc-macro-transparency.rs:30:5 diff --git a/tests/ui/hygiene/unpretty-debug.stdout b/tests/ui/hygiene/unpretty-debug.stdout index e475cfac2fc1..f35bd7a7cb2c 100644 --- a/tests/ui/hygiene/unpretty-debug.stdout +++ b/tests/ui/hygiene/unpretty-debug.stdout @@ -24,5 +24,5 @@ crate0::{{expn1}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: SyntaxContexts: #0: parent: #0, outer_mark: (crate0::{{expn0}}, Opaque) -#1: parent: #0, outer_mark: (crate0::{{expn1}}, SemiTransparent) +#1: parent: #0, outer_mark: (crate0::{{expn1}}, SemiOpaque) */ diff --git a/tests/ui/illegal-sized-bound/regular.rs b/tests/ui/illegal-sized-bound/regular.rs index 7abd27ef9831..b5a4cbf10eca 100644 --- a/tests/ui/illegal-sized-bound/regular.rs +++ b/tests/ui/illegal-sized-bound/regular.rs @@ -4,7 +4,7 @@ pub trait MutTrait { fn function(&mut self) where Self: Sized; - //~^ this has a `Sized` requirement + //~^ NOTE this has a `Sized` requirement } impl MutTrait for MutType { @@ -17,7 +17,7 @@ pub trait Trait { fn function(&self) where Self: Sized; - //~^ this has a `Sized` requirement + //~^ NOTE this has a `Sized` requirement } impl Trait for Type { diff --git a/tests/ui/impl-trait/auto-trait-coherence.rs b/tests/ui/impl-trait/auto-trait-leakage/auto-trait-coherence.rs similarity index 100% rename from tests/ui/impl-trait/auto-trait-coherence.rs rename to tests/ui/impl-trait/auto-trait-leakage/auto-trait-coherence.rs diff --git a/tests/ui/impl-trait/auto-trait-coherence.stderr b/tests/ui/impl-trait/auto-trait-leakage/auto-trait-coherence.stderr similarity index 100% rename from tests/ui/impl-trait/auto-trait-coherence.stderr rename to tests/ui/impl-trait/auto-trait-leakage/auto-trait-coherence.stderr diff --git a/tests/ui/impl-trait/auto-trait-contains-err.rs b/tests/ui/impl-trait/auto-trait-leakage/auto-trait-contains-err.rs similarity index 92% rename from tests/ui/impl-trait/auto-trait-contains-err.rs rename to tests/ui/impl-trait/auto-trait-leakage/auto-trait-contains-err.rs index d7f094211d7d..8a2ebe301f11 100644 --- a/tests/ui/impl-trait/auto-trait-contains-err.rs +++ b/tests/ui/impl-trait/auto-trait-leakage/auto-trait-contains-err.rs @@ -1,4 +1,4 @@ -//@ compile-flags: --edition=2021 +//@ edition: 2021 use std::future::Future; diff --git a/tests/ui/impl-trait/auto-trait-contains-err.stderr b/tests/ui/impl-trait/auto-trait-leakage/auto-trait-contains-err.stderr similarity index 100% rename from tests/ui/impl-trait/auto-trait-contains-err.stderr rename to tests/ui/impl-trait/auto-trait-leakage/auto-trait-contains-err.stderr diff --git a/tests/ui/impl-trait/auto-trait-leak-rpass.rs b/tests/ui/impl-trait/auto-trait-leakage/auto-trait-leak-rpass.rs similarity index 100% rename from tests/ui/impl-trait/auto-trait-leak-rpass.rs rename to tests/ui/impl-trait/auto-trait-leakage/auto-trait-leak-rpass.rs diff --git a/tests/ui/impl-trait/auto-trait-leak.rs b/tests/ui/impl-trait/auto-trait-leakage/auto-trait-leak.rs similarity index 100% rename from tests/ui/impl-trait/auto-trait-leak.rs rename to tests/ui/impl-trait/auto-trait-leakage/auto-trait-leak.rs diff --git a/tests/ui/impl-trait/auto-trait-leak.stderr b/tests/ui/impl-trait/auto-trait-leakage/auto-trait-leak.stderr similarity index 100% rename from tests/ui/impl-trait/auto-trait-leak.stderr rename to tests/ui/impl-trait/auto-trait-leakage/auto-trait-leak.stderr diff --git a/tests/ui/impl-trait/auto-trait-leak2.rs b/tests/ui/impl-trait/auto-trait-leakage/auto-trait-leak2.rs similarity index 100% rename from tests/ui/impl-trait/auto-trait-leak2.rs rename to tests/ui/impl-trait/auto-trait-leakage/auto-trait-leak2.rs diff --git a/tests/ui/impl-trait/auto-trait-leak2.stderr b/tests/ui/impl-trait/auto-trait-leakage/auto-trait-leak2.stderr similarity index 100% rename from tests/ui/impl-trait/auto-trait-leak2.stderr rename to tests/ui/impl-trait/auto-trait-leakage/auto-trait-leak2.stderr diff --git a/tests/ui/impl-trait/auto-trait-leakage/avoid-query-cycle-via-item-bound.rs b/tests/ui/impl-trait/auto-trait-leakage/avoid-query-cycle-via-item-bound.rs new file mode 100644 index 000000000000..7f366fdcabd2 --- /dev/null +++ b/tests/ui/impl-trait/auto-trait-leakage/avoid-query-cycle-via-item-bound.rs @@ -0,0 +1,33 @@ +//@ check-pass +//@ revisions: current next +//@[next] compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) + +// When proving auto trait bounds, make sure that we depend on auto trait +// leakage if we can also prove it via an item bound. +fn is_send(_: T) {} + +fn direct() -> impl Send { + is_send(check(false)); // leaks auto traits, depends on `check` + 1u16 +} + +trait Indir: Send {} +impl Indir for u32 {} +fn indir() -> impl Indir { + is_send(check(false)); // leaks auto traits, depends on `check` + 1u32 +} + +fn check(b: bool) -> impl Sized { + if b { + // must not leak auto traits, as we otherwise get a query cycle. + is_send(direct()); + is_send(indir()); + } + 1u64 +} + +fn main() { + check(true); +} diff --git a/tests/ui/impl-trait/call_method_ambiguous.rs b/tests/ui/impl-trait/call_method_ambiguous.rs index 8fd6f727b73f..6bcafc8ce149 100644 --- a/tests/ui/impl-trait/call_method_ambiguous.rs +++ b/tests/ui/impl-trait/call_method_ambiguous.rs @@ -24,7 +24,7 @@ where fn foo(n: usize, m: &mut ()) -> impl Get + use<'_> { if n > 0 { let mut iter = foo(n - 1, m); - //[next]~^ type annotations needed + //[next]~^ ERROR type annotations needed assert_eq!(iter.get(), 1); } m diff --git a/tests/ui/impl-trait/call_method_on_inherent_impl.rs b/tests/ui/impl-trait/call_method_on_inherent_impl.rs index 17f7cad660db..0e333c3260a2 100644 --- a/tests/ui/impl-trait/call_method_on_inherent_impl.rs +++ b/tests/ui/impl-trait/call_method_on_inherent_impl.rs @@ -16,7 +16,7 @@ where fn my_foo() -> impl std::fmt::Debug { if false { let x = my_foo(); - //[next]~^ type annotations needed + //[next]~^ ERROR type annotations needed x.my_debug(); } () diff --git a/tests/ui/impl-trait/call_method_on_inherent_impl_ref.rs b/tests/ui/impl-trait/call_method_on_inherent_impl_ref.rs index abe60e5e45a3..4e4098b37f93 100644 --- a/tests/ui/impl-trait/call_method_on_inherent_impl_ref.rs +++ b/tests/ui/impl-trait/call_method_on_inherent_impl_ref.rs @@ -15,9 +15,9 @@ where fn my_foo() -> impl std::fmt::Debug { if false { let x = my_foo(); - //[next]~^ type annotations needed + //[next]~^ ERROR type annotations needed x.my_debug(); - //[current]~^ no method named `my_debug` found + //[current]~^ ERROR no method named `my_debug` found } () } @@ -25,7 +25,7 @@ fn my_foo() -> impl std::fmt::Debug { fn my_bar() -> impl std::fmt::Debug { if false { let x = &my_bar(); - //[next]~^ type annotations needed + //[next]~^ ERROR type annotations needed x.my_debug(); } () diff --git a/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.current.stderr b/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.current.stderr index c76415d8114b..341262ac85b3 100644 --- a/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.current.stderr +++ b/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.current.stderr @@ -4,7 +4,7 @@ error[E0407]: method `line_stream` is not a member of trait `X` LL | fn line_stream<'a, Repr>(&'a self) -> Self::LineStreamFut<'a, Repr> {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not a member of trait `X` -error[E0049]: type `LineStream` has 0 type parameters but its trait declaration has 1 type parameter +error[E0049]: associated type `LineStream` has 0 type parameters but its trait declaration has 1 type parameter --> $DIR/ice-unexpected-param-type-whensubstituting-in-region-112823.rs:25:21 | LL | type LineStream<'a, Repr> diff --git a/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.next.stderr b/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.next.stderr index 4d72490ff956..9632d2ce6249 100644 --- a/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.next.stderr +++ b/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.next.stderr @@ -4,7 +4,7 @@ error[E0407]: method `line_stream` is not a member of trait `X` LL | fn line_stream<'a, Repr>(&'a self) -> Self::LineStreamFut<'a, Repr> {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not a member of trait `X` -error[E0049]: type `LineStream` has 0 type parameters but its trait declaration has 1 type parameter +error[E0049]: associated type `LineStream` has 0 type parameters but its trait declaration has 1 type parameter --> $DIR/ice-unexpected-param-type-whensubstituting-in-region-112823.rs:25:21 | LL | type LineStream<'a, Repr> diff --git a/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.rs b/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.rs index a5a37dbb210f..0b507ed948ae 100644 --- a/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.rs +++ b/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.rs @@ -27,7 +27,7 @@ impl X for Y { //~| ERROR: unconstrained opaque type type LineStreamFut<'a, Repr> = impl Future>; fn line_stream<'a, Repr>(&'a self) -> Self::LineStreamFut<'a, Repr> {} - //~^ method `line_stream` is not a member of trait `X` + //~^ ERROR method `line_stream` is not a member of trait `X` //[current]~^^ ERROR `()` is not a future //[next]~^^^ ERROR type mismatch resolving `::LineStreamFut<'a, Repr> == ()` //[next]~| ERROR type mismatch resolving `::LineStreamFut<'a, Repr> normalizes-to _` diff --git a/tests/ui/impl-trait/impl-generic-mismatch.rs b/tests/ui/impl-trait/impl-generic-mismatch.rs index fb8bde0d0813..f05e01716c31 100644 --- a/tests/ui/impl-trait/impl-generic-mismatch.rs +++ b/tests/ui/impl-trait/impl-generic-mismatch.rs @@ -6,7 +6,7 @@ trait Foo { impl Foo for () { fn foo(&self, _: &U) { } - //~^ Error method `foo` has incompatible signature for trait + //~^ ERROR method `foo` has incompatible signature for trait } trait Bar { @@ -15,7 +15,7 @@ trait Bar { impl Bar for () { fn bar(&self, _: &impl Debug) { } - //~^ Error method `bar` has incompatible signature for trait + //~^ ERROR method `bar` has incompatible signature for trait } trait Baz { @@ -24,7 +24,7 @@ trait Baz { impl Baz for () { fn baz(&self, _: &impl Debug, _: &T) { } - //~^ Error method `baz` has incompatible signature for trait + //~^ ERROR method `baz` has incompatible signature for trait } // With non-local trait (#49841): @@ -35,7 +35,7 @@ struct X; impl Hash for X { fn hash(&self, hasher: &mut impl Hasher) {} - //~^ Error method `hash` has incompatible signature for trait + //~^ ERROR method `hash` has incompatible signature for trait } fn main() {} diff --git a/tests/ui/impl-trait/impl-trait-plus-priority.rs b/tests/ui/impl-trait/impl-trait-plus-priority.rs index 5575493a17d3..8f76d4126622 100644 --- a/tests/ui/impl-trait/impl-trait-plus-priority.rs +++ b/tests/ui/impl-trait/impl-trait-plus-priority.rs @@ -27,7 +27,7 @@ type A = fn() -> impl A + B; type A = fn() -> dyn A + B; //~^ ERROR ambiguous `+` in a type type A = fn() -> A + B; -//~^ ERROR expected a path on the left-hand side of `+`, not `fn() -> A` +//~^ ERROR expected a path on the left-hand side of `+` type A = Fn() -> impl A +; //~^ ERROR ambiguous `+` in a type @@ -44,6 +44,6 @@ type A = &impl A + B; type A = &dyn A + B; //~^ ERROR ambiguous `+` in a type type A = &A + B; -//~^ ERROR expected a path on the left-hand side of `+`, not `&A` +//~^ ERROR expected a path on the left-hand side of `+` fn main() {} diff --git a/tests/ui/impl-trait/impl-trait-plus-priority.stderr b/tests/ui/impl-trait/impl-trait-plus-priority.stderr index 03e7910095a9..161206579603 100644 --- a/tests/ui/impl-trait/impl-trait-plus-priority.stderr +++ b/tests/ui/impl-trait/impl-trait-plus-priority.stderr @@ -31,11 +31,13 @@ help: try adding parentheses LL | type A = fn() -> (dyn A + B); | + + -error[E0178]: expected a path on the left-hand side of `+`, not `fn() -> A` +error[E0178]: expected a path on the left-hand side of `+` --> $DIR/impl-trait-plus-priority.rs:29:10 | LL | type A = fn() -> A + B; - | ^^^^^^^^^^^^^ perhaps you forgot parentheses? + | ^^^^^^^^^---- + | | + | perhaps you forgot parentheses? error: ambiguous `+` in a type --> $DIR/impl-trait-plus-priority.rs:32:18 @@ -103,11 +105,11 @@ help: try adding parentheses LL | type A = &(dyn A + B); | + + -error[E0178]: expected a path on the left-hand side of `+`, not `&A` +error[E0178]: expected a path on the left-hand side of `+` --> $DIR/impl-trait-plus-priority.rs:46:10 | LL | type A = &A + B; - | ^^^^^^ + | ^^ | help: try adding parentheses | diff --git a/tests/ui/impl-trait/implicit-capture-late.rs b/tests/ui/impl-trait/implicit-capture-late.rs index 13cbcd66f8d8..57a00357c711 100644 --- a/tests/ui/impl-trait/implicit-capture-late.rs +++ b/tests/ui/impl-trait/implicit-capture-late.rs @@ -6,7 +6,7 @@ use std::ops::Deref; -fn foo(x: Vec) -> Box Deref> { //~ ['a: o] +fn foo(x: Vec) -> Box Deref> { //~ ERROR ['a: o] //~^ ERROR cannot capture higher-ranked lifetime Box::new(x) } diff --git a/tests/ui/impl-trait/in-trait/default-body-type-err.rs b/tests/ui/impl-trait/in-trait/default-body-type-err.rs index ac7a50a365ea..0cd59bf0feb2 100644 --- a/tests/ui/impl-trait/in-trait/default-body-type-err.rs +++ b/tests/ui/impl-trait/in-trait/default-body-type-err.rs @@ -2,7 +2,7 @@ use std::ops::Deref; pub trait Foo { fn lol(&self) -> impl Deref { - //~^ type mismatch resolving `<&i32 as Deref>::Target == String` + //~^ ERROR type mismatch resolving `<&i32 as Deref>::Target == String` &1i32 } } diff --git a/tests/ui/impl-trait/in-trait/doesnt-satisfy.stderr b/tests/ui/impl-trait/in-trait/doesnt-satisfy.stderr index fc3efb44ac76..a9dfac274d55 100644 --- a/tests/ui/impl-trait/in-trait/doesnt-satisfy.stderr +++ b/tests/ui/impl-trait/in-trait/doesnt-satisfy.stderr @@ -6,11 +6,11 @@ LL | fn bar() -> () {} | = help: the trait `std::fmt::Display` is not implemented for `()` = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead -note: required by a bound in `Foo::{synthetic#0}` +note: required by a bound in `Foo::{anon_assoc#0}` --> $DIR/doesnt-satisfy.rs:2:22 | LL | fn bar() -> impl std::fmt::Display; - | ^^^^^^^^^^^^^^^^^ required by this bound in `Foo::{synthetic#0}` + | ^^^^^^^^^^^^^^^^^ required by this bound in `Foo::{anon_assoc#0}` error: aborting due to 1 previous error diff --git a/tests/ui/impl-trait/in-trait/dont-probe-missing-item-name.rs b/tests/ui/impl-trait/in-trait/dont-probe-missing-item-name.rs new file mode 100644 index 000000000000..450f41e209df --- /dev/null +++ b/tests/ui/impl-trait/in-trait/dont-probe-missing-item-name.rs @@ -0,0 +1,12 @@ +// Regression test for . + +// Test that we don't try to get the (nonexistent) name of the RPITIT in `Trait::foo` +// when emitting an error for a missing associated item `Trait::Output`. + +trait Trait { + fn foo() -> impl Sized; + fn bar() -> Self::Output; + //~^ ERROR associated type `Output` not found for `Self` +} + +fn main() {} diff --git a/tests/ui/impl-trait/in-trait/dont-probe-missing-item-name.stderr b/tests/ui/impl-trait/in-trait/dont-probe-missing-item-name.stderr new file mode 100644 index 000000000000..74e15785af19 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/dont-probe-missing-item-name.stderr @@ -0,0 +1,9 @@ +error[E0220]: associated type `Output` not found for `Self` + --> $DIR/dont-probe-missing-item-name.rs:8:23 + | +LL | fn bar() -> Self::Output; + | ^^^^^^ associated type `Output` not found + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0220`. diff --git a/tests/ui/impl-trait/in-trait/dump.rs b/tests/ui/impl-trait/in-trait/dump.rs index 20b0e60702fa..da3cfd099b56 100644 --- a/tests/ui/impl-trait/in-trait/dump.rs +++ b/tests/ui/impl-trait/in-trait/dump.rs @@ -8,7 +8,7 @@ trait Foo { } fn hello<'s, T: Foo>(x: &'s T) -> impl Sized + use<'s, T> { -//~^ ERROR ::{synthetic#0}<'s/#1> +//~^ ERROR ::{anon_assoc#0}<'s/#1> x.hello() } diff --git a/tests/ui/impl-trait/in-trait/dump.stderr b/tests/ui/impl-trait/in-trait/dump.stderr index 958058403852..15b6f186ced5 100644 --- a/tests/ui/impl-trait/in-trait/dump.stderr +++ b/tests/ui/impl-trait/in-trait/dump.stderr @@ -1,4 +1,4 @@ -error: ::{synthetic#0}<'s/#1> +error: ::{anon_assoc#0}<'s/#1> --> $DIR/dump.rs:10:35 | LL | fn hello<'s, T: Foo>(x: &'s T) -> impl Sized + use<'s, T> { diff --git a/tests/ui/impl-trait/in-trait/method-compatability-via-leakage-cycle.current.stderr b/tests/ui/impl-trait/in-trait/method-compatability-via-leakage-cycle.current.stderr new file mode 100644 index 000000000000..bf598d627094 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/method-compatability-via-leakage-cycle.current.stderr @@ -0,0 +1,58 @@ +error[E0391]: cycle detected when computing type of `::{anon_assoc#0}` + --> $DIR/method-compatability-via-leakage-cycle.rs:21:24 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^ + | +note: ...which requires comparing an impl and trait method signature, inferring any hidden `impl Trait` types in the process... + --> $DIR/method-compatability-via-leakage-cycle.rs:21:24 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^ + = note: ...which requires evaluating trait selection obligation `::foo::{opaque#0}: core::marker::Send`... +note: ...which requires computing type of opaque `::foo::{opaque#0}`... + --> $DIR/method-compatability-via-leakage-cycle.rs:21:24 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^ +note: ...which requires borrow-checking `::foo`... + --> $DIR/method-compatability-via-leakage-cycle.rs:21:5 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires promoting constants in MIR for `::foo`... + --> $DIR/method-compatability-via-leakage-cycle.rs:21:5 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires checking if `::foo` contains FFI-unwind calls... + --> $DIR/method-compatability-via-leakage-cycle.rs:21:5 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires building MIR for `::foo`... + --> $DIR/method-compatability-via-leakage-cycle.rs:21:5 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires match-checking `::foo`... + --> $DIR/method-compatability-via-leakage-cycle.rs:21:5 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires type-checking `::foo`... + --> $DIR/method-compatability-via-leakage-cycle.rs:21:5 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: ...which again requires computing type of `::{anon_assoc#0}`, completing the cycle +note: cycle used when checking that `` is well-formed + --> $DIR/method-compatability-via-leakage-cycle.rs:17:1 + | +LL | impl Trait for u32 { + | ^^^^^^^^^^^^^^^^^^ + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/impl-trait/in-trait/method-compatability-via-leakage-cycle.next.stderr b/tests/ui/impl-trait/in-trait/method-compatability-via-leakage-cycle.next.stderr new file mode 100644 index 000000000000..6bec5bbc0632 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/method-compatability-via-leakage-cycle.next.stderr @@ -0,0 +1,122 @@ +error[E0391]: cycle detected when computing type of `::{anon_assoc#0}` + --> $DIR/method-compatability-via-leakage-cycle.rs:21:24 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^ + | +note: ...which requires comparing an impl and trait method signature, inferring any hidden `impl Trait` types in the process... + --> $DIR/method-compatability-via-leakage-cycle.rs:21:5 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires computing type of `::foo::{opaque#0}`... + --> $DIR/method-compatability-via-leakage-cycle.rs:21:24 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^ +note: ...which requires computing type of opaque `::foo::{opaque#0}`... + --> $DIR/method-compatability-via-leakage-cycle.rs:21:24 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^ +note: ...which requires borrow-checking `::foo`... + --> $DIR/method-compatability-via-leakage-cycle.rs:21:5 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires promoting constants in MIR for `::foo`... + --> $DIR/method-compatability-via-leakage-cycle.rs:21:5 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires checking if `::foo` contains FFI-unwind calls... + --> $DIR/method-compatability-via-leakage-cycle.rs:21:5 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires building MIR for `::foo`... + --> $DIR/method-compatability-via-leakage-cycle.rs:21:5 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires match-checking `::foo`... + --> $DIR/method-compatability-via-leakage-cycle.rs:21:5 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires type-checking `::foo`... + --> $DIR/method-compatability-via-leakage-cycle.rs:21:5 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: ...which again requires computing type of `::{anon_assoc#0}`, completing the cycle +note: cycle used when checking that `` is well-formed + --> $DIR/method-compatability-via-leakage-cycle.rs:17:1 + | +LL | impl Trait for u32 { + | ^^^^^^^^^^^^^^^^^^ + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information + +error[E0391]: cycle detected when computing type of `::{anon_assoc#0}` + --> $DIR/method-compatability-via-leakage-cycle.rs:21:24 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^ + | +note: ...which requires comparing an impl and trait method signature, inferring any hidden `impl Trait` types in the process... + --> $DIR/method-compatability-via-leakage-cycle.rs:21:5 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires computing type of `::foo::{opaque#0}`... + --> $DIR/method-compatability-via-leakage-cycle.rs:21:24 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^ +note: ...which requires computing type of opaque `::foo::{opaque#0}`... + --> $DIR/method-compatability-via-leakage-cycle.rs:21:24 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^ +note: ...which requires borrow-checking `::foo`... + --> $DIR/method-compatability-via-leakage-cycle.rs:21:5 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires promoting constants in MIR for `::foo`... + --> $DIR/method-compatability-via-leakage-cycle.rs:21:5 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires checking if `::foo` contains FFI-unwind calls... + --> $DIR/method-compatability-via-leakage-cycle.rs:21:5 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires building MIR for `::foo`... + --> $DIR/method-compatability-via-leakage-cycle.rs:21:5 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires match-checking `::foo`... + --> $DIR/method-compatability-via-leakage-cycle.rs:21:5 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires type-checking `::foo`... + --> $DIR/method-compatability-via-leakage-cycle.rs:21:5 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: ...which again requires computing type of `::{anon_assoc#0}`, completing the cycle +note: cycle used when checking that `` is well-formed + --> $DIR/method-compatability-via-leakage-cycle.rs:17:1 + | +LL | impl Trait for u32 { + | ^^^^^^^^^^^^^^^^^^ + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/impl-trait/in-trait/method-compatability-via-leakage-cycle.rs b/tests/ui/impl-trait/in-trait/method-compatability-via-leakage-cycle.rs new file mode 100644 index 000000000000..917820dc2b8b --- /dev/null +++ b/tests/ui/impl-trait/in-trait/method-compatability-via-leakage-cycle.rs @@ -0,0 +1,30 @@ +//@ revisions: current next +//@[next] compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) +//@ known-bug: #139788 + +// Recursively using the trait method inside of an impl in case checking +// method compatability relies on opaque type leakage currently causes a +// cycle error. + +trait Trait { + // desugars to + // type Assoc: Sized + Send; + // fn foo(b: bool) -> Self::Assoc; + fn foo(b: bool) -> impl Sized + Send; +} + +impl Trait for u32 { + // desugars to + // type Assoc = impl_rpit::; + // fn foo(b: bool) -> Self::Assoc { .. } + fn foo(b: bool) -> impl Sized { + if b { + u32::foo(false) + } else { + 1u32 + } + } +} + +fn main() {} diff --git a/tests/ui/impl-trait/in-trait/method-compatability-via-leakage.rs b/tests/ui/impl-trait/in-trait/method-compatability-via-leakage.rs new file mode 100644 index 000000000000..249ec0728c1a --- /dev/null +++ b/tests/ui/impl-trait/in-trait/method-compatability-via-leakage.rs @@ -0,0 +1,14 @@ +//@ check-pass +//@ revisions: current next +//@[next] compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) + +trait Trait { + fn foo() -> impl Sized + Send; +} + +impl Trait for u32 { + fn foo() -> impl Sized {} +} + +fn main() {} diff --git a/tests/ui/impl-trait/in-trait/refine-cycle.rs b/tests/ui/impl-trait/in-trait/refine-cycle.rs index 78d672a7ed60..d97f9821347e 100644 --- a/tests/ui/impl-trait/in-trait/refine-cycle.rs +++ b/tests/ui/impl-trait/in-trait/refine-cycle.rs @@ -1,4 +1,7 @@ //@ check-pass +//@ revisions: current next +//@[next] compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) // Make sure that refinement checking doesn't cause a cycle in `Instance::resolve` // which calls `compare_impl_item`. diff --git a/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.stderr b/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.stderr index 5cb80386b35f..6571ce2d5f05 100644 --- a/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.stderr +++ b/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.stderr @@ -14,11 +14,11 @@ LL | fn foo>(self) -> impl Foo { | ^^^^^^^^^^^^ the trait `Foo` is not implemented for `impl Foo` | = help: the trait `Foo` is implemented for `Bar` -note: required by a bound in `Foo::{synthetic#0}` +note: required by a bound in `Foo::{anon_assoc#0}` --> $DIR/return-dont-satisfy-bounds.rs:2:30 | LL | fn foo(self) -> impl Foo; - | ^^^^^^ required by this bound in `Foo::{synthetic#0}` + | ^^^^^^ required by this bound in `Foo::{anon_assoc#0}` error[E0277]: the trait bound `Bar: Foo` is not satisfied --> $DIR/return-dont-satisfy-bounds.rs:8:34 diff --git a/tests/ui/impl-trait/in-trait/rpitit-hidden-types-self-implied-wf-via-param.rs b/tests/ui/impl-trait/in-trait/rpitit-hidden-types-self-implied-wf-via-param.rs index 7a3a59d37c6a..65c4542e2359 100644 --- a/tests/ui/impl-trait/in-trait/rpitit-hidden-types-self-implied-wf-via-param.rs +++ b/tests/ui/impl-trait/in-trait/rpitit-hidden-types-self-implied-wf-via-param.rs @@ -6,7 +6,7 @@ impl Extend for () { fn extend<'a: 'a>(s: &'a str) -> (Option<&'static &'a ()>, &'static str) where 'a: 'static, - //~^ impl has stricter requirements than trait + //~^ ERROR impl has stricter requirements than trait { (None, s) } diff --git a/tests/ui/impl-trait/in-trait/span-bug-issue-121457.rs b/tests/ui/impl-trait/in-trait/span-bug-issue-121457.rs index ab21dae7dc50..7dc747bffba4 100644 --- a/tests/ui/impl-trait/in-trait/span-bug-issue-121457.rs +++ b/tests/ui/impl-trait/in-trait/span-bug-issue-121457.rs @@ -8,7 +8,7 @@ pub trait Iterable { impl<'a, I: 'a + Iterable> Iterable for &'a I { type Item = u32; - //~^ ERROR lifetime parameters or bounds on type `Item` do not match the trait declaration + //~^ ERROR lifetime parameters or bounds on associated type `Item` do not match the trait declaration fn iter(&self) -> impl for<'missing> Iterator> {} //~^ ERROR binding for associated type `Item` references lifetime `'missing` diff --git a/tests/ui/impl-trait/in-trait/span-bug-issue-121457.stderr b/tests/ui/impl-trait/in-trait/span-bug-issue-121457.stderr index d8a2eef94a18..eaa320455bbb 100644 --- a/tests/ui/impl-trait/in-trait/span-bug-issue-121457.stderr +++ b/tests/ui/impl-trait/in-trait/span-bug-issue-121457.stderr @@ -12,17 +12,17 @@ LL | fn iter(&self) -> impl for<'missing> Iterator $DIR/span-bug-issue-121457.rs:10:14 | LL | type Item<'a> - | ---- lifetimes in impl do not match this type in trait + | ---- lifetimes in impl do not match this associated type in trait LL | where LL | Self: 'a; | -- this bound might be missing in the impl ... LL | type Item = u32; - | ^ lifetimes do not match type in trait + | ^ lifetimes do not match associated type in trait error[E0277]: `()` is not an iterator --> $DIR/span-bug-issue-121457.rs:13:23 diff --git a/tests/ui/impl-trait/in-trait/variance.rs b/tests/ui/impl-trait/in-trait/variance.rs index c0f569c690ab..f0b8c05b2d71 100644 --- a/tests/ui/impl-trait/in-trait/variance.rs +++ b/tests/ui/impl-trait/in-trait/variance.rs @@ -4,22 +4,22 @@ trait Foo<'i> { fn implicit_capture_early<'a: 'a>() -> impl Sized {} - //~^ [Self: o, 'i: o, 'a: *, 'i: o, 'a: o] + //~^ ERROR [Self: o, 'i: o, 'a: *, 'i: o, 'a: o] fn explicit_capture_early<'a: 'a>() -> impl Sized + use<'i, 'a, Self> {} - //~^ [Self: o, 'i: o, 'a: *, 'i: o, 'a: o] + //~^ ERROR [Self: o, 'i: o, 'a: *, 'i: o, 'a: o] fn not_captured_early<'a: 'a>() -> impl Sized + use<'i, Self> {} - //~^ [Self: o, 'i: o, 'a: *, 'i: o] + //~^ ERROR [Self: o, 'i: o, 'a: *, 'i: o] fn implicit_capture_late<'a>(_: &'a ()) -> impl Sized {} - //~^ [Self: o, 'i: o, 'i: o, 'a: o] + //~^ ERROR [Self: o, 'i: o, 'i: o, 'a: o] fn explicit_capture_late<'a>(_: &'a ()) -> impl Sized + use<'i, 'a, Self> {} - //~^ [Self: o, 'i: o, 'i: o, 'a: o] + //~^ ERROR [Self: o, 'i: o, 'i: o, 'a: o] fn not_captured_late<'a>(_: &'a ()) -> impl Sized + use<'i, Self> {} - //~^ [Self: o, 'i: o, 'i: o] + //~^ ERROR [Self: o, 'i: o, 'i: o] } fn main() {} diff --git a/tests/ui/impl-trait/issues/issue-54600.rs b/tests/ui/impl-trait/issues/issue-54600.rs index 62bfd7cd9688..b349c47328bb 100644 --- a/tests/ui/impl-trait/issues/issue-54600.rs +++ b/tests/ui/impl-trait/issues/issue-54600.rs @@ -2,6 +2,6 @@ use std::fmt::Debug; fn main() { let x: Option = Some(44_u32); - //~^ `impl Trait` is not allowed in the type of variable bindings + //~^ ERROR `impl Trait` is not allowed in the type of variable bindings println!("{:?}", x); } diff --git a/tests/ui/impl-trait/issues/issue-54840.rs b/tests/ui/impl-trait/issues/issue-54840.rs index 65257d2f7f1d..853728630351 100644 --- a/tests/ui/impl-trait/issues/issue-54840.rs +++ b/tests/ui/impl-trait/issues/issue-54840.rs @@ -3,5 +3,5 @@ use std::ops::Add; fn main() { let i: i32 = 0; let j: &impl Add = &i; - //~^ `impl Trait` is not allowed in the type of variable bindings + //~^ ERROR `impl Trait` is not allowed in the type of variable bindings } diff --git a/tests/ui/impl-trait/issues/issue-58504.rs b/tests/ui/impl-trait/issues/issue-58504.rs index 856e1297e58b..57119671680e 100644 --- a/tests/ui/impl-trait/issues/issue-58504.rs +++ b/tests/ui/impl-trait/issues/issue-58504.rs @@ -8,5 +8,5 @@ fn mk_gen() -> impl Coroutine { fn main() { let gens: [impl Coroutine;2] = [ mk_gen(), mk_gen() ]; - //~^ `impl Trait` is not allowed in the type of variable bindings + //~^ ERROR `impl Trait` is not allowed in the type of variable bindings } diff --git a/tests/ui/impl-trait/issues/issue-58956.rs b/tests/ui/impl-trait/issues/issue-58956.rs index a59de2379d8f..8fb69aca9bce 100644 --- a/tests/ui/impl-trait/issues/issue-58956.rs +++ b/tests/ui/impl-trait/issues/issue-58956.rs @@ -5,9 +5,9 @@ impl Lam for B {} pub struct Wrap(T); const _A: impl Lam = { - //~^ `impl Trait` is not allowed in const types + //~^ ERROR `impl Trait` is not allowed in const types let x: Wrap = Wrap(B); - //~^ `impl Trait` is not allowed in the type of variable bindings + //~^ ERROR `impl Trait` is not allowed in the type of variable bindings x.0 }; diff --git a/tests/ui/impl-trait/issues/issue-70971.rs b/tests/ui/impl-trait/issues/issue-70971.rs index 2f2c2e8f441a..e7b51e0e6db4 100644 --- a/tests/ui/impl-trait/issues/issue-70971.rs +++ b/tests/ui/impl-trait/issues/issue-70971.rs @@ -1,4 +1,4 @@ fn main() { let x : (impl Copy,) = (true,); - //~^ `impl Trait` is not allowed in the type of variable bindings + //~^ ERROR `impl Trait` is not allowed in the type of variable bindings } diff --git a/tests/ui/impl-trait/issues/issue-79099.rs b/tests/ui/impl-trait/issues/issue-79099.rs index 757e61fb631e..c2bad59045b2 100644 --- a/tests/ui/impl-trait/issues/issue-79099.rs +++ b/tests/ui/impl-trait/issues/issue-79099.rs @@ -1,8 +1,8 @@ struct Bug { V1: [(); { let f: impl core::future::Future = async { 1 }; - //~^ `impl Trait` is not allowed in the type of variable bindings - //~| expected identifier + //~^ ERROR `impl Trait` is not allowed in the type of variable bindings + //~| ERROR expected identifier 1 }], } diff --git a/tests/ui/impl-trait/issues/issue-84919.rs b/tests/ui/impl-trait/issues/issue-84919.rs index 0f911ba23ae2..1012024f21e1 100644 --- a/tests/ui/impl-trait/issues/issue-84919.rs +++ b/tests/ui/impl-trait/issues/issue-84919.rs @@ -3,7 +3,7 @@ impl Trait for () {} fn foo<'a: 'a>() { let _x: impl Trait = (); - //~^ `impl Trait` is not allowed in the type of variable bindings + //~^ ERROR `impl Trait` is not allowed in the type of variable bindings } fn main() {} diff --git a/tests/ui/impl-trait/issues/issue-86642.rs b/tests/ui/impl-trait/issues/issue-86642.rs index 74be8779d445..2feb045abee2 100644 --- a/tests/ui/impl-trait/issues/issue-86642.rs +++ b/tests/ui/impl-trait/issues/issue-86642.rs @@ -1,5 +1,5 @@ static x: impl Fn(&str) -> Result<&str, ()> = move |source| { - //~^ `impl Trait` is not allowed in static types + //~^ ERROR `impl Trait` is not allowed in static types let res = (move |source| Ok(source))(source); let res = res.or((move |source| Ok(source))(source)); res diff --git a/tests/ui/impl-trait/issues/issue-87295.rs b/tests/ui/impl-trait/issues/issue-87295.rs index a765e14884b0..d8d1b462ca3b 100644 --- a/tests/ui/impl-trait/issues/issue-87295.rs +++ b/tests/ui/impl-trait/issues/issue-87295.rs @@ -14,5 +14,5 @@ impl Struct { fn main() { let _do_not_waste: Struct> = Struct::new(()); - //~^ `impl Trait` is not allowed in the type of variable bindings + //~^ ERROR `impl Trait` is not allowed in the type of variable bindings } diff --git a/tests/ui/impl-trait/issues/issue-99348-impl-compatibility.rs b/tests/ui/impl-trait/issues/issue-99348-impl-compatibility.rs index e19230b44b40..4937794b040c 100644 --- a/tests/ui/impl-trait/issues/issue-99348-impl-compatibility.rs +++ b/tests/ui/impl-trait/issues/issue-99348-impl-compatibility.rs @@ -6,7 +6,7 @@ type Tait = impl Sized; impl Foo for Concrete { type Item = Concrete; - //~^ type mismatch resolving + //~^ ERROR type mismatch resolving } impl Bar for Concrete { diff --git a/tests/ui/impl-trait/method-resolution4.rs b/tests/ui/impl-trait/method-resolution4.rs index 5c8813ed7922..90e7850cad51 100644 --- a/tests/ui/impl-trait/method-resolution4.rs +++ b/tests/ui/impl-trait/method-resolution4.rs @@ -11,7 +11,7 @@ fn foo(b: bool) -> impl Iterator { if b { foo(false).next().unwrap(); - //[next]~^ type annotations needed + //[next]~^ ERROR type annotations needed } std::iter::empty() } diff --git a/tests/ui/impl-trait/nested_impl_trait.rs b/tests/ui/impl-trait/nested_impl_trait.rs index 760102794c34..3e985b5dcca9 100644 --- a/tests/ui/impl-trait/nested_impl_trait.rs +++ b/tests/ui/impl-trait/nested_impl_trait.rs @@ -9,7 +9,7 @@ fn bad_in_ret_position(x: impl Into) -> impl Into { x } fn bad_in_fn_syntax(x: fn() -> impl Into) {} //~^ ERROR nested `impl Trait` is not allowed -//~| `impl Trait` is not allowed in `fn` pointer +//~| ERROR `impl Trait` is not allowed in `fn` pointer fn bad_in_arg_position(_: impl Into) { } //~^ ERROR nested `impl Trait` is not allowed diff --git a/tests/ui/impl-trait/recursive-in-exhaustiveness.current.stderr b/tests/ui/impl-trait/recursive-in-exhaustiveness.current.stderr new file mode 100644 index 000000000000..42dbc7c91607 --- /dev/null +++ b/tests/ui/impl-trait/recursive-in-exhaustiveness.current.stderr @@ -0,0 +1,56 @@ +warning: function cannot return without recursing + --> $DIR/recursive-in-exhaustiveness.rs:17:1 + | +LL | fn build(x: T) -> impl Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing +LL | +LL | let (x,) = (build(x),); + | -------- recursive call site + | + = help: a `loop` may express intention better if this is on purpose + = note: `#[warn(unconditional_recursion)]` on by default + +warning: function cannot return without recursing + --> $DIR/recursive-in-exhaustiveness.rs:27:1 + | +LL | fn build2(x: T) -> impl Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing +... +LL | let (x,) = (build2(x),); + | --------- recursive call site + | + = help: a `loop` may express intention better if this is on purpose + +error[E0720]: cannot resolve opaque type + --> $DIR/recursive-in-exhaustiveness.rs:27:23 + | +LL | fn build2(x: T) -> impl Sized { + | ^^^^^^^^^^ recursive opaque type +... +LL | (build2(x),) + | ------------ returning here with type `(impl Sized,)` + +warning: function cannot return without recursing + --> $DIR/recursive-in-exhaustiveness.rs:40:1 + | +LL | fn build3(x: T) -> impl Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing +LL | +LL | let (x,) = (build3((x,)),); + | ------------ recursive call site + | + = help: a `loop` may express intention better if this is on purpose + +error[E0792]: expected generic type parameter, found `(T,)` + --> $DIR/recursive-in-exhaustiveness.rs:49:5 + | +LL | fn build3(x: T) -> impl Sized { + | - this generic parameter must be used with a generic type parameter +... +LL | build3(x) + | ^^^^^^^^^ + +error: aborting due to 2 previous errors; 3 warnings emitted + +Some errors have detailed explanations: E0720, E0792. +For more information about an error, try `rustc --explain E0720`. diff --git a/tests/ui/impl-trait/recursive-in-exhaustiveness.next.stderr b/tests/ui/impl-trait/recursive-in-exhaustiveness.next.stderr new file mode 100644 index 000000000000..4c3d5aa8fb8f --- /dev/null +++ b/tests/ui/impl-trait/recursive-in-exhaustiveness.next.stderr @@ -0,0 +1,80 @@ +error[E0284]: type annotations needed: cannot satisfy `impl Sized == _` + --> $DIR/recursive-in-exhaustiveness.rs:19:17 + | +LL | let (x,) = (build(x),); + | ^^^^^^^^ cannot satisfy `impl Sized == _` + +error[E0271]: type mismatch resolving `build2<(_,)>::{opaque#0} normalizes-to _` + --> $DIR/recursive-in-exhaustiveness.rs:31:6 + | +LL | (build2(x),) + | ^^^^^^^^^ types differ + +error[E0271]: type mismatch resolving `build2<(_,)>::{opaque#0} normalizes-to _` + --> $DIR/recursive-in-exhaustiveness.rs:31:5 + | +LL | (build2(x),) + | ^^^^^^^^^^^^ types differ + +error[E0277]: the size for values of type `(impl Sized,)` cannot be known at compilation time + --> $DIR/recursive-in-exhaustiveness.rs:31:5 + | +LL | (build2(x),) + | ^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `(impl Sized,)` + = note: tuples must have a statically known size to be initialized + +error[E0271]: type mismatch resolving `build3<(T,)>::{opaque#0} normalizes-to _` + --> $DIR/recursive-in-exhaustiveness.rs:42:17 + | +LL | let (x,) = (build3((x,)),); + | ^^^^^^^^^^^^ types differ + +error[E0277]: the size for values of type `(impl Sized,)` cannot be known at compilation time + --> $DIR/recursive-in-exhaustiveness.rs:42:16 + | +LL | let (x,) = (build3((x,)),); + | ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `(impl Sized,)` + = note: tuples must have a statically known size to be initialized + +error[E0308]: mismatched types + --> $DIR/recursive-in-exhaustiveness.rs:42:16 + | +LL | fn build3(x: T) -> impl Sized { + | ---------- the found opaque type +LL | +LL | let (x,) = (build3((x,)),); + | ^^^^^^^^^^^^^^^ types differ + | + = note: expected type `_` + found tuple `(impl Sized,)` + +error[E0271]: type mismatch resolving `build3<(T,)>::{opaque#0} normalizes-to _` + --> $DIR/recursive-in-exhaustiveness.rs:42:17 + | +LL | let (x,) = (build3((x,)),); + | ^^^^^^^^^^^^ types differ + | + = note: the return type of a function must have a statically known size + +error[E0271]: type mismatch resolving `build3<(T,)>::{opaque#0} normalizes-to _` + --> $DIR/recursive-in-exhaustiveness.rs:42:16 + | +LL | let (x,) = (build3((x,)),); + | ^^^^^^^^^^^^^^^ types differ + +error[E0271]: type mismatch resolving `build3<(T,)>::{opaque#0} normalizes-to _` + --> $DIR/recursive-in-exhaustiveness.rs:42:17 + | +LL | let (x,) = (build3((x,)),); + | ^^^^^^^^^^^^ types differ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 10 previous errors + +Some errors have detailed explanations: E0271, E0277, E0284, E0308. +For more information about an error, try `rustc --explain E0271`. diff --git a/tests/ui/impl-trait/recursive-in-exhaustiveness.rs b/tests/ui/impl-trait/recursive-in-exhaustiveness.rs new file mode 100644 index 000000000000..58944533686c --- /dev/null +++ b/tests/ui/impl-trait/recursive-in-exhaustiveness.rs @@ -0,0 +1,53 @@ +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver + +// Test several spicy non-trivial recursive opaque definitions inferred from HIR typeck +// don't cause stack overflows in exhaustiveness code, which currently reveals opaques +// manually in a way that is not overflow aware. +// +// These should eventually be outright rejected, but today (some) non-trivial recursive +// opaque definitions are accepted, and changing that requires an FCP, so for now just +// make sure we don't stack overflow :^) + +// Opaque = Opaque> +// +// We unfortunately accept this today, and due to how opaque type relating is implemented +// in the NLL type relation, this defines `Opaque = T`. +fn build(x: T) -> impl Sized { + //[current]~^ WARN function cannot return without recursing + let (x,) = (build(x),); + //[next]~^ ERROR type annotations needed + build(x) +} + +// Opaque = (Opaque,) +// +// Not allowed today. Detected as recursive. +fn build2(x: T) -> impl Sized { + //[current]~^ ERROR cannot resolve opaque type + //[current]~| WARN function cannot return without recursing + let (x,) = (build2(x),); + (build2(x),) + //[next]~^ ERROR type mismatch resolving + //[next]~| ERROR type mismatch resolving + //[next]~| ERROR the size for values of type +} + +// Opaque = Opaque<(T,)> +// +// Not allowed today. Detected as not defining. +fn build3(x: T) -> impl Sized { + //[current]~^ WARN function cannot return without recursing + let (x,) = (build3((x,)),); + //[next]~^ ERROR type mismatch resolving + //[next]~| ERROR type mismatch resolving + //[next]~| ERROR type mismatch resolving + //[next]~| ERROR type mismatch resolving + //[next]~| ERROR the size for values of type + //[next]~| ERROR mismatched types + build3(x) + //[current]~^ ERROR expected generic type parameter, found `(T,)` +} + +fn main() {} diff --git a/tests/ui/impl-trait/variance.rs b/tests/ui/impl-trait/variance.rs index bde3a886a4d3..e73e0c623aa4 100644 --- a/tests/ui/impl-trait/variance.rs +++ b/tests/ui/impl-trait/variance.rs @@ -9,15 +9,15 @@ trait Captures<'a> {} impl Captures<'_> for T {} fn not_captured_early<'a: 'a>() -> impl Sized {} -//[old]~^ ['a: *] -//[e2024]~^^ ['a: *, 'a: o] +//[old]~^ ERROR ['a: *] +//[e2024]~^^ ERROR ['a: *, 'a: o] -fn captured_early<'a: 'a>() -> impl Sized + Captures<'a> {} //~ ['a: *, 'a: o] +fn captured_early<'a: 'a>() -> impl Sized + Captures<'a> {} //~ ERROR ['a: *, 'a: o] fn not_captured_late<'a>(_: &'a ()) -> impl Sized {} -//[old]~^ [] -//[e2024]~^^ ['a: o] +//[old]~^ ERROR [] +//[e2024]~^^ ERROR ['a: o] -fn captured_late<'a>(_: &'a ()) -> impl Sized + Captures<'a> {} //~ ['a: o] +fn captured_late<'a>(_: &'a ()) -> impl Sized + Captures<'a> {} //~ ERROR ['a: o] fn main() {} diff --git a/tests/ui/implied-bounds/implied-bounds-on-trait-hierarchy-1.rs b/tests/ui/implied-bounds/implied-bounds-on-trait-hierarchy-1.rs index b532a110a1c7..83803646a2dc 100644 --- a/tests/ui/implied-bounds/implied-bounds-on-trait-hierarchy-1.rs +++ b/tests/ui/implied-bounds/implied-bounds-on-trait-hierarchy-1.rs @@ -32,7 +32,7 @@ fn main() { { let x = "Hello World".to_string(); subs_to_soup((x.as_str(), &mut d)); - //~^ does not live long enough + //~^ ERROR does not live long enough } println!("{}", d); } diff --git a/tests/ui/implied-bounds/issue-100690.stderr b/tests/ui/implied-bounds/issue-100690.stderr index 4964dccd551d..d00895d8fc9c 100644 --- a/tests/ui/implied-bounds/issue-100690.stderr +++ b/tests/ui/implied-bounds/issue-100690.stderr @@ -6,8 +6,8 @@ LL | real_dispatch(f) | | | required by a bound introduced by this call | - = note: expected a closure with arguments `(&mut UIView<'a, _>,)` - found a closure with arguments `(&mut UIView<'_, _>,)` + = note: expected a closure with signature `for<'a, 'b> fn(&'a mut UIView<'b, _>)` + found a closure with signature `fn(&mut UIView<'a, _>)` note: required by a bound in `real_dispatch` --> $DIR/issue-100690.rs:8:8 | diff --git a/tests/ui/implied-bounds/overflow.rs b/tests/ui/implied-bounds/overflow.rs new file mode 100644 index 000000000000..7c36998dd4d3 --- /dev/null +++ b/tests/ui/implied-bounds/overflow.rs @@ -0,0 +1,11 @@ +trait Tailed<'a>: 'a { + type Tail: Tailed<'a>; +} + +struct List<'a, T: Tailed<'a>> { + //~^ ERROR overflow computing implied lifetime bounds for `List` + next: Box>, + node: &'a T, +} + +fn main() {} diff --git a/tests/ui/implied-bounds/overflow.stderr b/tests/ui/implied-bounds/overflow.stderr new file mode 100644 index 000000000000..2e5a9ab141cf --- /dev/null +++ b/tests/ui/implied-bounds/overflow.stderr @@ -0,0 +1,8 @@ +error: overflow computing implied lifetime bounds for `List` + --> $DIR/overflow.rs:5:1 + | +LL | struct List<'a, T: Tailed<'a>> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/implied-bounds/sod_service_chain.rs b/tests/ui/implied-bounds/sod_service_chain.rs index 032483e1be48..73dce2fce249 100644 --- a/tests/ui/implied-bounds/sod_service_chain.rs +++ b/tests/ui/implied-bounds/sod_service_chain.rs @@ -27,17 +27,17 @@ pub struct ServiceChainBuilder> { } impl> ServiceChainBuilder { pub fn next>( - //~^ the associated type + //~^ ERROR the associated type + //~| ERROR the associated type + //~| ERROR the associated type //~| the associated type //~| the associated type //~| the associated type - //~| the associated type - //~| the associated type - //~| may not live long enough + //~| ERROR may not live long enough self, ) -> ServiceChainBuilder, NS> { - //~^ the associated type - //~| the associated type + //~^ ERROR the associated type + //~| ERROR the associated type //~| the associated type //~| the associated type panic!(); diff --git a/tests/ui/imports/import-from-missing.rs b/tests/ui/imports/import-from-missing.rs index 8eae700208f9..1dcc3a901337 100644 --- a/tests/ui/imports/import-from-missing.rs +++ b/tests/ui/imports/import-from-missing.rs @@ -1,5 +1,5 @@ use spam::{ham, eggs}; //~ ERROR unresolved import `spam::eggs` [E0432] - //~^ no `eggs` in `spam` + //~^ NOTE no `eggs` in `spam` mod spam { pub fn ham() { } diff --git a/tests/ui/imports/import2.rs b/tests/ui/imports/import2.rs index 036d6bc07e28..731ccb6f41c2 100644 --- a/tests/ui/imports/import2.rs +++ b/tests/ui/imports/import2.rs @@ -1,5 +1,5 @@ use baz::zed::bar; //~ ERROR unresolved import `baz::zed` [E0432] - //~^ could not find `zed` in `baz` + //~^ NOTE could not find `zed` in `baz` mod baz {} mod zed { diff --git a/tests/ui/imports/issue-13404.rs b/tests/ui/imports/issue-13404.rs index c5af827d50c4..b6e5804abac4 100644 --- a/tests/ui/imports/issue-13404.rs +++ b/tests/ui/imports/issue-13404.rs @@ -1,6 +1,6 @@ use a::f; use b::f; //~ ERROR: unresolved import `b::f` [E0432] - //~^ no `f` in `b` + //~^ NOTE no `f` in `b` mod a { pub fn f() {} } mod b { } diff --git a/tests/ui/imports/issue-2937.rs b/tests/ui/imports/issue-2937.rs index 335df5c07e25..7ca6ffb479e0 100644 --- a/tests/ui/imports/issue-2937.rs +++ b/tests/ui/imports/issue-2937.rs @@ -1,5 +1,5 @@ use m::f as x; //~ ERROR unresolved import `m::f` [E0432] - //~^ no `f` in `m` + //~^ NOTE no `f` in `m` mod m {} diff --git a/tests/ui/imports/issue-32833.rs b/tests/ui/imports/issue-32833.rs index 379eedde7263..8f82eb68c1ff 100644 --- a/tests/ui/imports/issue-32833.rs +++ b/tests/ui/imports/issue-32833.rs @@ -1,5 +1,5 @@ use bar::Foo; //~ ERROR unresolved import `bar::Foo` [E0432] - //~^ no `Foo` in `bar` + //~^ NOTE no `Foo` in `bar` mod bar { use Foo; } diff --git a/tests/ui/imports/issue-8208.rs b/tests/ui/imports/issue-8208.rs index 1c566938f9d0..997d4d227b3d 100644 --- a/tests/ui/imports/issue-8208.rs +++ b/tests/ui/imports/issue-8208.rs @@ -1,14 +1,14 @@ use self::*; //~ ERROR: unresolved import `self::*` [E0432] - //~^ cannot glob-import a module into itself + //~^ NOTE cannot glob-import a module into itself mod foo { use foo::*; //~ ERROR: unresolved import `foo::*` [E0432] - //~^ cannot glob-import a module into itself + //~^ NOTE cannot glob-import a module into itself mod bar { use super::bar::*; //~^ ERROR: unresolved import `super::bar::*` [E0432] - //~| cannot glob-import a module into itself + //~| NOTE cannot glob-import a module into itself } } diff --git a/tests/ui/imports/redundant-import-extern-prelude.rs b/tests/ui/imports/redundant-import-extern-prelude.rs index 0064eaa93188..b573b8fc6109 100644 --- a/tests/ui/imports/redundant-import-extern-prelude.rs +++ b/tests/ui/imports/redundant-import-extern-prelude.rs @@ -5,7 +5,8 @@ // See also the discussion in . -//@ compile-flags: --extern aux_issue_121915 --edition 2018 +//@ compile-flags: --extern aux_issue_121915 +//@ edition: 2018 //@ aux-build: aux-issue-121915.rs #[deny(redundant_imports)] diff --git a/tests/ui/imports/redundant-import-extern-prelude.stderr b/tests/ui/imports/redundant-import-extern-prelude.stderr index 6d2518c1284b..06cce7e17256 100644 --- a/tests/ui/imports/redundant-import-extern-prelude.stderr +++ b/tests/ui/imports/redundant-import-extern-prelude.stderr @@ -1,11 +1,11 @@ error: the item `aux_issue_121915` is imported redundantly - --> $DIR/redundant-import-extern-prelude.rs:14:9 + --> $DIR/redundant-import-extern-prelude.rs:15:9 | LL | use aux_issue_121915; | ^^^^^^^^^^^^^^^^ the item `aux_issue_121915` is already defined by the extern prelude | note: the lint level is defined here - --> $DIR/redundant-import-extern-prelude.rs:11:8 + --> $DIR/redundant-import-extern-prelude.rs:12:8 | LL | #[deny(redundant_imports)] | ^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/imports/redundant-import-issue-121915-2015.rs b/tests/ui/imports/redundant-import-issue-121915-2015.rs index dc499bc40b61..7108776757e9 100644 --- a/tests/ui/imports/redundant-import-issue-121915-2015.rs +++ b/tests/ui/imports/redundant-import-issue-121915-2015.rs @@ -1,4 +1,5 @@ -//@ compile-flags: --extern aux_issue_121915 --edition 2015 +//@ compile-flags: --extern aux_issue_121915 +//@ edition: 2015 //@ aux-build: aux-issue-121915.rs extern crate aux_issue_121915; diff --git a/tests/ui/imports/redundant-import-issue-121915-2015.stderr b/tests/ui/imports/redundant-import-issue-121915-2015.stderr index f4e9f604896a..367a4f1cd15a 100644 --- a/tests/ui/imports/redundant-import-issue-121915-2015.stderr +++ b/tests/ui/imports/redundant-import-issue-121915-2015.stderr @@ -1,5 +1,5 @@ error: the item `aux_issue_121915` is imported redundantly - --> $DIR/redundant-import-issue-121915-2015.rs:8:9 + --> $DIR/redundant-import-issue-121915-2015.rs:9:9 | LL | extern crate aux_issue_121915; | ------------------------------ the item `aux_issue_121915` is already imported here @@ -8,7 +8,7 @@ LL | use aux_issue_121915; | ^^^^^^^^^^^^^^^^ | note: the lint level is defined here - --> $DIR/redundant-import-issue-121915-2015.rs:6:8 + --> $DIR/redundant-import-issue-121915-2015.rs:7:8 | LL | #[deny(redundant_imports)] | ^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/imports/suggest-remove-issue-121315.rs b/tests/ui/imports/suggest-remove-issue-121315.rs index ee3ceb6e3a38..3c036b843fd4 100644 --- a/tests/ui/imports/suggest-remove-issue-121315.rs +++ b/tests/ui/imports/suggest-remove-issue-121315.rs @@ -1,4 +1,4 @@ -//@ compile-flags: --edition 2021 +//@ edition: 2021 #![deny(unused_imports, redundant_imports)] #![allow(dead_code)] diff --git a/tests/ui/inline-const/in-pat-recovery.rs b/tests/ui/inline-const/in-pat-recovery.rs index 0d912af09811..e9e60116ff4c 100644 --- a/tests/ui/inline-const/in-pat-recovery.rs +++ b/tests/ui/inline-const/in-pat-recovery.rs @@ -4,7 +4,7 @@ fn main() { match 1 { const { 1 + 7 } => {} - //~^ `inline_const_pat` has been removed + //~^ ERROR `inline_const_pat` has been removed 2 => {} _ => {} } diff --git a/tests/ui/inline-const/using-late-bound-from-closure.rs b/tests/ui/inline-const/using-late-bound-from-closure.rs index 2b12b2e26a22..cb3dfd957397 100644 --- a/tests/ui/inline-const/using-late-bound-from-closure.rs +++ b/tests/ui/inline-const/using-late-bound-from-closure.rs @@ -7,7 +7,7 @@ fn foo() { const { let awd = (); let _: &'a () = &awd; - //~^ `awd` does not live long enough + //~^ ERROR `awd` does not live long enough }; b }; diff --git a/tests/ui/inner-attrs-on-impl.rs b/tests/ui/inner-attrs-on-impl.rs index 75f406232e20..1dce1cdd261a 100644 --- a/tests/ui/inner-attrs-on-impl.rs +++ b/tests/ui/inner-attrs-on-impl.rs @@ -3,7 +3,7 @@ struct Foo; impl Foo { - #![cfg(FALSE)] + #![cfg(false)] fn method(&self) -> bool { false } } @@ -12,7 +12,7 @@ impl Foo { #![cfg(not(FALSE))] // check that we don't eat attributes too eagerly. - #[cfg(FALSE)] + #[cfg(false)] fn method(&self) -> bool { false } fn method(&self) -> bool { true } diff --git a/tests/ui/intrinsics/always-extern.rs b/tests/ui/intrinsics/always-extern.rs deleted file mode 100644 index 0afd8353455f..000000000000 --- a/tests/ui/intrinsics/always-extern.rs +++ /dev/null @@ -1,17 +0,0 @@ -#![feature(intrinsics)] - -trait Foo { - extern "rust-intrinsic" fn foo(&self); //~ ERROR intrinsic must -} - -impl Foo for () { - extern "rust-intrinsic" fn foo(&self) { //~ ERROR intrinsic must - } -} - -extern "rust-intrinsic" fn hello() {//~ ERROR intrinsic must - //~^ ERROR unrecognized intrinsic function: `hello` -} - -fn main() { -} diff --git a/tests/ui/intrinsics/always-extern.stderr b/tests/ui/intrinsics/always-extern.stderr deleted file mode 100644 index 44b889c6faac..000000000000 --- a/tests/ui/intrinsics/always-extern.stderr +++ /dev/null @@ -1,34 +0,0 @@ -error: intrinsic must be in `extern "rust-intrinsic" { ... }` block - --> $DIR/always-extern.rs:4:32 - | -LL | extern "rust-intrinsic" fn foo(&self); - | ^^^ - -error[E0093]: unrecognized intrinsic function: `hello` - --> $DIR/always-extern.rs:12:28 - | -LL | extern "rust-intrinsic" fn hello() { - | ^^^^^ unrecognized intrinsic - | - = help: if you're adding an intrinsic, be sure to update `check_intrinsic_type` - -error: intrinsic must be in `extern "rust-intrinsic" { ... }` block - --> $DIR/always-extern.rs:8:43 - | -LL | extern "rust-intrinsic" fn foo(&self) { - | ___________________________________________^ -LL | | } - | |_____^ - -error: intrinsic must be in `extern "rust-intrinsic" { ... }` block - --> $DIR/always-extern.rs:12:36 - | -LL | extern "rust-intrinsic" fn hello() { - | ____________________________________^ -LL | | -LL | | } - | |_^ - -error: aborting due to 4 previous errors - -For more information about this error, try `rustc --explain E0093`. diff --git a/tests/ui/intrinsics/auxiliary/cci_intrinsic.rs b/tests/ui/intrinsics/auxiliary/cci_intrinsic.rs index f3b9d569ce3b..1014ac6f5609 100644 --- a/tests/ui/intrinsics/auxiliary/cci_intrinsic.rs +++ b/tests/ui/intrinsics/auxiliary/cci_intrinsic.rs @@ -1,14 +1,11 @@ #![feature(intrinsics)] pub mod rusti { - extern "rust-intrinsic" { - pub fn atomic_xchg_seqcst(dst: *mut T, src: T) -> T; - } + #[rustc_intrinsic] + pub unsafe fn atomic_xchg_seqcst(dst: *mut T, src: T) -> T; } #[inline(always)] pub fn atomic_xchg_seqcst(dst: *mut isize, src: isize) -> isize { - unsafe { - rusti::atomic_xchg_seqcst(dst, src) - } + unsafe { rusti::atomic_xchg_seqcst(dst, src) } } diff --git a/tests/ui/intrinsics/incorrect-read_via_copy-defn.rs b/tests/ui/intrinsics/incorrect-read_via_copy-defn.rs index 5520430e140b..e9f9270de87f 100644 --- a/tests/ui/intrinsics/incorrect-read_via_copy-defn.rs +++ b/tests/ui/intrinsics/incorrect-read_via_copy-defn.rs @@ -1,7 +1,8 @@ fn main() { read_via_copy(); + //~^ ERROR call to unsafe function `read_via_copy` is unsafe and requires unsafe function or block } -extern "rust-intrinsic" fn read_via_copy() {} -//~^ ERROR "rust-intrinsic" ABI is an implementation detail -//~| ERROR intrinsic must be in `extern "rust-intrinsic" { ... }` block +#[rustc_intrinsic] +//~^ ERROR the `#[rustc_intrinsic]` attribute is used to declare intrinsics as function items +unsafe fn read_via_copy() {} diff --git a/tests/ui/intrinsics/incorrect-read_via_copy-defn.stderr b/tests/ui/intrinsics/incorrect-read_via_copy-defn.stderr index c6682693f740..6711c77a11eb 100644 --- a/tests/ui/intrinsics/incorrect-read_via_copy-defn.stderr +++ b/tests/ui/intrinsics/incorrect-read_via_copy-defn.stderr @@ -1,18 +1,21 @@ -error[E0658]: the extern "rust-intrinsic" ABI is an implementation detail and perma-unstable - --> $DIR/incorrect-read_via_copy-defn.rs:5:8 +error[E0658]: the `#[rustc_intrinsic]` attribute is used to declare intrinsics as function items + --> $DIR/incorrect-read_via_copy-defn.rs:6:1 | -LL | extern "rust-intrinsic" fn read_via_copy() {} - | ^^^^^^^^^^^^^^^^ +LL | #[rustc_intrinsic] + | ^^^^^^^^^^^^^^^^^^ | = help: add `#![feature(intrinsics)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: intrinsic must be in `extern "rust-intrinsic" { ... }` block - --> $DIR/incorrect-read_via_copy-defn.rs:5:44 +error[E0133]: call to unsafe function `read_via_copy` is unsafe and requires unsafe function or block + --> $DIR/incorrect-read_via_copy-defn.rs:2:5 | -LL | extern "rust-intrinsic" fn read_via_copy() {} - | ^^ +LL | read_via_copy(); + | ^^^^^^^^^^^^^^^ call to unsafe function + | + = note: consult the function's documentation for information on how to avoid undefined behavior error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0658`. +Some errors have detailed explanations: E0133, E0658. +For more information about an error, try `rustc --explain E0133`. diff --git a/tests/ui/intrinsics/incorrect-transmute.rs b/tests/ui/intrinsics/incorrect-transmute.rs index 15d1ab939ed0..25fbc7a92ee7 100644 --- a/tests/ui/intrinsics/incorrect-transmute.rs +++ b/tests/ui/intrinsics/incorrect-transmute.rs @@ -1,7 +1,8 @@ fn main() { transmute(); // does not ICE + //~^ ERROR call to unsafe function `transmute` is unsafe and requires unsafe function or block } -extern "rust-intrinsic" fn transmute() {} -//~^ ERROR "rust-intrinsic" ABI is an implementation detail -//~| ERROR intrinsic must be in `extern "rust-intrinsic" { ... }` block +#[rustc_intrinsic] +//~^ ERROR the `#[rustc_intrinsic]` attribute is used to declare intrinsics as function items +unsafe fn transmute() {} diff --git a/tests/ui/intrinsics/incorrect-transmute.stderr b/tests/ui/intrinsics/incorrect-transmute.stderr index 99dfb9847ff2..6145a11c4ae0 100644 --- a/tests/ui/intrinsics/incorrect-transmute.stderr +++ b/tests/ui/intrinsics/incorrect-transmute.stderr @@ -1,18 +1,21 @@ -error[E0658]: the extern "rust-intrinsic" ABI is an implementation detail and perma-unstable - --> $DIR/incorrect-transmute.rs:5:8 +error[E0658]: the `#[rustc_intrinsic]` attribute is used to declare intrinsics as function items + --> $DIR/incorrect-transmute.rs:6:1 | -LL | extern "rust-intrinsic" fn transmute() {} - | ^^^^^^^^^^^^^^^^ +LL | #[rustc_intrinsic] + | ^^^^^^^^^^^^^^^^^^ | = help: add `#![feature(intrinsics)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: intrinsic must be in `extern "rust-intrinsic" { ... }` block - --> $DIR/incorrect-transmute.rs:5:40 +error[E0133]: call to unsafe function `transmute` is unsafe and requires unsafe function or block + --> $DIR/incorrect-transmute.rs:2:5 | -LL | extern "rust-intrinsic" fn transmute() {} - | ^^ +LL | transmute(); // does not ICE + | ^^^^^^^^^^^ call to unsafe function + | + = note: consult the function's documentation for information on how to avoid undefined behavior error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0658`. +Some errors have detailed explanations: E0133, E0658. +For more information about an error, try `rustc --explain E0133`. diff --git a/tests/ui/intrinsics/intrinsic-atomics.rs b/tests/ui/intrinsics/intrinsic-atomics.rs index 4ad267e3ddb3..9127cc649e66 100644 --- a/tests/ui/intrinsics/intrinsic-atomics.rs +++ b/tests/ui/intrinsics/intrinsic-atomics.rs @@ -1,35 +1,6 @@ //@ run-pass -#![feature(intrinsics)] - -mod rusti { - extern "rust-intrinsic" { - pub fn atomic_cxchg_seqcst_seqcst(dst: *mut T, old: T, src: T) -> (T, bool); - pub fn atomic_cxchg_acquire_acquire(dst: *mut T, old: T, src: T) -> (T, bool); - pub fn atomic_cxchg_release_relaxed(dst: *mut T, old: T, src: T) -> (T, bool); - - pub fn atomic_cxchgweak_seqcst_seqcst(dst: *mut T, old: T, src: T) -> (T, bool); - pub fn atomic_cxchgweak_acquire_acquire(dst: *mut T, old: T, src: T) -> (T, bool); - pub fn atomic_cxchgweak_release_relaxed(dst: *mut T, old: T, src: T) -> (T, bool); - - pub fn atomic_load_seqcst(src: *const T) -> T; - pub fn atomic_load_acquire(src: *const T) -> T; - - pub fn atomic_store_seqcst(dst: *mut T, val: T); - pub fn atomic_store_release(dst: *mut T, val: T); - - pub fn atomic_xchg_seqcst(dst: *mut T, src: T) -> T; - pub fn atomic_xchg_acquire(dst: *mut T, src: T) -> T; - pub fn atomic_xchg_release(dst: *mut T, src: T) -> T; - - pub fn atomic_xadd_seqcst(dst: *mut T, src: T) -> T; - pub fn atomic_xadd_acquire(dst: *mut T, src: T) -> T; - pub fn atomic_xadd_release(dst: *mut T, src: T) -> T; - - pub fn atomic_xsub_seqcst(dst: *mut T, src: T) -> T; - pub fn atomic_xsub_acquire(dst: *mut T, src: T) -> T; - pub fn atomic_xsub_release(dst: *mut T, src: T) -> T; - } -} +#![feature(core_intrinsics)] +use std::intrinsics as rusti; pub fn main() { unsafe { @@ -39,9 +10,9 @@ pub fn main() { *x = 5; assert_eq!(rusti::atomic_load_acquire(&*x), 5); - rusti::atomic_store_seqcst(&mut *x,3); + rusti::atomic_store_seqcst(&mut *x, 3); assert_eq!(*x, 3); - rusti::atomic_store_release(&mut *x,1); + rusti::atomic_store_release(&mut *x, 1); assert_eq!(*x, 1); assert_eq!(rusti::atomic_cxchg_seqcst_seqcst(&mut *x, 1, 2), (1, true)); diff --git a/tests/ui/intrinsics/intrinsic-raw_eq-const-bad.rs b/tests/ui/intrinsics/intrinsic-raw_eq-const-bad.rs index 76b6a8c8395c..fdb25a3ae3f5 100644 --- a/tests/ui/intrinsics/intrinsic-raw_eq-const-bad.rs +++ b/tests/ui/intrinsics/intrinsic-raw_eq-const-bad.rs @@ -3,13 +3,13 @@ const RAW_EQ_PADDING: bool = unsafe { std::intrinsics::raw_eq(&(1_u8, 2_u16), &(1_u8, 2_u16)) //~^ ERROR evaluation of constant value failed -//~| requires initialized memory +//~| NOTE requires initialized memory }; const RAW_EQ_PTR: bool = unsafe { std::intrinsics::raw_eq(&(&0), &(&1)) //~^ ERROR evaluation of constant value failed -//~| unable to turn pointer into integer +//~| NOTE unable to turn pointer into integer }; const RAW_EQ_NOT_ALIGNED: bool = unsafe { @@ -17,7 +17,7 @@ const RAW_EQ_NOT_ALIGNED: bool = unsafe { let aref = &*arr.as_ptr().cast::(); std::intrinsics::raw_eq(aref, aref) //~^ ERROR evaluation of constant value failed -//~| alignment +//~| NOTE alignment }; pub fn main() { diff --git a/tests/ui/intrinsics/invalid-ABI-rust-intrinsic.rs b/tests/ui/intrinsics/invalid-ABI-rust-intrinsic.rs new file mode 100644 index 000000000000..4b777deb8b50 --- /dev/null +++ b/tests/ui/intrinsics/invalid-ABI-rust-intrinsic.rs @@ -0,0 +1,19 @@ +#![feature(intrinsics)] + +trait Foo { + extern "rust-intrinsic" fn foo(&self); //~ ERROR invalid ABI +} + +impl Foo for () { + extern "rust-intrinsic" fn foo(&self) { //~ ERROR invalid ABI + } +} + +extern "rust-intrinsic" fn hello() { //~ ERROR invalid ABI +} + +extern "rust-intrinsic" { + //~^ ERROR invalid ABI +} + +fn main() {} diff --git a/tests/ui/intrinsics/invalid-ABI-rust-intrinsic.stderr b/tests/ui/intrinsics/invalid-ABI-rust-intrinsic.stderr new file mode 100644 index 000000000000..fc8bf62915b1 --- /dev/null +++ b/tests/ui/intrinsics/invalid-ABI-rust-intrinsic.stderr @@ -0,0 +1,35 @@ +error[E0703]: invalid ABI: found `rust-intrinsic` + --> $DIR/invalid-ABI-rust-intrinsic.rs:4:12 + | +LL | extern "rust-intrinsic" fn foo(&self); + | ^^^^^^^^^^^^^^^^ invalid ABI + | + = note: invoke `rustc --print=calling-conventions` for a full list of supported calling conventions + +error[E0703]: invalid ABI: found `rust-intrinsic` + --> $DIR/invalid-ABI-rust-intrinsic.rs:8:12 + | +LL | extern "rust-intrinsic" fn foo(&self) { + | ^^^^^^^^^^^^^^^^ invalid ABI + | + = note: invoke `rustc --print=calling-conventions` for a full list of supported calling conventions + +error[E0703]: invalid ABI: found `rust-intrinsic` + --> $DIR/invalid-ABI-rust-intrinsic.rs:12:8 + | +LL | extern "rust-intrinsic" fn hello() { + | ^^^^^^^^^^^^^^^^ invalid ABI + | + = note: invoke `rustc --print=calling-conventions` for a full list of supported calling conventions + +error[E0703]: invalid ABI: found `rust-intrinsic` + --> $DIR/invalid-ABI-rust-intrinsic.rs:15:8 + | +LL | extern "rust-intrinsic" { + | ^^^^^^^^^^^^^^^^ invalid ABI + | + = note: invoke `rustc --print=calling-conventions` for a full list of supported calling conventions + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0703`. diff --git a/tests/ui/intrinsics/issue-28575.rs b/tests/ui/intrinsics/issue-28575.rs index 141136d25b21..841bc45138a1 100644 --- a/tests/ui/intrinsics/issue-28575.rs +++ b/tests/ui/intrinsics/issue-28575.rs @@ -2,6 +2,7 @@ extern "C" { pub static FOO: extern "rust-intrinsic" fn(); + //~^ ERROR invalid ABI } fn main() { diff --git a/tests/ui/intrinsics/issue-28575.stderr b/tests/ui/intrinsics/issue-28575.stderr index 8a7816f231f7..09c52aa4c998 100644 --- a/tests/ui/intrinsics/issue-28575.stderr +++ b/tests/ui/intrinsics/issue-28575.stderr @@ -1,11 +1,20 @@ +error[E0703]: invalid ABI: found `rust-intrinsic` + --> $DIR/issue-28575.rs:4:28 + | +LL | pub static FOO: extern "rust-intrinsic" fn(); + | ^^^^^^^^^^^^^^^^ invalid ABI + | + = note: invoke `rustc --print=calling-conventions` for a full list of supported calling conventions + error[E0133]: use of extern static is unsafe and requires unsafe function or block - --> $DIR/issue-28575.rs:8:5 + --> $DIR/issue-28575.rs:9:5 | LL | FOO() | ^^^ use of extern static | = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior -error: aborting due to 1 previous error +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0133`. +Some errors have detailed explanations: E0133, E0703. +For more information about an error, try `rustc --explain E0133`. diff --git a/tests/ui/intrinsics/safe-intrinsic-mismatch.rs b/tests/ui/intrinsics/safe-intrinsic-mismatch.rs index 915a23b59053..4c301f9dbb09 100644 --- a/tests/ui/intrinsics/safe-intrinsic-mismatch.rs +++ b/tests/ui/intrinsics/safe-intrinsic-mismatch.rs @@ -1,13 +1,14 @@ #![feature(intrinsics)] #![feature(rustc_attrs)] -extern "rust-intrinsic" { - fn size_of() -> usize; //~ ERROR intrinsic safety mismatch - //~^ ERROR intrinsic safety mismatch -} +#[rustc_intrinsic] +unsafe fn size_of() -> usize; +//~^ ERROR intrinsic safety mismatch +//~| ERROR intrinsic has wrong type #[rustc_intrinsic] -const fn assume(_b: bool) {} //~ ERROR intrinsic safety mismatch +const fn assume(_b: bool) {} +//~^ ERROR intrinsic safety mismatch //~| ERROR intrinsic has wrong type #[rustc_intrinsic] diff --git a/tests/ui/intrinsics/safe-intrinsic-mismatch.stderr b/tests/ui/intrinsics/safe-intrinsic-mismatch.stderr index aa4f294232d2..04f6daeced2a 100644 --- a/tests/ui/intrinsics/safe-intrinsic-mismatch.stderr +++ b/tests/ui/intrinsics/safe-intrinsic-mismatch.stderr @@ -1,16 +1,17 @@ error: intrinsic safety mismatch between list of intrinsics within the compiler and core library intrinsics for intrinsic `size_of` - --> $DIR/safe-intrinsic-mismatch.rs:5:5 + --> $DIR/safe-intrinsic-mismatch.rs:5:1 | -LL | fn size_of() -> usize; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | unsafe fn size_of() -> usize; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: intrinsic safety mismatch between list of intrinsics within the compiler and core library intrinsics for intrinsic `size_of` - --> $DIR/safe-intrinsic-mismatch.rs:5:5 +error[E0308]: intrinsic has wrong type + --> $DIR/safe-intrinsic-mismatch.rs:5:18 | -LL | fn size_of() -> usize; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | unsafe fn size_of() -> usize; + | ^^^ expected safe fn, found unsafe fn | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + = note: expected signature `fn() -> _` + found signature `unsafe fn() -> _` error: intrinsic safety mismatch between list of intrinsics within the compiler and core library intrinsics for intrinsic `assume` --> $DIR/safe-intrinsic-mismatch.rs:10:1 @@ -28,13 +29,13 @@ LL | const fn assume(_b: bool) {} found signature `fn(_)` error: intrinsic safety mismatch between list of intrinsics within the compiler and core library intrinsics for intrinsic `const_deallocate` - --> $DIR/safe-intrinsic-mismatch.rs:14:1 + --> $DIR/safe-intrinsic-mismatch.rs:15:1 | LL | const fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: intrinsic has wrong type - --> $DIR/safe-intrinsic-mismatch.rs:14:26 + --> $DIR/safe-intrinsic-mismatch.rs:15:26 | LL | const fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) {} | ^ expected unsafe fn, found safe fn diff --git a/tests/ui/invalid-compile-flags/crate-type-flag.rs b/tests/ui/invalid-compile-flags/crate-type-flag.rs index 8ccce97f7bfa..61b35cf8c64f 100644 --- a/tests/ui/invalid-compile-flags/crate-type-flag.rs +++ b/tests/ui/invalid-compile-flags/crate-type-flag.rs @@ -3,8 +3,6 @@ //! //! This test does not try to check if the output artifacts are valid. -// FIXME(#132309): add a proper `supports-crate-type` directive. - // Single valid crate types should pass //@ revisions: lib rlib staticlib dylib cdylib bin proc_dash_macro @@ -17,19 +15,18 @@ //@[staticlib] compile-flags: --crate-type=staticlib //@[staticlib] check-pass -//@[dylib] ignore-musl (dylib is supported, but musl libc is statically linked by default) -//@[dylib] ignore-wasm (dylib is not supported) +//@[dylib] needs-crate-type: dylib //@[dylib] compile-flags: --crate-type=dylib //@[dylib] check-pass -//@[cdylib] ignore-musl (cdylib is supported, but musl libc is statically linked by default) +//@[cdylib] needs-crate-type: cdylib //@[cdylib] compile-flags: --crate-type=cdylib //@[cdylib] check-pass //@[bin] compile-flags: --crate-type=bin //@[bin] check-pass -//@[proc_dash_macro] ignore-wasm (proc-macro is not supported) +//@[proc_dash_macro] needs-crate-type: proc-macro //@[proc_dash_macro] needs-unwind (panic=abort causes warning to be emitted) //@[proc_dash_macro] compile-flags: --crate-type=proc-macro //@[proc_dash_macro] check-pass diff --git a/tests/ui/invalid-compile-flags/print-without-arg.stderr b/tests/ui/invalid-compile-flags/print-without-arg.stderr index 8abaee5056ba..fd2a36e761be 100644 --- a/tests/ui/invalid-compile-flags/print-without-arg.stderr +++ b/tests/ui/invalid-compile-flags/print-without-arg.stderr @@ -1,5 +1,6 @@ error: Argument to option 'print' missing Usage: - --print [all-target-specs-json|calling-conventions|cfg|check-cfg|code-models|crate-name|crate-root-lint-levels|deployment-target|file-names|host-tuple|link-args|native-static-libs|relocation-models|split-debuginfo|stack-protector-strategies|supported-crate-types|sysroot|target-cpus|target-features|target-libdir|target-list|target-spec-json|tls-models] - Compiler information to print on stdout + --print INFO[=FILE] Compiler information to print on stdout (or to a file) + INFO may be one of + (all-target-specs-json|calling-conventions|cfg|check-cfg|code-models|crate-name|crate-root-lint-levels|deployment-target|file-names|host-tuple|link-args|native-static-libs|relocation-models|split-debuginfo|stack-protector-strategies|supported-crate-types|sysroot|target-cpus|target-features|target-libdir|target-list|target-spec-json|tls-models). diff --git a/tests/ui/invalid/invalid-rustc_legacy_const_generics-issue-123077.rs b/tests/ui/invalid/invalid-rustc_legacy_const_generics-issue-123077.rs index 8d854c6c2370..f3a15a58f26a 100644 --- a/tests/ui/invalid/invalid-rustc_legacy_const_generics-issue-123077.rs +++ b/tests/ui/invalid/invalid-rustc_legacy_const_generics-issue-123077.rs @@ -6,26 +6,26 @@ const fn foo() -> i32 { fn main() { std::arch::x86_64::_mm_blend_ps(loop {}, loop {}, || ()); - //~^ invalid argument to a legacy const generic + //~^ ERROR invalid argument to a legacy const generic std::arch::x86_64::_mm_blend_ps(loop {}, loop {}, 5 + || ()); - //~^ invalid argument to a legacy const generic + //~^ ERROR invalid argument to a legacy const generic std::arch::x86_64::_mm_blend_ps(loop {}, loop {}, foo::<{ 1 + 2 }>()); - //~^ invalid argument to a legacy const generic + //~^ ERROR invalid argument to a legacy const generic std::arch::x86_64::_mm_blend_ps(loop {}, loop {}, foo::<3>()); - //~^ invalid argument to a legacy const generic + //~^ ERROR invalid argument to a legacy const generic std::arch::x86_64::_mm_blend_ps(loop {}, loop {}, &const {}); - //~^ invalid argument to a legacy const generic + //~^ ERROR invalid argument to a legacy const generic std::arch::x86_64::_mm_blend_ps(loop {}, loop {}, { struct F(); - //~^ invalid argument to a legacy const generic + //~^ ERROR invalid argument to a legacy const generic 1 }); std::arch::x86_64::_mm_inserti_si64(loop {}, loop {}, || (), 1 + || ()); - //~^ invalid argument to a legacy const generic + //~^ ERROR invalid argument to a legacy const generic } diff --git a/tests/ui/invalid_dispatch_from_dyn_impls.rs b/tests/ui/invalid_dispatch_from_dyn_impls.rs index 972465d71978..b1d4b261babe 100644 --- a/tests/ui/invalid_dispatch_from_dyn_impls.rs +++ b/tests/ui/invalid_dispatch_from_dyn_impls.rs @@ -20,7 +20,7 @@ struct MultiplePointers{ } impl DispatchFromDyn> for MultiplePointers -//~^ implementing `DispatchFromDyn` does not allow multiple fields to be coerced +//~^ ERROR implementing `DispatchFromDyn` does not allow multiple fields to be coerced where T: Unsize, {} diff --git a/tests/ui/issues/issue-11004.rs b/tests/ui/issues/issue-11004.rs index 09d5476dbe60..0c34554c12d1 100644 --- a/tests/ui/issues/issue-11004.rs +++ b/tests/ui/issues/issue-11004.rs @@ -4,12 +4,12 @@ struct A { x: i32, y: f64 } #[cfg(not(FALSE))] unsafe fn access(n:*mut A) -> (i32, f64) { - let x : i32 = n.x; //~ no field `x` on type `*mut A` - let y : f64 = n.y; //~ no field `y` on type `*mut A` + let x : i32 = n.x; //~ ERROR no field `x` on type `*mut A` + let y : f64 = n.y; //~ ERROR no field `y` on type `*mut A` (x, y) } -#[cfg(FALSE)] +#[cfg(false)] unsafe fn access(n:*mut A) -> (i32, f64) { let x : i32 = (*n).x; let y : f64 = (*n).y; diff --git a/tests/ui/issues/issue-11085.rs b/tests/ui/issues/issue-11085.rs index d0703b063954..c3f13199b308 100644 --- a/tests/ui/issues/issue-11085.rs +++ b/tests/ui/issues/issue-11085.rs @@ -3,7 +3,7 @@ #![allow(dead_code)] struct Foo { - #[cfg(FALSE)] + #[cfg(false)] bar: baz, foo: isize, } @@ -15,18 +15,18 @@ struct Foo2 { enum Bar1 { Bar1_1, - #[cfg(FALSE)] + #[cfg(false)] Bar1_2(NotAType), } enum Bar2 { - #[cfg(FALSE)] + #[cfg(false)] Bar2_1(NotAType), } enum Bar3 { Bar3_1 { - #[cfg(FALSE)] + #[cfg(false)] foo: isize, bar: isize, } diff --git a/tests/ui/issues/issue-14721.rs b/tests/ui/issues/issue-14721.rs index a5c47dd8cb3d..c015a6bab083 100644 --- a/tests/ui/issues/issue-14721.rs +++ b/tests/ui/issues/issue-14721.rs @@ -1,4 +1,4 @@ fn main() { let foo = "str"; - println!("{}", foo.desc); //~ no field `desc` on type `&str` + println!("{}", foo.desc); //~ ERROR no field `desc` on type `&str` } diff --git a/tests/ui/issues/issue-16819.rs b/tests/ui/issues/issue-16819.rs index e2b109091777..2805c82acfb2 100644 --- a/tests/ui/issues/issue-16819.rs +++ b/tests/ui/issues/issue-16819.rs @@ -3,7 +3,7 @@ // `#[cfg]` on struct field permits empty unusable struct struct S { - #[cfg(FALSE)] + #[cfg(false)] a: int, } diff --git a/tests/ui/issues/issue-17740.rs b/tests/ui/issues/issue-17740.rs index 3b868555fc52..574d3662b4fb 100644 --- a/tests/ui/issues/issue-17740.rs +++ b/tests/ui/issues/issue-17740.rs @@ -4,11 +4,11 @@ struct Foo<'a> { impl <'a> Foo<'a>{ fn bar(self: &mut Foo) { - //~^ mismatched `self` parameter type + //~^ ERROR mismatched `self` parameter type //~| expected struct `Foo<'a>` //~| found struct `Foo<'_>` //~| lifetime mismatch - //~| mismatched `self` parameter type + //~| ERROR mismatched `self` parameter type //~| expected struct `Foo<'a>` //~| found struct `Foo<'_>` //~| lifetime mismatch diff --git a/tests/ui/issues/issue-23253.rs b/tests/ui/issues/issue-23253.rs index 22b55c285814..b285cb81ee23 100644 --- a/tests/ui/issues/issue-23253.rs +++ b/tests/ui/issues/issue-23253.rs @@ -2,5 +2,5 @@ enum Foo { Bar } fn main() { Foo::Bar.a; - //~^ no field `a` on type `Foo` + //~^ ERROR no field `a` on type `Foo` } diff --git a/tests/ui/issues/issue-24363.rs b/tests/ui/issues/issue-24363.rs index 34726fba9c66..f358b8b90171 100644 --- a/tests/ui/issues/issue-24363.rs +++ b/tests/ui/issues/issue-24363.rs @@ -1,5 +1,5 @@ fn main() { - 1.create_a_type_error[ //~ `{integer}` is a primitive type and therefore doesn't have fields + 1.create_a_type_error[ //~ ERROR `{integer}` is a primitive type and therefore doesn't have fields ()+() //~ ERROR cannot add // ^ ensure that we typeck the inner expression ^ ]; diff --git a/tests/ui/issues/issue-24365.rs b/tests/ui/issues/issue-24365.rs index eca104b6f1d8..da1951160478 100644 --- a/tests/ui/issues/issue-24365.rs +++ b/tests/ui/issues/issue-24365.rs @@ -7,13 +7,13 @@ pub enum Foo { } fn test(a: Foo) { - println!("{}", a.b); //~ no field `b` on type `Foo` + println!("{}", a.b); //~ ERROR no field `b` on type `Foo` } fn main() { let x = Attribute::Code { attr_name_idx: 42, }; - let z = (&x).attr_name_idx; //~ no field `attr_name_idx` on type `&Attribute` - let y = x.attr_name_idx; //~ no field `attr_name_idx` on type `Attribute` + let z = (&x).attr_name_idx; //~ ERROR no field `attr_name_idx` on type `&Attribute` + let y = x.attr_name_idx; //~ ERROR no field `attr_name_idx` on type `Attribute` } diff --git a/tests/ui/issues/issue-27008.rs b/tests/ui/issues/issue-27008.rs index adf8e779e0a0..20aa4f282c7e 100644 --- a/tests/ui/issues/issue-27008.rs +++ b/tests/ui/issues/issue-27008.rs @@ -3,5 +3,5 @@ struct S; fn main() { let b = [0; S]; //~^ ERROR mismatched types - //~| expected `usize`, found `S` + //~| NOTE expected `usize`, found `S` } diff --git a/tests/ui/issues/issue-2848.rs b/tests/ui/issues/issue-2848.rs index 34181acdd055..8499459cec26 100644 --- a/tests/ui/issues/issue-2848.rs +++ b/tests/ui/issues/issue-2848.rs @@ -11,8 +11,8 @@ mod bar { fn main() { use bar::foo::{alpha, charlie}; match alpha { - alpha | beta => {} //~ ERROR variable `beta` is not bound in all patterns - //~^ ERROR: `beta` is named the same as one of the variants + alpha | beta => {} //~ ERROR variable `beta` is not bound in all patterns + //~^ ERROR `beta` is named the same as one of the variants charlie => {} } } diff --git a/tests/ui/issues/issue-31011.rs b/tests/ui/issues/issue-31011.rs index 4dead04c2ca3..86fe16f48e22 100644 --- a/tests/ui/issues/issue-31011.rs +++ b/tests/ui/issues/issue-31011.rs @@ -1,7 +1,7 @@ macro_rules! log { ( $ctx:expr, $( $args:expr),* ) => { if $ctx.trace { - //~^ no field `trace` on type `&T` + //~^ ERROR no field `trace` on type `&T` println!( $( $args, )* ); } } diff --git a/tests/ui/issues/issue-37131.rs b/tests/ui/issues/issue-37131.rs index 16681ac21d11..e91c76e1390e 100644 --- a/tests/ui/issues/issue-37131.rs +++ b/tests/ui/issues/issue-37131.rs @@ -1,4 +1,6 @@ //~ ERROR can't find crate for `std` +//~| NOTE target may not be installed +//~| NOTE can't find crate // Tests that compiling for a target which is not installed will result in a helpful // error message. @@ -6,5 +8,4 @@ //@ ignore-arm //@ needs-llvm-components: arm -//@ error-pattern:target may not be installed fn main() { } diff --git a/tests/ui/issues/issue-51102.rs b/tests/ui/issues/issue-51102.rs index 41446cd29b0d..b5ddc7221d06 100644 --- a/tests/ui/issues/issue-51102.rs +++ b/tests/ui/issues/issue-51102.rs @@ -11,7 +11,7 @@ fn main() { match simple { SimpleStruct { state: 0, - //~^ struct `SimpleStruct` does not have a field named `state` [E0026] + //~^ ERROR struct `SimpleStruct` does not have a field named `state` [E0026] .. } => (), } diff --git a/tests/ui/issues/issue-69130.rs b/tests/ui/issues/issue-69130.rs index 9552e8ec2a87..90dffc99db7f 100644 --- a/tests/ui/issues/issue-69130.rs +++ b/tests/ui/issues/issue-69130.rs @@ -3,5 +3,5 @@ enum F { M (§& u8)} //~^ ERROR unknown start of token -//~| missing lifetime specifier +//~| ERROR missing lifetime specifier fn main() {} diff --git a/tests/ui/issues/issue-87199.rs b/tests/ui/issues/issue-87199.rs index 6664119e5798..4e4e35c6a71e 100644 --- a/tests/ui/issues/issue-87199.rs +++ b/tests/ui/issues/issue-87199.rs @@ -17,5 +17,5 @@ fn ret() -> impl Iterator + ?Send { std::iter::empty() } fn main() { ref_arg::(&5); ref_arg::<[i32]>(&[5]); - //~^ the size for values of type `[i32]` cannot be known + //~^ ERROR the size for values of type `[i32]` cannot be known } diff --git a/tests/ui/issues/issue-8761.rs b/tests/ui/issues/issue-8761.rs index 1453c3d757f7..5883bb966956 100644 --- a/tests/ui/issues/issue-8761.rs +++ b/tests/ui/issues/issue-8761.rs @@ -1,10 +1,10 @@ enum Foo { A = 1i64, //~^ ERROR mismatched types - //~| expected `isize`, found `i64` + //~| NOTE expected `isize`, found `i64` B = 2u8 //~^ ERROR mismatched types - //~| expected `isize`, found `u8` + //~| NOTE expected `isize`, found `u8` } fn main() {} diff --git a/tests/ui/iterators/float_iterator_hint.rs b/tests/ui/iterators/float_iterator_hint.rs index a3335ca41f77..9e7a10ca497e 100644 --- a/tests/ui/iterators/float_iterator_hint.rs +++ b/tests/ui/iterators/float_iterator_hint.rs @@ -3,7 +3,7 @@ fn main() { for i in 0.2 { //~^ ERROR `{float}` is not an iterator - //~| `{float}` is not an iterator + //~| NOTE `{float}` is not an iterator //~| NOTE in this expansion of desugaring of `for` loop //~| NOTE in this expansion of desugaring of `for` loop //~| NOTE in this expansion of desugaring of `for` loop diff --git a/tests/ui/label/label_break_value_desugared_break.rs b/tests/ui/label/label_break_value_desugared_break.rs index b7e7fd47c27f..17ef1ba6d24b 100644 --- a/tests/ui/label/label_break_value_desugared_break.rs +++ b/tests/ui/label/label_break_value_desugared_break.rs @@ -1,4 +1,4 @@ -//@ compile-flags: --edition 2018 +//@ edition: 2018 #![feature(try_blocks)] //@ run-pass diff --git a/tests/ui/layout/post-mono-layout-cycle.rs b/tests/ui/layout/post-mono-layout-cycle.rs index 6753c01267ec..841fc30a50bc 100644 --- a/tests/ui/layout/post-mono-layout-cycle.rs +++ b/tests/ui/layout/post-mono-layout-cycle.rs @@ -1,5 +1,5 @@ //@ build-fail -//~^ cycle detected when computing layout of `Wrapper<()>` +//~^ ERROR cycle detected when computing layout of `Wrapper<()>` trait Trait { type Assoc; diff --git a/tests/ui/layout/unknown-when-no-type-parameter.rs b/tests/ui/layout/unknown-when-no-type-parameter.rs index 500b7938eeb0..87f90aa438ab 100644 --- a/tests/ui/layout/unknown-when-no-type-parameter.rs +++ b/tests/ui/layout/unknown-when-no-type-parameter.rs @@ -1,13 +1,13 @@ #![feature(trivial_bounds)] -//@ error-pattern: the type `<() as Project>::Assoc` has an unknown layout - trait Project { type Assoc; } fn foo() where (): Project { [(); size_of::<<() as Project>::Assoc>()]; //~ ERROR evaluation of constant value failed + //~| NOTE the type `<() as Project>::Assoc` has an unknown layout + //~| NOTE inside `std::mem::size_of::<<() as Project>::Assoc>` } fn main() {} diff --git a/tests/ui/layout/unknown-when-no-type-parameter.stderr b/tests/ui/layout/unknown-when-no-type-parameter.stderr index a2dbb191ee27..35fbb11f156a 100644 --- a/tests/ui/layout/unknown-when-no-type-parameter.stderr +++ b/tests/ui/layout/unknown-when-no-type-parameter.stderr @@ -1,5 +1,5 @@ error[E0080]: evaluation of constant value failed - --> $DIR/unknown-when-no-type-parameter.rs:10:10 + --> $DIR/unknown-when-no-type-parameter.rs:8:10 | LL | [(); size_of::<<() as Project>::Assoc>()]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the type `<() as Project>::Assoc` has an unknown layout diff --git a/tests/ui/let-else/issue-102317.rs b/tests/ui/let-else/issue-102317.rs index d94410e10a8d..5afcacfc3aad 100644 --- a/tests/ui/let-else/issue-102317.rs +++ b/tests/ui/let-else/issue-102317.rs @@ -1,6 +1,7 @@ // issue #102317 //@ build-pass -//@ compile-flags: --edition 2021 -C opt-level=3 -Zvalidate-mir +//@ compile-flags: -C opt-level=3 -Zvalidate-mir +//@ edition: 2021 struct SegmentJob; diff --git a/tests/ui/lexer/error-stage.rs b/tests/ui/lexer/error-stage.rs index c8d88f745a1f..f0ccb886d0d2 100644 --- a/tests/ui/lexer/error-stage.rs +++ b/tests/ui/lexer/error-stage.rs @@ -59,7 +59,7 @@ const _: () = sink! { // The invalid literals used to cause errors, but this was changed by #102944. // Except for `0b010.0f32`, because it's a lexer error. -#[cfg(FALSE)] +#[cfg(false)] fn configured_out() { "string"any_suffix; // OK 10u123; // OK diff --git a/tests/ui/lifetimes/conflicting-bounds.rs b/tests/ui/lifetimes/conflicting-bounds.rs index f37f163dbb63..62240792afd7 100644 --- a/tests/ui/lifetimes/conflicting-bounds.rs +++ b/tests/ui/lifetimes/conflicting-bounds.rs @@ -1,4 +1,4 @@ -//~ type annotations needed: cannot satisfy `Self: Gen<'source>` +//~ ERROR type annotations needed: cannot satisfy `Self: Gen<'source>` pub trait Gen<'source> { type Output; diff --git a/tests/ui/lifetimes/issue-83737-binders-across-types.rs b/tests/ui/lifetimes/issue-83737-binders-across-types.rs index d20c84dae3f7..6f3993812944 100644 --- a/tests/ui/lifetimes/issue-83737-binders-across-types.rs +++ b/tests/ui/lifetimes/issue-83737-binders-across-types.rs @@ -1,5 +1,5 @@ //@ build-pass -//@ compile-flags: --edition 2018 +//@ edition: 2018 //@ compile-flags: --crate-type rlib use std::future::Future; diff --git a/tests/ui/lifetimes/issue-83737-erasing-bound-vars.rs b/tests/ui/lifetimes/issue-83737-erasing-bound-vars.rs index 466bcdc6be0f..dcc8c7e94ba6 100644 --- a/tests/ui/lifetimes/issue-83737-erasing-bound-vars.rs +++ b/tests/ui/lifetimes/issue-83737-erasing-bound-vars.rs @@ -1,5 +1,5 @@ //@ build-pass -//@ compile-flags: --edition 2018 +//@ edition: 2018 //@ compile-flags: --crate-type rlib use std::future::Future; diff --git a/tests/ui/lifetimes/issue-83753-invalid-associated-type-supertrait-hrtb.rs b/tests/ui/lifetimes/issue-83753-invalid-associated-type-supertrait-hrtb.rs index 78069e682c13..4aa212bb4bd3 100644 --- a/tests/ui/lifetimes/issue-83753-invalid-associated-type-supertrait-hrtb.rs +++ b/tests/ui/lifetimes/issue-83753-invalid-associated-type-supertrait-hrtb.rs @@ -3,6 +3,6 @@ struct Foo {} impl Foo { fn bar(foo: Foo) {} - //~^ associated item constraints are not allowed here + //~^ ERROR associated item constraints are not allowed here } fn main() {} diff --git a/tests/ui/lifetimes/issue-83907-invalid-fn-like-path.rs b/tests/ui/lifetimes/issue-83907-invalid-fn-like-path.rs index 4e093bb2e17d..4f4e2cda9469 100644 --- a/tests/ui/lifetimes/issue-83907-invalid-fn-like-path.rs +++ b/tests/ui/lifetimes/issue-83907-invalid-fn-like-path.rs @@ -1,7 +1,7 @@ //@ check-fail static STATIC_VAR_FIVE: &One(); -//~^ cannot find type -//~| free static item without body +//~^ ERROR cannot find type +//~| ERROR free static item without body fn main() {} diff --git a/tests/ui/lifetimes/no_lending_iterators.rs b/tests/ui/lifetimes/no_lending_iterators.rs index 21395475fb3d..b3e8ad08ba18 100644 --- a/tests/ui/lifetimes/no_lending_iterators.rs +++ b/tests/ui/lifetimes/no_lending_iterators.rs @@ -25,7 +25,7 @@ impl Bar for usize { impl Bar for isize { type Item<'a> = &'a isize; - //~^ ERROR 27:14: 27:18: lifetime parameters or bounds on type `Item` do not match the trait declaration [E0195] + //~^ ERROR 27:14: 27:18: lifetime parameters or bounds on associated type `Item` do not match the trait declaration [E0195] fn poke(&mut self, item: Self::Item) { self += *item; diff --git a/tests/ui/lifetimes/no_lending_iterators.stderr b/tests/ui/lifetimes/no_lending_iterators.stderr index 9ceaef2f9b1a..340ef9358851 100644 --- a/tests/ui/lifetimes/no_lending_iterators.stderr +++ b/tests/ui/lifetimes/no_lending_iterators.stderr @@ -16,14 +16,14 @@ error: in the trait associated type is declared without lifetime parameters, so LL | type Item = &usize; | ^ this lifetime must come from the implemented type -error[E0195]: lifetime parameters or bounds on type `Item` do not match the trait declaration +error[E0195]: lifetime parameters or bounds on associated type `Item` do not match the trait declaration --> $DIR/no_lending_iterators.rs:27:14 | LL | type Item; - | - lifetimes in impl do not match this type in trait + | - lifetimes in impl do not match this associated type in trait ... LL | type Item<'a> = &'a isize; - | ^^^^ lifetimes do not match type in trait + | ^^^^ lifetimes do not match associated type in trait error: aborting due to 3 previous errors diff --git a/tests/ui/limits/huge-static.rs b/tests/ui/limits/huge-static.rs index 4709b46e59d1..4c3641ac7d4b 100644 --- a/tests/ui/limits/huge-static.rs +++ b/tests/ui/limits/huge-static.rs @@ -18,9 +18,9 @@ impl TooBigArray { static MY_TOO_BIG_ARRAY_1: TooBigArray = TooBigArray::new(); //~^ ERROR could not evaluate static initializer -//~| too big +//~| NOTE too big static MY_TOO_BIG_ARRAY_2: [u8; HUGE_SIZE] = [0x00; HUGE_SIZE]; //~^ ERROR could not evaluate static initializer -//~| too big +//~| NOTE too big fn main() { } diff --git a/tests/ui/link-native-libs/link-attr-validation-late.rs b/tests/ui/link-native-libs/link-attr-validation-late.rs index 34f720dd2d3c..4eeb8ba4884f 100644 --- a/tests/ui/link-native-libs/link-attr-validation-late.rs +++ b/tests/ui/link-native-libs/link-attr-validation-late.rs @@ -9,7 +9,7 @@ extern "C" {} #[link(name = "foo", name = "bar")] //~ ERROR multiple `name` arguments #[link(name = "...", kind = "dylib", kind = "bar")] //~ ERROR multiple `kind` arguments #[link(name = "...", modifiers = "+verbatim", modifiers = "bar")] //~ ERROR multiple `modifiers` arguments -#[link(name = "...", cfg(FALSE), cfg(FALSE))] //~ ERROR multiple `cfg` arguments +#[link(name = "...", cfg(false), cfg(false))] //~ ERROR multiple `cfg` arguments #[link(wasm_import_module = "foo", wasm_import_module = "bar")] //~ ERROR multiple `wasm_import_module` arguments extern "C" {} diff --git a/tests/ui/link-native-libs/link-attr-validation-late.stderr b/tests/ui/link-native-libs/link-attr-validation-late.stderr index 1ad5fbaf7de8..f3989c09360f 100644 --- a/tests/ui/link-native-libs/link-attr-validation-late.stderr +++ b/tests/ui/link-native-libs/link-attr-validation-late.stderr @@ -31,7 +31,7 @@ LL | #[link(name = "...", modifiers = "+verbatim", modifiers = "bar")] error: multiple `cfg` arguments in a single `#[link]` attribute --> $DIR/link-attr-validation-late.rs:12:34 | -LL | #[link(name = "...", cfg(FALSE), cfg(FALSE))] +LL | #[link(name = "...", cfg(false), cfg(false))] | ^^^^^^^^^^ error: multiple `wasm_import_module` arguments in a single `#[link]` attribute diff --git a/tests/ui/link-native-libs/suggest-libname-only-1.rs b/tests/ui/link-native-libs/suggest-libname-only-1.rs index 4ccfa086bde6..8699e4819e62 100644 --- a/tests/ui/link-native-libs/suggest-libname-only-1.rs +++ b/tests/ui/link-native-libs/suggest-libname-only-1.rs @@ -1,10 +1,11 @@ //@ build-fail //@ compile-flags: --crate-type rlib -//@ error-pattern: only provide the library name `foo`, not the full filename #[link(name = "libfoo.a", kind = "static")] -extern { } //~ WARN extern declarations without an explicit ABI are deprecated +extern { } //~ WARN `extern` declarations without an explicit ABI are deprecated + //~| HELP explicitly specify the "C" ABI pub fn main() { } //~? ERROR could not find native static library `libfoo.a` +//~? HELP only provide the library name `foo`, not the full filename diff --git a/tests/ui/link-native-libs/suggest-libname-only-1.stderr b/tests/ui/link-native-libs/suggest-libname-only-1.stderr index 85a3599e8dbd..59bd99f619a0 100644 --- a/tests/ui/link-native-libs/suggest-libname-only-1.stderr +++ b/tests/ui/link-native-libs/suggest-libname-only-1.stderr @@ -1,5 +1,5 @@ -warning: extern declarations without an explicit ABI are deprecated - --> $DIR/suggest-libname-only-1.rs:6:1 +warning: `extern` declarations without an explicit ABI are deprecated + --> $DIR/suggest-libname-only-1.rs:5:1 | LL | extern { } | ^^^^^^ help: explicitly specify the "C" ABI: `extern "C"` diff --git a/tests/ui/link-native-libs/suggest-libname-only-2.rs b/tests/ui/link-native-libs/suggest-libname-only-2.rs index c35b4a674b77..87373f563d09 100644 --- a/tests/ui/link-native-libs/suggest-libname-only-2.rs +++ b/tests/ui/link-native-libs/suggest-libname-only-2.rs @@ -1,10 +1,11 @@ //@ build-fail //@ compile-flags: --crate-type rlib -//@ error-pattern: only provide the library name `bar`, not the full filename #[link(name = "bar.lib", kind = "static")] -extern { } //~ WARN extern declarations without an explicit ABI are deprecated +extern { } //~ WARN `extern` declarations without an explicit ABI are deprecated + //~| HELP explicitly specify the "C" ABI pub fn main() { } //~? ERROR could not find native static library `bar.lib` +//~? HELP only provide the library name `bar`, not the full filename diff --git a/tests/ui/link-native-libs/suggest-libname-only-2.stderr b/tests/ui/link-native-libs/suggest-libname-only-2.stderr index d5c88931ad54..298a9ced1707 100644 --- a/tests/ui/link-native-libs/suggest-libname-only-2.stderr +++ b/tests/ui/link-native-libs/suggest-libname-only-2.stderr @@ -1,5 +1,5 @@ -warning: extern declarations without an explicit ABI are deprecated - --> $DIR/suggest-libname-only-2.rs:6:1 +warning: `extern` declarations without an explicit ABI are deprecated + --> $DIR/suggest-libname-only-2.rs:5:1 | LL | extern { } | ^^^^^^ help: explicitly specify the "C" ABI: `extern "C"` diff --git a/tests/ui/linkage-attr/issue-12133-3.rs b/tests/ui/linkage-attr/issue-12133-3.rs index 473d5774c162..df1b0b2f728e 100644 --- a/tests/ui/linkage-attr/issue-12133-3.rs +++ b/tests/ui/linkage-attr/issue-12133-3.rs @@ -2,8 +2,7 @@ //@ aux-build:issue-12133-rlib.rs //@ aux-build:issue-12133-dylib.rs //@ aux-build:issue-12133-dylib2.rs -//@ ignore-wasm32 no dylib support -//@ ignore-musl +//@ needs-crate-type: dylib //@ needs-dynamic-linking diff --git a/tests/ui/lint/cli-lint-override.forbid_warn.stderr b/tests/ui/lint/cli-lint-override.forbid_warn.stderr index fb8779ad4f15..fe3437ae3d75 100644 --- a/tests/ui/lint/cli-lint-override.forbid_warn.stderr +++ b/tests/ui/lint/cli-lint-override.forbid_warn.stderr @@ -1,4 +1,4 @@ -error: extern declarations without an explicit ABI are deprecated +error: `extern` declarations without an explicit ABI are deprecated --> $DIR/cli-lint-override.rs:12:1 | LL | extern fn foo() {} diff --git a/tests/ui/lint/cli-lint-override.force_warn_deny.stderr b/tests/ui/lint/cli-lint-override.force_warn_deny.stderr index 10fc13e3f52f..f48fca4bd9f3 100644 --- a/tests/ui/lint/cli-lint-override.force_warn_deny.stderr +++ b/tests/ui/lint/cli-lint-override.force_warn_deny.stderr @@ -1,4 +1,4 @@ -warning: extern declarations without an explicit ABI are deprecated +warning: `extern` declarations without an explicit ABI are deprecated --> $DIR/cli-lint-override.rs:12:1 | LL | extern fn foo() {} diff --git a/tests/ui/lint/cli-lint-override.rs b/tests/ui/lint/cli-lint-override.rs index 4b3fd0d9c01c..b733872166aa 100644 --- a/tests/ui/lint/cli-lint-override.rs +++ b/tests/ui/lint/cli-lint-override.rs @@ -10,8 +10,8 @@ extern fn foo() {} -//[warn_deny]~^ ERROR extern declarations without an explicit ABI are deprecated -//[forbid_warn]~^^ ERROR extern declarations without an explicit ABI are deprecated -//[force_warn_deny]~^^^ WARN extern declarations without an explicit ABI are deprecated +//[warn_deny]~^ ERROR `extern` declarations without an explicit ABI are deprecated +//[forbid_warn]~^^ ERROR `extern` declarations without an explicit ABI are deprecated +//[force_warn_deny]~^^^ WARN `extern` declarations without an explicit ABI are deprecated fn main() {} diff --git a/tests/ui/lint/cli-lint-override.warn_deny.stderr b/tests/ui/lint/cli-lint-override.warn_deny.stderr index 979ca22324f1..91baad1f9f87 100644 --- a/tests/ui/lint/cli-lint-override.warn_deny.stderr +++ b/tests/ui/lint/cli-lint-override.warn_deny.stderr @@ -1,4 +1,4 @@ -error: extern declarations without an explicit ABI are deprecated +error: `extern` declarations without an explicit ABI are deprecated --> $DIR/cli-lint-override.rs:12:1 | LL | extern fn foo() {} diff --git a/tests/ui/lint/cli-unknown-force-warn.rs b/tests/ui/lint/cli-unknown-force-warn.rs index 330d5570e21b..0c60f48c5142 100644 --- a/tests/ui/lint/cli-unknown-force-warn.rs +++ b/tests/ui/lint/cli-unknown-force-warn.rs @@ -3,12 +3,12 @@ //@ check-pass //@ compile-flags: --force-warn foo-qux - -//@ error-pattern: requested on the command line with `--force-warn foo_qux` -//@ error-pattern: `#[warn(unknown_lints)]` on by default +//@ dont-require-annotations: NOTE fn main() {} //~? WARN unknown lint: `foo_qux` //~? WARN unknown lint: `foo_qux` //~? WARN unknown lint: `foo_qux` +//~? NOTE requested on the command line with `--force-warn foo_qux` +//~? NOTE `#[warn(unknown_lints)]` on by default diff --git a/tests/ui/lint/dead-code/self-assign.rs b/tests/ui/lint/dead-code/self-assign.rs index 072a899e1bdb..357846baf221 100644 --- a/tests/ui/lint/dead-code/self-assign.rs +++ b/tests/ui/lint/dead-code/self-assign.rs @@ -1,19 +1,29 @@ -// Test that dead code warnings are issued for superfluous assignments of -// fields or variables to themselves (issue #75356). - -//@ ignore-test FIXME(81658, 83171) +//! Test that dead code warnings are issued for superfluous assignments of fields or variables to +//! themselves (issue #75356). +//! +//! # History of this test (to aid relanding of a fixed version of #81473) +//! +//! - Original lint request was about self-assignments not triggering sth like `dead_code`. +//! - `dead_code` lint expansion for self-assignments was implemented in #87129. +//! - Unfortunately implementation components of #87129 had to be disabled as part of reverts +//! #86212, #83171 (to revert #81473) to address regressions #81626 and #81658. +//! - Consequently, none of the following warnings are emitted. //@ check-pass + +// Implementation of self-assignment `dead_code` lint expansions disabled due to reverts. +//@ known-bug: #75356 + #![allow(unused_assignments)] #![warn(dead_code)] fn main() { let mut x = 0; x = x; - //~^ WARNING: useless assignment of variable of type `i32` to itself + // FIXME ~^ WARNING: useless assignment of variable of type `i32` to itself x = (x); - //~^ WARNING: useless assignment of variable of type `i32` to itself + // FIXME ~^ WARNING: useless assignment of variable of type `i32` to itself x = {x}; // block expressions don't count as self-assignments @@ -22,10 +32,10 @@ fn main() { struct S<'a> { f: &'a str } let mut s = S { f: "abc" }; s = s; - //~^ WARNING: useless assignment of variable of type `S` to itself + // FIXME ~^ WARNING: useless assignment of variable of type `S` to itself s.f = s.f; - //~^ WARNING: useless assignment of field of type `&str` to itself + // FIXME ~^ WARNING: useless assignment of field of type `&str` to itself struct N0 { x: Box } @@ -34,11 +44,11 @@ fn main() { struct N3 { n: N2 }; let mut n3 = N3 { n: N2(N1 { n: N0 { x: Box::new(42) } }) }; n3.n.0.n.x = n3.n.0.n.x; - //~^ WARNING: useless assignment of field of type `Box` to itself + // FIXME ~^ WARNING: useless assignment of field of type `Box` to itself let mut t = (1, ((2, 3, (4, 5)),)); t.1.0.2.1 = t.1.0.2.1; - //~^ WARNING: useless assignment of field of type `i32` to itself + // FIXME ~^ WARNING: useless assignment of field of type `i32` to itself let mut y = 0; diff --git a/tests/ui/lint/dead-code/self-assign.stderr b/tests/ui/lint/dead-code/self-assign.stderr deleted file mode 100644 index bb79c0ec72a3..000000000000 --- a/tests/ui/lint/dead-code/self-assign.stderr +++ /dev/null @@ -1,44 +0,0 @@ -warning: useless assignment of variable of type `i32` to itself - --> $DIR/self-assign.rs:10:5 - | -LL | x = x; - | ^^^^^ - | -note: the lint level is defined here - --> $DIR/self-assign.rs:6:9 - | -LL | #![warn(dead_code)] - | ^^^^^^^^^ - -warning: useless assignment of variable of type `i32` to itself - --> $DIR/self-assign.rs:13:5 - | -LL | x = (x); - | ^^^^^^^ - -warning: useless assignment of variable of type `S` to itself - --> $DIR/self-assign.rs:22:5 - | -LL | s = s; - | ^^^^^ - -warning: useless assignment of field of type `&str` to itself - --> $DIR/self-assign.rs:25:5 - | -LL | s.f = s.f; - | ^^^^^^^^^ - -warning: useless assignment of field of type `Box` to itself - --> $DIR/self-assign.rs:34:5 - | -LL | n3.n.0.n.x = n3.n.0.n.x; - | ^^^^^^^^^^^^^^^^^^^^^^^ - -warning: useless assignment of field of type `i32` to itself - --> $DIR/self-assign.rs:38:5 - | -LL | t.1.0.2.1 = t.1.0.2.1; - | ^^^^^^^^^^^^^^^^^^^^^ - -warning: 6 warnings emitted - diff --git a/tests/ui/lint/expansion-time-include.rs b/tests/ui/lint/expansion-time-include.rs index 3ecc01b045c4..cbe3510f04ae 100644 --- a/tests/ui/lint/expansion-time-include.rs +++ b/tests/ui/lint/expansion-time-include.rs @@ -1,4 +1,4 @@ -//@ ignore-test auxiliary file for expansion-time.rs +//@ ignore-auxiliary (used by `./expansion-time.rs`) 1 2 diff --git a/tests/ui/lint/inert-attr-macro.rs b/tests/ui/lint/inert-attr-macro.rs index 5d4133d6c774..f2d50e30aecc 100644 --- a/tests/ui/lint/inert-attr-macro.rs +++ b/tests/ui/lint/inert-attr-macro.rs @@ -1,6 +1,5 @@ //@ check-pass -#![feature(cfg_boolean_literals)] #![warn(unused)] macro_rules! foo { diff --git a/tests/ui/lint/inert-attr-macro.stderr b/tests/ui/lint/inert-attr-macro.stderr index b85b0319e712..5ccb4ffe7929 100644 --- a/tests/ui/lint/inert-attr-macro.stderr +++ b/tests/ui/lint/inert-attr-macro.stderr @@ -1,41 +1,41 @@ warning: unused attribute `inline` - --> $DIR/inert-attr-macro.rs:11:5 + --> $DIR/inert-attr-macro.rs:10:5 | LL | #[inline] foo!(); | ^^^^^^^^^ | note: the built-in attribute `inline` will be ignored, since it's applied to the macro invocation `foo` - --> $DIR/inert-attr-macro.rs:11:15 + --> $DIR/inert-attr-macro.rs:10:15 | LL | #[inline] foo!(); | ^^^ note: the lint level is defined here - --> $DIR/inert-attr-macro.rs:4:9 + --> $DIR/inert-attr-macro.rs:3:9 | LL | #![warn(unused)] | ^^^^^^ = note: `#[warn(unused_attributes)]` implied by `#[warn(unused)]` warning: unused attribute `allow` - --> $DIR/inert-attr-macro.rs:15:5 + --> $DIR/inert-attr-macro.rs:14:5 | LL | #[allow(warnings)] #[inline] foo!(); | ^^^^^^^^^^^^^^^^^^ | note: the built-in attribute `allow` will be ignored, since it's applied to the macro invocation `foo` - --> $DIR/inert-attr-macro.rs:15:34 + --> $DIR/inert-attr-macro.rs:14:34 | LL | #[allow(warnings)] #[inline] foo!(); | ^^^ warning: unused attribute `inline` - --> $DIR/inert-attr-macro.rs:15:24 + --> $DIR/inert-attr-macro.rs:14:24 | LL | #[allow(warnings)] #[inline] foo!(); | ^^^^^^^^^ | note: the built-in attribute `inline` will be ignored, since it's applied to the macro invocation `foo` - --> $DIR/inert-attr-macro.rs:15:34 + --> $DIR/inert-attr-macro.rs:14:34 | LL | #[allow(warnings)] #[inline] foo!(); | ^^^ diff --git a/tests/ui/lint/internal_features.rs b/tests/ui/lint/internal_features.rs index 32ce9540cb36..6456078a5c2f 100644 --- a/tests/ui/lint/internal_features.rs +++ b/tests/ui/lint/internal_features.rs @@ -4,8 +4,7 @@ //~^ ERROR: internal //~| ERROR: internal -extern "rust-intrinsic" { - fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize); -} +#[rustc_intrinsic] +unsafe fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize); fn main() {} diff --git a/tests/ui/lint/known-tool-in-submodule/submodule.rs b/tests/ui/lint/known-tool-in-submodule/submodule.rs index 0bb2b93d53b7..9c24964e94f9 100644 --- a/tests/ui/lint/known-tool-in-submodule/submodule.rs +++ b/tests/ui/lint/known-tool-in-submodule/submodule.rs @@ -1,4 +1,4 @@ -//@ ignore-test: not a test +//@ ignore-auxiliary (used by `./root.rs`) #[allow(tool::lint)] pub fn foo() {} diff --git a/tests/ui/lint/large_assignments/inline_mir.rs b/tests/ui/lint/large_assignments/inline_mir.rs new file mode 100644 index 000000000000..fc27b8ff244d --- /dev/null +++ b/tests/ui/lint/large_assignments/inline_mir.rs @@ -0,0 +1,24 @@ +#![feature(large_assignments)] +#![deny(large_assignments)] +#![move_size_limit = "1000"] + +//! Tests that with `-Zinline-mir`, we do NOT get an error that points to the +//! implementation of `UnsafeCell` since that is not actionable by the user: +//! +//! ```text +//! error: moving 9999 bytes +//! --> /rustc/FAKE_PREFIX/library/core/src/cell.rs:2054:9 +//! | +//! = note: value moved from here +//! ``` +//! +//! We want the diagnostics to point to the relevant user code. + +//@ build-fail +//@ compile-flags: -Zmir-opt-level=1 -Zinline-mir + +pub fn main() { + let data = [10u8; 9999]; + let cell = std::cell::UnsafeCell::new(data); //~ ERROR large_assignments + std::hint::black_box(cell); +} diff --git a/tests/ui/lint/large_assignments/inline_mir.stderr b/tests/ui/lint/large_assignments/inline_mir.stderr new file mode 100644 index 000000000000..d9010e24d03b --- /dev/null +++ b/tests/ui/lint/large_assignments/inline_mir.stderr @@ -0,0 +1,15 @@ +error: moving 9999 bytes + --> $DIR/inline_mir.rs:22:16 + | +LL | let cell = std::cell::UnsafeCell::new(data); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ value moved from here + | + = note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]` +note: the lint level is defined here + --> $DIR/inline_mir.rs:2:9 + | +LL | #![deny(large_assignments)] + | ^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/lint/lint-attr-everywhere-early.rs b/tests/ui/lint/lint-attr-everywhere-early.rs index ae32ec426f23..7ca127d066f5 100644 --- a/tests/ui/lint/lint-attr-everywhere-early.rs +++ b/tests/ui/lint/lint-attr-everywhere-early.rs @@ -40,7 +40,7 @@ struct Associated; impl Associated { #![deny(unsafe_code)] - fn inherent_denied_from_inner() { unsafe {} } //~ usage of an `unsafe` block + fn inherent_denied_from_inner() { unsafe {} } //~ ERROR usage of an `unsafe` block #[deny(while_true)] fn inherent_fn() { while true {} } //~ ERROR denote infinite loops with diff --git a/tests/ui/lint/lint-removed-cmdline-deny.rs b/tests/ui/lint/lint-removed-cmdline-deny.rs index 6616781d5cb7..83bbd248aa0c 100644 --- a/tests/ui/lint/lint-removed-cmdline-deny.rs +++ b/tests/ui/lint/lint-removed-cmdline-deny.rs @@ -2,9 +2,7 @@ // cc #30346 //@ compile-flags:-D renamed-and-removed-lints -D raw_pointer_derive - -//@ error-pattern:requested on the command line with `-D raw_pointer_derive` -//@ error-pattern:requested on the command line with `-D renamed-and-removed-lints` +//@ dont-require-annotations: NOTE #![warn(unused)] @@ -14,3 +12,5 @@ fn main() { let unused = (); } //~ ERROR unused variable: `unused` //~? ERROR lint `raw_pointer_derive` has been removed: using derive with raw pointers is ok //~? ERROR lint `raw_pointer_derive` has been removed: using derive with raw pointers is ok //~? ERROR lint `raw_pointer_derive` has been removed: using derive with raw pointers is ok +//~? NOTE requested on the command line with `-D raw_pointer_derive` +//~? NOTE requested on the command line with `-D renamed-and-removed-lints` diff --git a/tests/ui/lint/lint-removed-cmdline-deny.stderr b/tests/ui/lint/lint-removed-cmdline-deny.stderr index 27a3504a16a7..2fb237339cd8 100644 --- a/tests/ui/lint/lint-removed-cmdline-deny.stderr +++ b/tests/ui/lint/lint-removed-cmdline-deny.stderr @@ -14,13 +14,13 @@ error: lint `raw_pointer_derive` has been removed: using derive with raw pointer = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: unused variable: `unused` - --> $DIR/lint-removed-cmdline-deny.rs:12:17 + --> $DIR/lint-removed-cmdline-deny.rs:10:17 | LL | fn main() { let unused = (); } | ^^^^^^ help: if this is intentional, prefix it with an underscore: `_unused` | note: the lint level is defined here - --> $DIR/lint-removed-cmdline-deny.rs:11:8 + --> $DIR/lint-removed-cmdline-deny.rs:9:8 | LL | #[deny(warnings)] | ^^^^^^^^ diff --git a/tests/ui/lint/lint-removed-cmdline.rs b/tests/ui/lint/lint-removed-cmdline.rs index 4dde3dbc3817..f83747a3a6be 100644 --- a/tests/ui/lint/lint-removed-cmdline.rs +++ b/tests/ui/lint/lint-removed-cmdline.rs @@ -2,9 +2,7 @@ // cc #30346 //@ compile-flags:-D raw_pointer_derive - -//@ error-pattern:`#[warn(renamed_and_removed_lints)]` on by default -//@ error-pattern:requested on the command line with `-D raw_pointer_derive` +//@ dont-require-annotations: NOTE #![warn(unused)] @@ -14,3 +12,5 @@ fn main() { let unused = (); } //~ ERROR unused variable: `unused` //~? WARN lint `raw_pointer_derive` has been removed: using derive with raw pointers is ok //~? WARN lint `raw_pointer_derive` has been removed: using derive with raw pointers is ok //~? WARN lint `raw_pointer_derive` has been removed: using derive with raw pointers is ok +//~? NOTE `#[warn(renamed_and_removed_lints)]` on by default +//~? NOTE requested on the command line with `-D raw_pointer_derive` diff --git a/tests/ui/lint/lint-removed-cmdline.stderr b/tests/ui/lint/lint-removed-cmdline.stderr index 7994f9bcfd91..64e7c572ca73 100644 --- a/tests/ui/lint/lint-removed-cmdline.stderr +++ b/tests/ui/lint/lint-removed-cmdline.stderr @@ -14,13 +14,13 @@ warning: lint `raw_pointer_derive` has been removed: using derive with raw point = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: unused variable: `unused` - --> $DIR/lint-removed-cmdline.rs:12:17 + --> $DIR/lint-removed-cmdline.rs:10:17 | LL | fn main() { let unused = (); } | ^^^^^^ help: if this is intentional, prefix it with an underscore: `_unused` | note: the lint level is defined here - --> $DIR/lint-removed-cmdline.rs:11:8 + --> $DIR/lint-removed-cmdline.rs:9:8 | LL | #[deny(warnings)] | ^^^^^^^^ diff --git a/tests/ui/lint/lint-renamed-cmdline-deny.rs b/tests/ui/lint/lint-renamed-cmdline-deny.rs index 0ea4ce408175..c8b035078154 100644 --- a/tests/ui/lint/lint-renamed-cmdline-deny.rs +++ b/tests/ui/lint/lint-renamed-cmdline-deny.rs @@ -1,8 +1,6 @@ //@ compile-flags:-D renamed-and-removed-lints -D bare_trait_object - -//@ error-pattern:use the new name `bare_trait_objects` -//@ error-pattern:requested on the command line with `-D bare_trait_object` -//@ error-pattern:requested on the command line with `-D renamed-and-removed-lints` +//@ dont-require-annotations: HELP +//@ dont-require-annotations: NOTE #[deny(unused)] fn main() { let unused = (); } //~ ERROR unused variable: `unused` @@ -10,3 +8,6 @@ fn main() { let unused = (); } //~ ERROR unused variable: `unused` //~? ERROR lint `bare_trait_object` has been renamed to `bare_trait_objects` //~? ERROR lint `bare_trait_object` has been renamed to `bare_trait_objects` //~? ERROR lint `bare_trait_object` has been renamed to `bare_trait_objects` +//~? HELP use the new name `bare_trait_objects` +//~? NOTE requested on the command line with `-D bare_trait_object` +//~? NOTE requested on the command line with `-D renamed-and-removed-lints` diff --git a/tests/ui/lint/lint-renamed-cmdline-deny.stderr b/tests/ui/lint/lint-renamed-cmdline-deny.stderr index a49cdc84f9e4..b42b82834c19 100644 --- a/tests/ui/lint/lint-renamed-cmdline-deny.stderr +++ b/tests/ui/lint/lint-renamed-cmdline-deny.stderr @@ -17,13 +17,13 @@ error: lint `bare_trait_object` has been renamed to `bare_trait_objects` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: unused variable: `unused` - --> $DIR/lint-renamed-cmdline-deny.rs:8:17 + --> $DIR/lint-renamed-cmdline-deny.rs:6:17 | LL | fn main() { let unused = (); } | ^^^^^^ help: if this is intentional, prefix it with an underscore: `_unused` | note: the lint level is defined here - --> $DIR/lint-renamed-cmdline-deny.rs:7:8 + --> $DIR/lint-renamed-cmdline-deny.rs:5:8 | LL | #[deny(unused)] | ^^^^^^ diff --git a/tests/ui/lint/lint-renamed-cmdline.rs b/tests/ui/lint/lint-renamed-cmdline.rs index 45df7b6d640d..757cb514267c 100644 --- a/tests/ui/lint/lint-renamed-cmdline.rs +++ b/tests/ui/lint/lint-renamed-cmdline.rs @@ -1,7 +1,5 @@ //@ compile-flags:-D bare_trait_object - -//@ error-pattern:requested on the command line with `-D bare_trait_object` -//@ error-pattern:`#[warn(renamed_and_removed_lints)]` on by default +//@ dont-require-annotations: NOTE #[deny(unused)] fn main() { let unused = (); } //~ ERROR unused variable: `unused` @@ -9,3 +7,5 @@ fn main() { let unused = (); } //~ ERROR unused variable: `unused` //~? WARN lint `bare_trait_object` has been renamed to `bare_trait_objects` //~? WARN lint `bare_trait_object` has been renamed to `bare_trait_objects` //~? WARN lint `bare_trait_object` has been renamed to `bare_trait_objects` +//~? NOTE requested on the command line with `-D bare_trait_object` +//~? NOTE `#[warn(renamed_and_removed_lints)]` on by default diff --git a/tests/ui/lint/lint-renamed-cmdline.stderr b/tests/ui/lint/lint-renamed-cmdline.stderr index 901e7a642d1f..efd399e21694 100644 --- a/tests/ui/lint/lint-renamed-cmdline.stderr +++ b/tests/ui/lint/lint-renamed-cmdline.stderr @@ -17,13 +17,13 @@ warning: lint `bare_trait_object` has been renamed to `bare_trait_objects` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: unused variable: `unused` - --> $DIR/lint-renamed-cmdline.rs:7:17 + --> $DIR/lint-renamed-cmdline.rs:5:17 | LL | fn main() { let unused = (); } | ^^^^^^ help: if this is intentional, prefix it with an underscore: `_unused` | note: the lint level is defined here - --> $DIR/lint-renamed-cmdline.rs:6:8 + --> $DIR/lint-renamed-cmdline.rs:4:8 | LL | #[deny(unused)] | ^^^^^^ diff --git a/tests/ui/lint/lint-unknown-lint-cmdline-deny.rs b/tests/ui/lint/lint-unknown-lint-cmdline-deny.rs index e2f7c73eacf0..ac001e1b6a04 100644 --- a/tests/ui/lint/lint-unknown-lint-cmdline-deny.rs +++ b/tests/ui/lint/lint-unknown-lint-cmdline-deny.rs @@ -1,9 +1,6 @@ //@ compile-flags:-D unknown-lints -D bogus -D dead_cod - -//@ error-pattern:requested on the command line with `-D bogus` -//@ error-pattern:requested on the command line with `-D dead_cod` -//@ error-pattern:requested on the command line with `-D unknown-lints` -//@ error-pattern:did you mean: `dead_code` +//@ dont-require-annotations: HELP +//@ dont-require-annotations: NOTE fn main() { } @@ -13,3 +10,7 @@ fn main() { } //~? ERROR unknown lint: `dead_cod` //~? ERROR unknown lint: `bogus` //~? ERROR unknown lint: `dead_cod` +//~? NOTE requested on the command line with `-D bogus` +//~? NOTE requested on the command line with `-D dead_cod` +//~? NOTE requested on the command line with `-D unknown-lints` +//~? HELP did you mean: `dead_code` diff --git a/tests/ui/lint/lint-unknown-lint-cmdline.rs b/tests/ui/lint/lint-unknown-lint-cmdline.rs index 931e945a1a32..7eb8c1f73142 100644 --- a/tests/ui/lint/lint-unknown-lint-cmdline.rs +++ b/tests/ui/lint/lint-unknown-lint-cmdline.rs @@ -1,10 +1,7 @@ //@ check-pass //@ compile-flags:-D bogus -D dead_cod - -//@ error-pattern:requested on the command line with `-D bogus` -//@ error-pattern:`#[warn(unknown_lints)]` on by default -//@ error-pattern:requested on the command line with `-D dead_cod` -//@ error-pattern:did you mean: `dead_code` +//@ dont-require-annotations: HELP +//@ dont-require-annotations: NOTE fn main() { } @@ -14,3 +11,7 @@ fn main() { } //~? WARN unknown lint: `dead_cod` //~? WARN unknown lint: `bogus` //~? WARN unknown lint: `dead_cod` +//~? NOTE requested on the command line with `-D bogus` +//~? NOTE `#[warn(unknown_lints)]` on by default +//~? NOTE requested on the command line with `-D dead_cod` +//~? HELP did you mean: `dead_code` diff --git a/tests/ui/lint/lint_pre_expansion_extern_module_aux.rs b/tests/ui/lint/lint_pre_expansion_extern_module_aux.rs index 6e16a796ff19..10e3c0f95644 100644 --- a/tests/ui/lint/lint_pre_expansion_extern_module_aux.rs +++ b/tests/ui/lint/lint_pre_expansion_extern_module_aux.rs @@ -1,3 +1,3 @@ -//@ ignore-test: not a test +//@ ignore-auxiliary (used by `./lint-pre-expansion-extern-module.rs`) pub fn try() {} diff --git a/tests/ui/lint/lints-in-foreign-macros.rs b/tests/ui/lint/lints-in-foreign-macros.rs index 49e83bae6421..31b59f4943a5 100644 --- a/tests/ui/lint/lints-in-foreign-macros.rs +++ b/tests/ui/lint/lints-in-foreign-macros.rs @@ -1,7 +1,7 @@ //@ aux-build:lints-in-foreign-macros.rs //@ check-pass -#![warn(unused_imports)] //~ missing documentation for the crate [missing_docs] +#![warn(unused_imports)] //~ WARN missing documentation for the crate [missing_docs] #![warn(missing_docs)] #[macro_use] diff --git a/tests/ui/lint/non-local-defs/cargo-update.rs b/tests/ui/lint/non-local-defs/cargo-update.rs index 8b8c15795d37..f778752b28af 100644 --- a/tests/ui/lint/non-local-defs/cargo-update.rs +++ b/tests/ui/lint/non-local-defs/cargo-update.rs @@ -8,7 +8,7 @@ // // and since we specifically want to check the presence // of the `cargo update` suggestion we assert it here. -//@ error-pattern: `cargo update -p non_local_macro` +//@ dont-require-annotations: NOTE extern crate non_local_macro; @@ -16,5 +16,6 @@ struct LocalStruct; non_local_macro::non_local_impl!(LocalStruct); //~^ WARN non-local `impl` definition +//~| NOTE `cargo update -p non_local_macro` fn main() {} diff --git a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.cdylib_.stderr b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.cdylib_.stderr index 1192b690e29c..a9c018867442 100644 --- a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.cdylib_.stderr +++ b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.cdylib_.stderr @@ -1,11 +1,11 @@ error: crate `NonSnakeCase` should have a snake case name - --> $DIR/lint-non-snake-case-crate.rs:36:18 + --> $DIR/lint-non-snake-case-crate.rs:35:18 | LL | #![crate_name = "NonSnakeCase"] | ^^^^^^^^^^^^ help: convert the identifier to snake case: `non_snake_case` | note: the lint level is defined here - --> $DIR/lint-non-snake-case-crate.rs:38:9 + --> $DIR/lint-non-snake-case-crate.rs:37:9 | LL | #![deny(non_snake_case)] | ^^^^^^^^^^^^^^ diff --git a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.dylib_.stderr b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.dylib_.stderr index 1192b690e29c..a9c018867442 100644 --- a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.dylib_.stderr +++ b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.dylib_.stderr @@ -1,11 +1,11 @@ error: crate `NonSnakeCase` should have a snake case name - --> $DIR/lint-non-snake-case-crate.rs:36:18 + --> $DIR/lint-non-snake-case-crate.rs:35:18 | LL | #![crate_name = "NonSnakeCase"] | ^^^^^^^^^^^^ help: convert the identifier to snake case: `non_snake_case` | note: the lint level is defined here - --> $DIR/lint-non-snake-case-crate.rs:38:9 + --> $DIR/lint-non-snake-case-crate.rs:37:9 | LL | #![deny(non_snake_case)] | ^^^^^^^^^^^^^^ diff --git a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.lib_.stderr b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.lib_.stderr index 1192b690e29c..a9c018867442 100644 --- a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.lib_.stderr +++ b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.lib_.stderr @@ -1,11 +1,11 @@ error: crate `NonSnakeCase` should have a snake case name - --> $DIR/lint-non-snake-case-crate.rs:36:18 + --> $DIR/lint-non-snake-case-crate.rs:35:18 | LL | #![crate_name = "NonSnakeCase"] | ^^^^^^^^^^^^ help: convert the identifier to snake case: `non_snake_case` | note: the lint level is defined here - --> $DIR/lint-non-snake-case-crate.rs:38:9 + --> $DIR/lint-non-snake-case-crate.rs:37:9 | LL | #![deny(non_snake_case)] | ^^^^^^^^^^^^^^ diff --git a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.proc_macro_.stderr b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.proc_macro_.stderr index 1192b690e29c..a9c018867442 100644 --- a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.proc_macro_.stderr +++ b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.proc_macro_.stderr @@ -1,11 +1,11 @@ error: crate `NonSnakeCase` should have a snake case name - --> $DIR/lint-non-snake-case-crate.rs:36:18 + --> $DIR/lint-non-snake-case-crate.rs:35:18 | LL | #![crate_name = "NonSnakeCase"] | ^^^^^^^^^^^^ help: convert the identifier to snake case: `non_snake_case` | note: the lint level is defined here - --> $DIR/lint-non-snake-case-crate.rs:38:9 + --> $DIR/lint-non-snake-case-crate.rs:37:9 | LL | #![deny(non_snake_case)] | ^^^^^^^^^^^^^^ diff --git a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.rlib_.stderr b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.rlib_.stderr index 1192b690e29c..a9c018867442 100644 --- a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.rlib_.stderr +++ b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.rlib_.stderr @@ -1,11 +1,11 @@ error: crate `NonSnakeCase` should have a snake case name - --> $DIR/lint-non-snake-case-crate.rs:36:18 + --> $DIR/lint-non-snake-case-crate.rs:35:18 | LL | #![crate_name = "NonSnakeCase"] | ^^^^^^^^^^^^ help: convert the identifier to snake case: `non_snake_case` | note: the lint level is defined here - --> $DIR/lint-non-snake-case-crate.rs:38:9 + --> $DIR/lint-non-snake-case-crate.rs:37:9 | LL | #![deny(non_snake_case)] | ^^^^^^^^^^^^^^ diff --git a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.rs b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.rs index 6f701cd27c62..a63e9c5ddf24 100644 --- a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.rs +++ b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.rs @@ -10,28 +10,27 @@ // But should fire on non-binary crates. -// FIXME(#132309): dylib crate type is not supported on wasm; we need a proper -// supports-crate-type directive. Also, needs-dynamic-linking should rule out -// musl since it supports neither dylibs nor cdylibs. -//@[dylib_] ignore-wasm -//@[dylib_] ignore-musl -//@[cdylib_] ignore-musl - -//@[dylib_] needs-dynamic-linking +//@[cdylib_] compile-flags: --crate-type=cdylib //@[cdylib_] needs-dynamic-linking +//@[cdylib_] needs-crate-type: cdylib + +//@[dylib_] compile-flags: --crate-type=dylib +//@[dylib_] needs-dynamic-linking +//@[dylib_] needs-crate-type: dylib + +//@[lib_] compile-flags: --crate-type=lib + //@[proc_macro_] force-host //@[proc_macro_] no-prefer-dynamic - -//@[cdylib_] compile-flags: --crate-type=cdylib -//@[dylib_] compile-flags: --crate-type=dylib -//@[lib_] compile-flags: --crate-type=lib //@[proc_macro_] compile-flags: --crate-type=proc-macro -//@[rlib_] compile-flags: --crate-type=rlib -//@[staticlib_] compile-flags: --crate-type=staticlib - -// The compiler may emit a warning that causes stderr output -// that contains a warning this test does not wish to check. +// The compiler may emit a warning that causes stderr output that contains a warning this test does +// not wish to check. //@[proc_macro_] needs-unwind +//@[proc_macro_] needs-crate-type: proc-macro + +//@[rlib_] compile-flags: --crate-type=rlib + +//@[staticlib_] compile-flags: --crate-type=staticlib #![crate_name = "NonSnakeCase"] //[cdylib_,dylib_,lib_,proc_macro_,rlib_,staticlib_]~^ ERROR crate `NonSnakeCase` should have a snake case name diff --git a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.staticlib_.stderr b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.staticlib_.stderr index 1192b690e29c..a9c018867442 100644 --- a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.staticlib_.stderr +++ b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.staticlib_.stderr @@ -1,11 +1,11 @@ error: crate `NonSnakeCase` should have a snake case name - --> $DIR/lint-non-snake-case-crate.rs:36:18 + --> $DIR/lint-non-snake-case-crate.rs:35:18 | LL | #![crate_name = "NonSnakeCase"] | ^^^^^^^^^^^^ help: convert the identifier to snake case: `non_snake_case` | note: the lint level is defined here - --> $DIR/lint-non-snake-case-crate.rs:38:9 + --> $DIR/lint-non-snake-case-crate.rs:37:9 | LL | #![deny(non_snake_case)] | ^^^^^^^^^^^^^^ diff --git a/tests/ui/lint/removed-lints/undefined_naked_function_abi.rs b/tests/ui/lint/removed-lints/undefined_naked_function_abi.rs new file mode 100644 index 000000000000..cf3ac66ac86d --- /dev/null +++ b/tests/ui/lint/removed-lints/undefined_naked_function_abi.rs @@ -0,0 +1,5 @@ +//@ check-pass + +#![deny(undefined_naked_function_abi)] +//~^ WARN lint `undefined_naked_function_abi` has been removed +fn main() {} diff --git a/tests/ui/lint/removed-lints/undefined_naked_function_abi.stderr b/tests/ui/lint/removed-lints/undefined_naked_function_abi.stderr new file mode 100644 index 000000000000..5a546688beb5 --- /dev/null +++ b/tests/ui/lint/removed-lints/undefined_naked_function_abi.stderr @@ -0,0 +1,10 @@ +warning: lint `undefined_naked_function_abi` has been removed: converted into hard error, see PR #139001 for more information + --> $DIR/undefined_naked_function_abi.rs:3:9 + | +LL | #![deny(undefined_naked_function_abi)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(renamed_and_removed_lints)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/lint/rfc-2383-lint-reason/no_ice_for_partial_compiler_runs.rs b/tests/ui/lint/rfc-2383-lint-reason/no_ice_for_partial_compiler_runs.rs index 9e38b94b76ce..11ee2bc852ab 100644 --- a/tests/ui/lint/rfc-2383-lint-reason/no_ice_for_partial_compiler_runs.rs +++ b/tests/ui/lint/rfc-2383-lint-reason/no_ice_for_partial_compiler_runs.rs @@ -1,6 +1,7 @@ // This ensures that ICEs like rust#94953 don't happen //@ check-pass //@ compile-flags: -Z unpretty=expanded +//@ edition: 2015 // This `expect` will create an expectation with an unstable expectation id #[expect(while_true)] diff --git a/tests/ui/lint/rfc-2383-lint-reason/no_ice_for_partial_compiler_runs.stdout b/tests/ui/lint/rfc-2383-lint-reason/no_ice_for_partial_compiler_runs.stdout index d804c1d2d200..d63abea92302 100644 --- a/tests/ui/lint/rfc-2383-lint-reason/no_ice_for_partial_compiler_runs.stdout +++ b/tests/ui/lint/rfc-2383-lint-reason/no_ice_for_partial_compiler_runs.stdout @@ -7,6 +7,7 @@ extern crate std; // This ensures that ICEs like rust#94953 don't happen //@ check-pass //@ compile-flags: -Z unpretty=expanded +//@ edition: 2015 // This `expect` will create an expectation with an unstable expectation id #[expect(while_true)] diff --git a/tests/ui/lint/rfc-2457-non-ascii-idents/lint-uncommon-codepoints.rs b/tests/ui/lint/rfc-2457-non-ascii-idents/lint-uncommon-codepoints.rs index a51452f06959..787b8999a106 100644 --- a/tests/ui/lint/rfc-2457-non-ascii-idents/lint-uncommon-codepoints.rs +++ b/tests/ui/lint/rfc-2457-non-ascii-idents/lint-uncommon-codepoints.rs @@ -1,6 +1,6 @@ #![deny(uncommon_codepoints)] -const µ: f64 = 0.000001; //~ identifier contains a non normalized (NFKC) character: 'µ' +const µ: f64 = 0.000001; //~ ERROR identifier contains a non normalized (NFKC) character: 'µ' //~| WARNING should have an upper case name fn dijkstra() {} diff --git a/tests/ui/lint/unknown-lints/other.rs b/tests/ui/lint/unknown-lints/other.rs index f917bff6d602..7770bc59108d 100644 --- a/tests/ui/lint/unknown-lints/other.rs +++ b/tests/ui/lint/unknown-lints/other.rs @@ -1,6 +1,4 @@ -//@ ignore-test - -// Companion to allow-in-other-module.rs +//@ ignore-auxiliary (used by `./allow-in-other-module.rs`) // This should not warn. #![allow(not_a_real_lint)] diff --git a/tests/ui/lint/unqualified_local_imports.rs b/tests/ui/lint/unqualified_local_imports.rs index 9de71471342d..b7036f9c68ea 100644 --- a/tests/ui/lint/unqualified_local_imports.rs +++ b/tests/ui/lint/unqualified_local_imports.rs @@ -1,4 +1,4 @@ -//@compile-flags: --edition 2018 +//@ edition: 2018 #![feature(unqualified_local_imports)] #![deny(unqualified_local_imports)] diff --git a/tests/ui/lint/unused-borrows.rs b/tests/ui/lint/unused-borrows.rs index 4518522ae00f..07d783382fae 100644 --- a/tests/ui/lint/unused-borrows.rs +++ b/tests/ui/lint/unused-borrows.rs @@ -4,24 +4,24 @@ fn foo(_: i32) -> bool { todo!() } fn bar() -> &'static i32 { &42; - //~^ unused + //~^ ERROR unused &mut foo(42); - //~^ unused + //~^ ERROR unused &&42; - //~^ unused + //~^ ERROR unused &&mut 42; - //~^ unused + //~^ ERROR unused &mut &42; - //~^ unused + //~^ ERROR unused let _result = foo(4) && foo(2); // Misplaced semi-colon (perhaps due to reordering of lines) && foo(42); - //~^ unused + //~^ ERROR unused let _ = &42; // ok diff --git a/tests/ui/lint/unused/issue-70041.rs b/tests/ui/lint/unused/issue-70041.rs index 817dfe821149..890ba378263b 100644 --- a/tests/ui/lint/unused/issue-70041.rs +++ b/tests/ui/lint/unused/issue-70041.rs @@ -1,4 +1,4 @@ -//@ compile-flags: --edition=2018 +//@ edition: 2018 //@ run-pass macro_rules! regex { diff --git a/tests/ui/lint/unused/must_use-unit.rs b/tests/ui/lint/unused/must_use-unit.rs index 4dd4798abb7c..171ae3257b6c 100644 --- a/tests/ui/lint/unused/must_use-unit.rs +++ b/tests/ui/lint/unused/must_use-unit.rs @@ -10,7 +10,7 @@ fn bar() -> ! { } fn main() { - foo(); //~ unused return value of `foo` + foo(); //~ ERROR unused return value of `foo` - bar(); //~ unused return value of `bar` + bar(); //~ ERROR unused return value of `bar` } diff --git a/tests/ui/lint/unused/unused-attr-macro-rules.rs b/tests/ui/lint/unused/unused-attr-macro-rules.rs index c0fc280ab1a7..7a8a1bb1ae52 100644 --- a/tests/ui/lint/unused/unused-attr-macro-rules.rs +++ b/tests/ui/lint/unused/unused-attr-macro-rules.rs @@ -17,7 +17,7 @@ macro_rules! foo2 { () => {}; } -#[cfg(FALSE)] +#[cfg(false)] macro_rules! foo { () => {}; } diff --git a/tests/ui/lint/unused/useless-comment.rs b/tests/ui/lint/unused/useless-comment.rs index 7d2e5ab6f2b7..4ec52f20747d 100644 --- a/tests/ui/lint/unused/useless-comment.rs +++ b/tests/ui/lint/unused/useless-comment.rs @@ -13,7 +13,7 @@ fn foo() { /// a //~ ERROR unused doc comment let x = 12; - /// multi-line //~ unused doc comment + /// multi-line //~ ERROR unused doc comment /// doc comment /// that is unused match x { diff --git a/tests/ui/lint/wasm_c_abi_transition.rs b/tests/ui/lint/wasm_c_abi_transition.rs index 1fe81679e65d..6a933a0de036 100644 --- a/tests/ui/lint/wasm_c_abi_transition.rs +++ b/tests/ui/lint/wasm_c_abi_transition.rs @@ -39,3 +39,9 @@ pub fn call_other_fun(x: MyType) { unsafe { other_fun(x) } //~ERROR: wasm ABI transition //~^WARN: previously accepted } + +// Zero-sized types are safe in both ABIs +#[repr(C)] +pub struct MyZstType; +#[allow(improper_ctypes_definitions)] +pub extern "C" fn zst_safe(_x: (), _y: MyZstType) {} diff --git a/tests/ui/lto/auxiliary/dwarf-mixed-versions-lto-aux.rs b/tests/ui/lto/auxiliary/dwarf-mixed-versions-lto-aux.rs index 3c81127ee65c..2f2bf57f42b4 100644 --- a/tests/ui/lto/auxiliary/dwarf-mixed-versions-lto-aux.rs +++ b/tests/ui/lto/auxiliary/dwarf-mixed-versions-lto-aux.rs @@ -1,4 +1,4 @@ -//@ compile-flags: -g --crate-type=rlib -Zdwarf-version=4 +//@ compile-flags: -g --crate-type=rlib -Cdwarf-version=4 pub fn say_hi() { println!("hello there") diff --git a/tests/ui/lto/dwarf-mixed-versions-lto.rs b/tests/ui/lto/dwarf-mixed-versions-lto.rs index 14ef65a868e0..900274eb22f4 100644 --- a/tests/ui/lto/dwarf-mixed-versions-lto.rs +++ b/tests/ui/lto/dwarf-mixed-versions-lto.rs @@ -4,7 +4,7 @@ //@ ignore-msvc Platform must use DWARF //@ aux-build:dwarf-mixed-versions-lto-aux.rs -//@ compile-flags: -C lto -g -Zdwarf-version=5 +//@ compile-flags: -C lto -g -Cdwarf-version=5 //@ no-prefer-dynamic //@ build-pass diff --git a/tests/ui/macros/auxiliary/macro-include-items-expr.rs b/tests/ui/macros/auxiliary/macro-include-items-expr.rs index 7394f194b80e..d00491fd7e5b 100644 --- a/tests/ui/macros/auxiliary/macro-include-items-expr.rs +++ b/tests/ui/macros/auxiliary/macro-include-items-expr.rs @@ -1,3 +1 @@ -// ignore-test: this is not a test - 1 diff --git a/tests/ui/macros/auxiliary/macro-include-items-item.rs b/tests/ui/macros/auxiliary/macro-include-items-item.rs index 7d54745e03bf..761cd0021897 100644 --- a/tests/ui/macros/auxiliary/macro-include-items-item.rs +++ b/tests/ui/macros/auxiliary/macro-include-items-item.rs @@ -1,3 +1 @@ -// ignore-test: this is not a test - fn foo() { bar() } diff --git a/tests/ui/macros/expr_2021_cargo_fix_edition.fixed b/tests/ui/macros/expr_2021_cargo_fix_edition.fixed index 061a4b98033c..c0d276093589 100644 --- a/tests/ui/macros/expr_2021_cargo_fix_edition.fixed +++ b/tests/ui/macros/expr_2021_cargo_fix_edition.fixed @@ -1,6 +1,6 @@ //@ run-rustfix //@ check-pass -//@ compile-flags: --edition=2021 +//@ edition: 2021 #![warn(edition_2024_expr_fragment_specifier)] macro_rules! m { diff --git a/tests/ui/macros/expr_2021_cargo_fix_edition.rs b/tests/ui/macros/expr_2021_cargo_fix_edition.rs index cd9cd965fad2..b2c16fc7041c 100644 --- a/tests/ui/macros/expr_2021_cargo_fix_edition.rs +++ b/tests/ui/macros/expr_2021_cargo_fix_edition.rs @@ -1,6 +1,6 @@ //@ run-rustfix //@ check-pass -//@ compile-flags: --edition=2021 +//@ edition: 2021 #![warn(edition_2024_expr_fragment_specifier)] macro_rules! m { diff --git a/tests/ui/macros/failed-to-reparse-issue-139445.rs b/tests/ui/macros/failed-to-reparse-issue-139445.rs new file mode 100644 index 000000000000..babe26b9d293 --- /dev/null +++ b/tests/ui/macros/failed-to-reparse-issue-139445.rs @@ -0,0 +1,6 @@ +fn main() { + assert_eq!(3, 'a,) + //~^ ERROR expected `while`, `for`, `loop` or `{` after a label + //~| ERROR expected `while`, `for`, `loop` or `{` after a label + //~| ERROR expected expression, found `` +} diff --git a/tests/ui/macros/failed-to-reparse-issue-139445.stderr b/tests/ui/macros/failed-to-reparse-issue-139445.stderr new file mode 100644 index 000000000000..6f7d88fb3446 --- /dev/null +++ b/tests/ui/macros/failed-to-reparse-issue-139445.stderr @@ -0,0 +1,24 @@ +error: expected `while`, `for`, `loop` or `{` after a label + --> $DIR/failed-to-reparse-issue-139445.rs:2:21 + | +LL | assert_eq!(3, 'a,) + | ^ expected `while`, `for`, `loop` or `{` after a label + +error: expected `while`, `for`, `loop` or `{` after a label + --> $DIR/failed-to-reparse-issue-139445.rs:2:5 + | +LL | assert_eq!(3, 'a,) + | ^^^^^^^^^^^^^^^^^^ expected `while`, `for`, `loop` or `{` after a label + | + = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: expected expression, found `` + --> $DIR/failed-to-reparse-issue-139445.rs:2:5 + | +LL | assert_eq!(3, 'a,) + | ^^^^^^^^^^^^^^^^^^ expected expression + | + = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 3 previous errors + diff --git a/tests/ui/macros/genercs-in-path-with-prettry-hir.rs b/tests/ui/macros/genercs-in-path-with-prettry-hir.rs index 84370fcebbcb..e6773f610da3 100644 --- a/tests/ui/macros/genercs-in-path-with-prettry-hir.rs +++ b/tests/ui/macros/genercs-in-path-with-prettry-hir.rs @@ -1,4 +1,5 @@ //@ compile-flags: -Zunpretty=hir +//@ edition: 2015 // issue#97006 diff --git a/tests/ui/macros/genercs-in-path-with-prettry-hir.stderr b/tests/ui/macros/genercs-in-path-with-prettry-hir.stderr index 8fcc7c6fbff0..173e77569a80 100644 --- a/tests/ui/macros/genercs-in-path-with-prettry-hir.stderr +++ b/tests/ui/macros/genercs-in-path-with-prettry-hir.stderr @@ -1,5 +1,5 @@ error: unexpected generic arguments in path - --> $DIR/genercs-in-path-with-prettry-hir.rs:12:10 + --> $DIR/genercs-in-path-with-prettry-hir.rs:13:10 | LL | m!(inline); | ^^^^ diff --git a/tests/ui/macros/genercs-in-path-with-prettry-hir.stdout b/tests/ui/macros/genercs-in-path-with-prettry-hir.stdout index e8c88d2dcdf2..6b41eb530dbc 100644 --- a/tests/ui/macros/genercs-in-path-with-prettry-hir.stdout +++ b/tests/ui/macros/genercs-in-path-with-prettry-hir.stdout @@ -3,6 +3,7 @@ use ::std::prelude::rust_2015::*; #[macro_use] extern crate std; //@ compile-flags: -Zunpretty=hir +//@ edition: 2015 // issue#97006 diff --git a/tests/ui/macros/include-single-expr-helper-1.rs b/tests/ui/macros/include-single-expr-helper-1.rs index ddeeb982f64c..6802719afa1b 100644 --- a/tests/ui/macros/include-single-expr-helper-1.rs +++ b/tests/ui/macros/include-single-expr-helper-1.rs @@ -1,4 +1,4 @@ -//@ ignore-test auxiliary file for include-single-expr.rs +//@ ignore-auxiliary (used by `./include-single-expr.rs`) 0 diff --git a/tests/ui/macros/include-single-expr-helper.rs b/tests/ui/macros/include-single-expr-helper.rs index e8ad9746b02c..bd75bbbd583e 100644 --- a/tests/ui/macros/include-single-expr-helper.rs +++ b/tests/ui/macros/include-single-expr-helper.rs @@ -1,4 +1,4 @@ -//@ ignore-test auxiliary file for include-single-expr.rs +//@ ignore-auxiliary (used by `./include-single-expr.rs`) 0 10 diff --git a/tests/ui/macros/issue-42954.fixed b/tests/ui/macros/issue-42954.fixed index acfc36e2bff2..b1d4e0a56a6b 100644 --- a/tests/ui/macros/issue-42954.fixed +++ b/tests/ui/macros/issue-42954.fixed @@ -4,7 +4,7 @@ macro_rules! is_plainly_printable { ($i: ident) => { - ($i as u32) < 0 //~ `<` is interpreted as a start of generic arguments + ($i as u32) < 0 //~ ERROR `<` is interpreted as a start of generic arguments }; } diff --git a/tests/ui/macros/issue-42954.rs b/tests/ui/macros/issue-42954.rs index 91362946f845..29e2aa3a682c 100644 --- a/tests/ui/macros/issue-42954.rs +++ b/tests/ui/macros/issue-42954.rs @@ -4,7 +4,7 @@ macro_rules! is_plainly_printable { ($i: ident) => { - $i as u32 < 0 //~ `<` is interpreted as a start of generic arguments + $i as u32 < 0 //~ ERROR `<` is interpreted as a start of generic arguments }; } diff --git a/tests/ui/macros/issue-69838-dir/bar.rs b/tests/ui/macros/issue-69838-dir/bar.rs index 4433005b85f1..6f91f8e2ffad 100644 --- a/tests/ui/macros/issue-69838-dir/bar.rs +++ b/tests/ui/macros/issue-69838-dir/bar.rs @@ -1,3 +1,3 @@ -//@ ignore-test -- this is an auxiliary file as part of another test. +//@ ignore-auxiliary (used by `../issue-69838-mods-relative-to-included-path.rs`) pub fn i_am_in_bar() {} diff --git a/tests/ui/macros/issue-69838-dir/included.rs b/tests/ui/macros/issue-69838-dir/included.rs index 11fcd3eff725..328334d5e66a 100644 --- a/tests/ui/macros/issue-69838-dir/included.rs +++ b/tests/ui/macros/issue-69838-dir/included.rs @@ -1,3 +1,3 @@ -//@ ignore-test -- this is an auxiliary file as part of another test. +//@ ignore-auxiliary (used by `../issue-69838-mods-relative-to-included-path.rs`) pub mod bar; diff --git a/tests/ui/macros/issue-88228.rs b/tests/ui/macros/issue-88228.rs index 48b405264fef..b4195a92557e 100644 --- a/tests/ui/macros/issue-88228.rs +++ b/tests/ui/macros/issue-88228.rs @@ -13,7 +13,7 @@ struct A; #[derive(println)] //~^ ERROR cannot find derive macro `println` -//~|`println` is in scope, but it is a function-like macro +//~| NOTE `println` is in scope, but it is a function-like macro struct B; fn main() { diff --git a/tests/ui/macros/lint-trailing-macro-call.rs b/tests/ui/macros/lint-trailing-macro-call.rs index 66dce057d0f5..78b861f1df17 100644 --- a/tests/ui/macros/lint-trailing-macro-call.rs +++ b/tests/ui/macros/lint-trailing-macro-call.rs @@ -6,7 +6,7 @@ macro_rules! expand_it { () => { - #[cfg(FALSE)] 25; //~ WARN trailing semicolon in macro + #[cfg(false)] 25; //~ WARN trailing semicolon in macro //~| WARN this was previously } } diff --git a/tests/ui/macros/lint-trailing-macro-call.stderr b/tests/ui/macros/lint-trailing-macro-call.stderr index 13cecc3a31d2..223b85e112ed 100644 --- a/tests/ui/macros/lint-trailing-macro-call.stderr +++ b/tests/ui/macros/lint-trailing-macro-call.stderr @@ -1,7 +1,7 @@ warning: trailing semicolon in macro used in expression position --> $DIR/lint-trailing-macro-call.rs:9:25 | -LL | #[cfg(FALSE)] 25; +LL | #[cfg(false)] 25; | ^ ... LL | expand_it!() @@ -20,7 +20,7 @@ Future incompatibility report: Future breakage diagnostic: warning: trailing semicolon in macro used in expression position --> $DIR/lint-trailing-macro-call.rs:9:25 | -LL | #[cfg(FALSE)] 25; +LL | #[cfg(false)] 25; | ^ ... LL | expand_it!() diff --git a/tests/ui/macros/macro-as-fn-body.rs b/tests/ui/macros/macro-as-fn-body.rs index e0542edc2a52..188c7f7f728c 100644 --- a/tests/ui/macros/macro-as-fn-body.rs +++ b/tests/ui/macros/macro-as-fn-body.rs @@ -1,7 +1,7 @@ // //@ run-pass // -// Description - ensure Interpolated blocks can act as valid function bodies +// Description - ensure block metavariables can act as valid function bodies // Covered cases: free functions, struct methods, and default trait functions macro_rules! def_fn { diff --git a/tests/ui/macros/macro-attributes.rs b/tests/ui/macros/macro-attributes.rs index 832907907669..976d2cbcccdb 100644 --- a/tests/ui/macros/macro-attributes.rs +++ b/tests/ui/macros/macro-attributes.rs @@ -9,7 +9,7 @@ macro_rules! compiles_fine { // check that the attributes are recognised by requiring this // to be removed to avoid a compile error - #[cfg(FALSE)] + #[cfg(false)] static MISTYPED: () = "foo"; } } diff --git a/tests/ui/macros/macro-expanded-include/foo/mod.rs b/tests/ui/macros/macro-expanded-include/foo/mod.rs index 926d84c93e58..4e6d9e4aea40 100644 --- a/tests/ui/macros/macro-expanded-include/foo/mod.rs +++ b/tests/ui/macros/macro-expanded-include/foo/mod.rs @@ -1,4 +1,4 @@ -//@ ignore-test (auxiliary, used by other tests) +//@ ignore-auxiliary (used by `../test.rs`) macro_rules! m { () => { include!("file.txt"); } diff --git a/tests/ui/macros/macro-inner-attributes.rs b/tests/ui/macros/macro-inner-attributes.rs index a1eb7cd15c4c..1a832ca9b0c4 100644 --- a/tests/ui/macros/macro-inner-attributes.rs +++ b/tests/ui/macros/macro-inner-attributes.rs @@ -5,7 +5,7 @@ macro_rules! test { ($nm:ident, $i:item) => (mod $nm { #![$a] $i }); } test!(a, - #[cfg(FALSE)], + #[cfg(false)], pub fn bar() { }); test!(b, diff --git a/tests/ui/macros/macro-outer-attributes.rs b/tests/ui/macros/macro-outer-attributes.rs index 8c79683f49a9..5b41cf9fd29d 100644 --- a/tests/ui/macros/macro-outer-attributes.rs +++ b/tests/ui/macros/macro-outer-attributes.rs @@ -5,7 +5,7 @@ macro_rules! test { ($nm:ident, $i:item) => (mod $nm { #[$a] $i }); } test!(a, - #[cfg(FALSE)], + #[cfg(false)], pub fn bar() { }); test!(b, diff --git a/tests/ui/macros/macro-outer-attributes.stderr b/tests/ui/macros/macro-outer-attributes.stderr index a8809f3fcff6..a894c90f4c32 100644 --- a/tests/ui/macros/macro-outer-attributes.stderr +++ b/tests/ui/macros/macro-outer-attributes.stderr @@ -16,7 +16,7 @@ LL | $i:item) => (mod $nm { #[$a] $i }); } | ^^^^^ LL | LL | / test!(a, -LL | | #[cfg(FALSE)], +LL | | #[cfg(false)], LL | | pub fn bar() { }); | |_______________________- in this macro invocation = note: this error originates in the macro `test` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/macros/macro-with-attrs2.rs b/tests/ui/macros/macro-with-attrs2.rs index 37188e45ad3b..7d0bf9114253 100644 --- a/tests/ui/macros/macro-with-attrs2.rs +++ b/tests/ui/macros/macro-with-attrs2.rs @@ -1,6 +1,6 @@ //@ run-pass -#[cfg(FALSE)] +#[cfg(false)] macro_rules! foo { () => (1) } #[cfg(not(FALSE))] diff --git a/tests/ui/macros/no-close-delim-issue-139248.rs b/tests/ui/macros/no-close-delim-issue-139248.rs new file mode 100644 index 000000000000..86583b2724ed --- /dev/null +++ b/tests/ui/macros/no-close-delim-issue-139248.rs @@ -0,0 +1,14 @@ +// This code caused a "no close delim when reparsing Expr" ICE in #139248. + +macro_rules! m { + (static a : () = $e:expr) => { + static a : () = $e; + //~^ ERROR macro expansion ends with an incomplete expression: expected expression + } +} + +m! { static a : () = (if b) } +//~^ ERROR expected `{`, found `)` +//~| ERROR expected `{`, found `)` + +fn main() {} diff --git a/tests/ui/macros/no-close-delim-issue-139248.stderr b/tests/ui/macros/no-close-delim-issue-139248.stderr new file mode 100644 index 000000000000..6ed41ae9b46a --- /dev/null +++ b/tests/ui/macros/no-close-delim-issue-139248.stderr @@ -0,0 +1,33 @@ +error: expected `{`, found `)` + --> $DIR/no-close-delim-issue-139248.rs:10:27 + | +LL | m! { static a : () = (if b) } + | ^ expected `{` + | +note: the `if` expression is missing a block after this condition + --> $DIR/no-close-delim-issue-139248.rs:10:26 + | +LL | m! { static a : () = (if b) } + | ^ + +error: expected `{`, found `)` + --> $DIR/no-close-delim-issue-139248.rs:10:27 + | +LL | m! { static a : () = (if b) } + | ^ expected `{` + | +note: the `if` expression is missing a block after this condition + --> $DIR/no-close-delim-issue-139248.rs:10:26 + | +LL | m! { static a : () = (if b) } + | ^ + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: macro expansion ends with an incomplete expression: expected expression + --> $DIR/no-close-delim-issue-139248.rs:5:28 + | +LL | static a : () = $e; + | ^ expected expression + +error: aborting due to 3 previous errors + diff --git a/tests/ui/macros/remove-repetition-issue-139480.rs b/tests/ui/macros/remove-repetition-issue-139480.rs new file mode 100644 index 000000000000..1efb4306763e --- /dev/null +++ b/tests/ui/macros/remove-repetition-issue-139480.rs @@ -0,0 +1,28 @@ +macro_rules! ciallo { + ($($v: vis)? $name: ident) => { + //~^ error: repetition matches empty token tree + }; +} + +macro_rules! meow { + ($name: ident $($v: vis)?) => { + //~^ error: repetition matches empty token tree + }; +} + +macro_rules! gbc { + ($name: ident $/* + this comment gets removed by the suggestion + */ + ($v: vis)?) => { + //~^ error: repetition matches empty token tree + }; +} + +ciallo!(hello); + +meow!(miaow, pub); + +gbc!(mygo,); + +fn main() {} diff --git a/tests/ui/macros/remove-repetition-issue-139480.stderr b/tests/ui/macros/remove-repetition-issue-139480.stderr new file mode 100644 index 000000000000..c2475589ee9a --- /dev/null +++ b/tests/ui/macros/remove-repetition-issue-139480.stderr @@ -0,0 +1,44 @@ +error: repetition matches empty token tree + --> $DIR/remove-repetition-issue-139480.rs:2:7 + | +LL | ($($v: vis)? $name: ident) => { + | ^^^^^^^^^ + | + = note: a `vis` fragment can already be empty +help: remove the `$(` and `)?` + | +LL - ($($v: vis)? $name: ident) => { +LL + ($v: vis $name: ident) => { + | + +error: repetition matches empty token tree + --> $DIR/remove-repetition-issue-139480.rs:8:20 + | +LL | ($name: ident $($v: vis)?) => { + | ^^^^^^^^^ + | + = note: a `vis` fragment can already be empty +help: remove the `$(` and `)?` + | +LL - ($name: ident $($v: vis)?) => { +LL + ($name: ident $v: vis) => { + | + +error: repetition matches empty token tree + --> $DIR/remove-repetition-issue-139480.rs:17:9 + | +LL | ($v: vis)?) => { + | ^^^^^^^^^ + | + = note: a `vis` fragment can already be empty +help: remove the `$(` and `)?` + | +LL - ($name: ident $/* +LL - this comment gets removed by the suggestion +LL - */ +LL - ($v: vis)?) => { +LL + ($name: ident $v: vis) => { + | + +error: aborting due to 3 previous errors + diff --git a/tests/ui/macros/reparse-expr-issue-139495.rs b/tests/ui/macros/reparse-expr-issue-139495.rs new file mode 100644 index 000000000000..38d24573a533 --- /dev/null +++ b/tests/ui/macros/reparse-expr-issue-139495.rs @@ -0,0 +1,7 @@ +macro_rules! m { + ($abi : expr) => { extern $abi } //~ ERROR expected expression, found keyword `extern` +} + +fn main() { + m!(-2) +} diff --git a/tests/ui/macros/reparse-expr-issue-139495.stderr b/tests/ui/macros/reparse-expr-issue-139495.stderr new file mode 100644 index 000000000000..73a8ed87ba05 --- /dev/null +++ b/tests/ui/macros/reparse-expr-issue-139495.stderr @@ -0,0 +1,13 @@ +error: expected expression, found keyword `extern` + --> $DIR/reparse-expr-issue-139495.rs:2:22 + | +LL | ($abi : expr) => { extern $abi } + | ^^^^^^ expected expression +... +LL | m!(-2) + | ------ in this macro invocation + | + = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 1 previous error + diff --git a/tests/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.rs b/tests/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.rs index cf47a1e67aed..29f71d10719b 100644 --- a/tests/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.rs +++ b/tests/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.rs @@ -1,5 +1,6 @@ //@ check-pass //@ compile-flags: -Z unpretty=expanded +//@ edition: 2015 #![feature(core_intrinsics, generic_assert)] diff --git a/tests/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.stdout b/tests/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.stdout index 8065d0dff8fc..9300f610f8e2 100644 --- a/tests/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.stdout +++ b/tests/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.stdout @@ -2,6 +2,7 @@ #![no_std] //@ check-pass //@ compile-flags: -Z unpretty=expanded +//@ edition: 2015 #![feature(core_intrinsics, generic_assert)] #[prelude_import] diff --git a/tests/ui/macros/stringify.rs b/tests/ui/macros/stringify.rs index 40033f546d30..3490d3efc599 100644 --- a/tests/ui/macros/stringify.rs +++ b/tests/ui/macros/stringify.rs @@ -515,6 +515,8 @@ fn test_meta() { #[test] fn test_pat() { + // PatKind::Missing: untestable in isolation. + // PatKind::Wild c1!(pat, [ _ ], "_"); diff --git a/tests/ui/macros/syntax-error-recovery.rs b/tests/ui/macros/syntax-error-recovery.rs index 6cf9d54e8263..e1681ea32a2e 100644 --- a/tests/ui/macros/syntax-error-recovery.rs +++ b/tests/ui/macros/syntax-error-recovery.rs @@ -5,14 +5,14 @@ macro_rules! values { $( #[$attr] $token $($inner)? = $value, + //~^ ERROR expected one of `!` or `::`, found `` )* } }; } -//~^^^^^ ERROR expected one of `(`, `,`, `=`, `{`, or `}`, found `ty` metavariable +//~^^^^^^ ERROR expected one of `(`, `,`, `=`, `{`, or `}`, found `ty` metavariable //~| ERROR macro expansion ignores `ty` metavariable and any tokens following values!(STRING(1) as (String) => cfg(test),); -//~^ ERROR expected one of `!` or `::`, found `` fn main() {} diff --git a/tests/ui/macros/syntax-error-recovery.stderr b/tests/ui/macros/syntax-error-recovery.stderr index 61758fb9d7dc..a2059aa1aa80 100644 --- a/tests/ui/macros/syntax-error-recovery.stderr +++ b/tests/ui/macros/syntax-error-recovery.stderr @@ -22,10 +22,10 @@ LL | values!(STRING(1) as (String) => cfg(test),); = note: the usage of `values!` is likely invalid in item context error: expected one of `!` or `::`, found `` - --> $DIR/syntax-error-recovery.rs:15:9 + --> $DIR/syntax-error-recovery.rs:7:17 | -LL | values!(STRING(1) as (String) => cfg(test),); - | ^^^^^^ expected one of `!` or `::` +LL | $token $($inner)? = $value, + | ^^^^^^ expected one of `!` or `::` error: aborting due to 3 previous errors diff --git a/tests/ui/match/intended-binding-pattern-is-const.rs b/tests/ui/match/intended-binding-pattern-is-const.rs index 95c8119cdb9d..12a8e2c18bc1 100644 --- a/tests/ui/match/intended-binding-pattern-is-const.rs +++ b/tests/ui/match/intended-binding-pattern-is-const.rs @@ -1,8 +1,8 @@ fn main() { match 1 { //~ ERROR non-exhaustive patterns - //~^ patterns `i32::MIN..=3_i32` and `5_i32..=i32::MAX` not covered - //~| the matched value is of type `i32` - x => {} //~ this pattern doesn't introduce a new catch-all binding + //~^ NOTE patterns `i32::MIN..=3_i32` and `5_i32..=i32::MAX` not covered + //~| NOTE the matched value is of type `i32` + x => {} //~ NOTE this pattern doesn't introduce a new catch-all binding //~^ HELP ensure that all possible cases are being handled //~| HELP if you meant to introduce a binding, use a different name } diff --git a/tests/ui/match/issue-82392.rs b/tests/ui/match/issue-82392.rs index 6f9527fb337b..4ae08fed93a2 100644 --- a/tests/ui/match/issue-82392.rs +++ b/tests/ui/match/issue-82392.rs @@ -1,6 +1,7 @@ // https://github.com/rust-lang/rust/issues/82329 //@ compile-flags: -Zunpretty=hir,typed //@ check-pass +//@ edition:2015 pub fn main() { if true { diff --git a/tests/ui/match/issue-82392.stdout b/tests/ui/match/issue-82392.stdout index 8949611ac12f..8b7edabf004e 100644 --- a/tests/ui/match/issue-82392.stdout +++ b/tests/ui/match/issue-82392.stdout @@ -5,6 +5,7 @@ extern crate std; // https://github.com/rust-lang/rust/issues/82329 //@ compile-flags: -Zunpretty=hir,typed //@ check-pass +//@ edition:2015 fn main() ({ (if (true as bool) diff --git a/tests/ui/match/postfix-match/pf-match-exhaustiveness.rs b/tests/ui/match/postfix-match/pf-match-exhaustiveness.rs index f4cac46f7cd6..cbd35482d222 100644 --- a/tests/ui/match/postfix-match/pf-match-exhaustiveness.rs +++ b/tests/ui/match/postfix-match/pf-match-exhaustiveness.rs @@ -1,7 +1,7 @@ #![feature(postfix_match)] fn main() { - Some(1).match { //~ non-exhaustive patterns + Some(1).match { //~ ERROR non-exhaustive patterns None => {}, } } diff --git a/tests/ui/methods/bad-wf-when-selecting-method.rs b/tests/ui/methods/bad-wf-when-selecting-method.rs index 638d1ffa982f..1f1a10f42046 100644 --- a/tests/ui/methods/bad-wf-when-selecting-method.rs +++ b/tests/ui/methods/bad-wf-when-selecting-method.rs @@ -12,7 +12,7 @@ fn test(t: T) { Wrapper(t).needs_sized(); //~^ ERROR the trait bound `T: Wf` is not satisfied //~| ERROR the trait bound `T: Wf` is not satisfied - //~| the method `needs_sized` exists for struct `Wrapper`, but its trait bounds were not satisfied + //~| ERROR the method `needs_sized` exists for struct `Wrapper`, but its trait bounds were not satisfied } fn main() {} diff --git a/tests/ui/methods/disambiguate-associated-function-first-arg.rs b/tests/ui/methods/disambiguate-associated-function-first-arg.rs index 4c8192fc14bd..c88be8424814 100644 --- a/tests/ui/methods/disambiguate-associated-function-first-arg.rs +++ b/tests/ui/methods/disambiguate-associated-function-first-arg.rs @@ -45,5 +45,5 @@ impl TraitB for T { fn test() { S.f(); - //~^ multiple applicable items in scope + //~^ ERROR multiple applicable items in scope } diff --git a/tests/ui/methods/issues/issue-90315.rs b/tests/ui/methods/issues/issue-90315.rs index fbecaf9b971f..3a82454b7b4f 100644 --- a/tests/ui/methods/issues/issue-90315.rs +++ b/tests/ui/methods/issues/issue-90315.rs @@ -3,7 +3,7 @@ fn main() { let arr = &[0, 1, 2, 3]; for _i in 0..arr.len().rev() { //~^ ERROR can't call method - //~| surround the range in parentheses + //~| HELP surround the range in parentheses // The above error used to say “the method `rev` exists for type `usize`”. // This regression test ensures it doesn't say that any more. } diff --git a/tests/ui/mir-dataflow/README.md b/tests/ui/mir-dataflow/README.md index a3ab14b23c7d..886020226d03 100644 --- a/tests/ui/mir-dataflow/README.md +++ b/tests/ui/mir-dataflow/README.md @@ -42,12 +42,3 @@ each generated output path. on *entry* to each block, as well as the gen- and kill-sets that were so-called "transfer functions" summarizing the effect of each basic block. - - * (In addition to the `borrowck_graphviz_postflow` attribute-key - noted above, there is also `borrowck_graphviz_preflow`; it has the - same interface and generates the same set of files, but it renders - the dataflow state after building the gen- and kill-sets but - *before* running the dataflow analysis itself, so each entry-set is - just the initial default state for that dataflow analysis. This is - less useful for understanding the error message output in these - tests.) diff --git a/tests/ui/mir/enable_passes_validation.rs b/tests/ui/mir/enable_passes_validation.rs index b97ddfba37f5..99b1ba528b0c 100644 --- a/tests/ui/mir/enable_passes_validation.rs +++ b/tests/ui/mir/enable_passes_validation.rs @@ -19,7 +19,7 @@ fn main() {} //[unprefixed]~? ERROR incorrect value `CheckAlignment` for unstable option `mir-enable-passes` //[mixed]~? WARN MIR pass `ThisPassDoesNotExist` is unknown and will be ignored //[mixed]~? WARN MIR pass `ThisPassDoesNotExist` is unknown and will be ignored -//[all_unknown]~? MIR pass `ThisPass` is unknown and will be ignored -//[all_unknown]~? MIR pass `DoesNotExist` is unknown and will be ignored -//[all_unknown]~? MIR pass `ThisPass` is unknown and will be ignored -//[all_unknown]~? MIR pass `DoesNotExist` is unknown and will be ignored +//[all_unknown]~? WARN MIR pass `ThisPass` is unknown and will be ignored +//[all_unknown]~? WARN MIR pass `DoesNotExist` is unknown and will be ignored +//[all_unknown]~? WARN MIR pass `ThisPass` is unknown and will be ignored +//[all_unknown]~? WARN MIR pass `DoesNotExist` is unknown and will be ignored diff --git a/tests/ui/mir/issue-105809.rs b/tests/ui/mir/issue-105809.rs index e7a8fb652689..a46dcf350adf 100644 --- a/tests/ui/mir/issue-105809.rs +++ b/tests/ui/mir/issue-105809.rs @@ -1,7 +1,8 @@ // Non-regression test ICE from issue #105809 and duplicates. //@ build-pass: the ICE is during codegen -//@ compile-flags: --edition 2018 -Zmir-opt-level=1 +//@ compile-flags: -Zmir-opt-level=1 +//@ edition: 2018 use std::{future::Future, pin::Pin}; diff --git a/tests/ui/mismatched_types/assignment-operator-unimplemented.rs b/tests/ui/mismatched_types/assignment-operator-unimplemented.rs index 21df464d5e45..04a379bbd048 100644 --- a/tests/ui/mismatched_types/assignment-operator-unimplemented.rs +++ b/tests/ui/mismatched_types/assignment-operator-unimplemented.rs @@ -3,5 +3,5 @@ struct Foo; fn main() { let mut a = Foo; let ref b = Foo; - a += *b; //~ Error: binary assignment operation `+=` cannot be applied to type `Foo` + a += *b; //~ ERROR binary assignment operation `+=` cannot be applied to type `Foo` } diff --git a/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.next.stderr b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.next.stderr index b71613106199..7912ed4d7071 100644 --- a/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.next.stderr +++ b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.next.stderr @@ -7,8 +7,8 @@ LL | let _ = (-10..=10).find(|x: i32| x.signum() == 0); | required by a bound introduced by this call | = help: the trait `for<'a> FnMut(&'a as Iterator>::Item)` is not implemented for closure `{closure@$DIR/closure-arg-type-mismatch-issue-45727.rs:6:29: 6:37}` - = note: expected a closure with arguments `(i32,)` - found a closure with arguments `(& as Iterator>::Item,)` + = note: expected a closure with signature `for<'a> fn(&'a as Iterator>::Item)` + found a closure with signature `fn(i32)` note: required by a bound in `find` --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL @@ -27,8 +27,8 @@ LL | let _ = (-10..=10).find(|x: &&&i32| x.signum() == 0); | required by a bound introduced by this call | = help: the trait `for<'a> FnMut(&'a as Iterator>::Item)` is not implemented for closure `{closure@$DIR/closure-arg-type-mismatch-issue-45727.rs:9:29: 9:40}` - = note: expected a closure with arguments `(&&&i32,)` - found a closure with arguments `(& as Iterator>::Item,)` + = note: expected a closure with signature `for<'a> fn(&'a as Iterator>::Item)` + found a closure with signature `fn(&&&i32)` note: required by a bound in `find` --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL diff --git a/tests/ui/mismatched_types/closure-mismatch.stderr b/tests/ui/mismatched_types/closure-mismatch.current.stderr similarity index 90% rename from tests/ui/mismatched_types/closure-mismatch.stderr rename to tests/ui/mismatched_types/closure-mismatch.current.stderr index 802110c6511d..378fe83ea89b 100644 --- a/tests/ui/mismatched_types/closure-mismatch.stderr +++ b/tests/ui/mismatched_types/closure-mismatch.current.stderr @@ -1,5 +1,5 @@ error: implementation of `FnOnce` is not general enough - --> $DIR/closure-mismatch.rs:8:5 + --> $DIR/closure-mismatch.rs:12:5 | LL | baz(|_| ()); | ^^^^^^^^^^^ implementation of `FnOnce` is not general enough @@ -8,7 +8,7 @@ LL | baz(|_| ()); = note: ...but it actually implements `FnOnce<(&'2 (),)>`, for some specific lifetime `'2` error: implementation of `Fn` is not general enough - --> $DIR/closure-mismatch.rs:8:5 + --> $DIR/closure-mismatch.rs:12:5 | LL | baz(|_| ()); | ^^^^^^^^^^^ implementation of `Fn` is not general enough @@ -17,7 +17,7 @@ LL | baz(|_| ()); = note: ...but it actually implements `Fn<(&'2 (),)>`, for some specific lifetime `'2` error: implementation of `FnOnce` is not general enough - --> $DIR/closure-mismatch.rs:11:5 + --> $DIR/closure-mismatch.rs:16:5 | LL | baz(|x| ()); | ^^^^^^^^^^^ implementation of `FnOnce` is not general enough @@ -26,7 +26,7 @@ LL | baz(|x| ()); = note: ...but it actually implements `FnOnce<(&'2 (),)>`, for some specific lifetime `'2` error: implementation of `Fn` is not general enough - --> $DIR/closure-mismatch.rs:11:5 + --> $DIR/closure-mismatch.rs:16:5 | LL | baz(|x| ()); | ^^^^^^^^^^^ implementation of `Fn` is not general enough diff --git a/tests/ui/mismatched_types/closure-mismatch.next.stderr b/tests/ui/mismatched_types/closure-mismatch.next.stderr new file mode 100644 index 000000000000..6b4620aa8d1b --- /dev/null +++ b/tests/ui/mismatched_types/closure-mismatch.next.stderr @@ -0,0 +1,67 @@ +error[E0277]: the trait bound `{closure@$DIR/closure-mismatch.rs:12:9: 12:12}: Foo` is not satisfied + --> $DIR/closure-mismatch.rs:12:9 + | +LL | baz(|_| ()); + | --- ^^^^^^ unsatisfied trait bound + | | + | required by a bound introduced by this call + | + = help: the trait `for<'a> FnOnce(&'a ())` is not implemented for closure `{closure@$DIR/closure-mismatch.rs:12:9: 12:12}` + = note: expected a closure with signature `for<'a> fn(&'a ())` + found a closure with signature `fn(&())` +note: this is a known limitation of the trait solver that will be lifted in the future + --> $DIR/closure-mismatch.rs:12:9 + | +LL | baz(|_| ()); + | ----^^^---- + | | | + | | the trait solver is unable to infer the generic types that should be inferred from this argument + | add turbofish arguments to this call to specify the types manually, even if it's redundant +note: required for `{closure@$DIR/closure-mismatch.rs:12:9: 12:12}` to implement `Foo` + --> $DIR/closure-mismatch.rs:7:18 + | +LL | impl Foo for T {} + | ------- ^^^ ^ + | | + | unsatisfied trait bound introduced here +note: required by a bound in `baz` + --> $DIR/closure-mismatch.rs:9:11 + | +LL | fn baz(_: T) {} + | ^^^ required by this bound in `baz` + +error[E0277]: the trait bound `{closure@$DIR/closure-mismatch.rs:16:9: 16:12}: Foo` is not satisfied + --> $DIR/closure-mismatch.rs:16:9 + | +LL | baz(|x| ()); + | --- ^^^^^^ unsatisfied trait bound + | | + | required by a bound introduced by this call + | + = help: the trait `for<'a> FnOnce(&'a ())` is not implemented for closure `{closure@$DIR/closure-mismatch.rs:16:9: 16:12}` + = note: expected a closure with signature `for<'a> fn(&'a ())` + found a closure with signature `fn(&())` +note: this is a known limitation of the trait solver that will be lifted in the future + --> $DIR/closure-mismatch.rs:16:9 + | +LL | baz(|x| ()); + | ----^^^---- + | | | + | | the trait solver is unable to infer the generic types that should be inferred from this argument + | add turbofish arguments to this call to specify the types manually, even if it's redundant +note: required for `{closure@$DIR/closure-mismatch.rs:16:9: 16:12}` to implement `Foo` + --> $DIR/closure-mismatch.rs:7:18 + | +LL | impl Foo for T {} + | ------- ^^^ ^ + | | + | unsatisfied trait bound introduced here +note: required by a bound in `baz` + --> $DIR/closure-mismatch.rs:9:11 + | +LL | fn baz(_: T) {} + | ^^^ required by this bound in `baz` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/mismatched_types/closure-mismatch.rs b/tests/ui/mismatched_types/closure-mismatch.rs index efaed4dc1b99..1a24c760a6af 100644 --- a/tests/ui/mismatched_types/closure-mismatch.rs +++ b/tests/ui/mismatched_types/closure-mismatch.rs @@ -1,3 +1,7 @@ +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver + trait Foo {} impl Foo for T {} @@ -6,9 +10,11 @@ fn baz(_: T) {} fn main() { baz(|_| ()); - //~^ ERROR implementation of `FnOnce` is not general enough - //~| ERROR implementation of `Fn` is not general enough + //[current]~^ ERROR implementation of `FnOnce` is not general enough + //[current]~| ERROR implementation of `Fn` is not general enough + //[next]~^^^ ERROR Foo` is not satisfied baz(|x| ()); - //~^ ERROR implementation of `FnOnce` is not general enough - //~| ERROR implementation of `Fn` is not general enough + //[current]~^ ERROR implementation of `FnOnce` is not general enough + //[current]~| ERROR implementation of `Fn` is not general enough + //[next]~^^^ ERROR Foo` is not satisfied } diff --git a/tests/ui/mismatched_types/similar_paths_primitive.rs b/tests/ui/mismatched_types/similar_paths_primitive.rs index a58fe68b8638..b20ca80ac071 100644 --- a/tests/ui/mismatched_types/similar_paths_primitive.rs +++ b/tests/ui/mismatched_types/similar_paths_primitive.rs @@ -4,8 +4,9 @@ struct bool; //~ NOTE the other `bool` is defined in the current crate struct str; //~ NOTE the other `str` is defined in the current crate fn foo(_: bool) {} //~ NOTE function defined here + //~^ NOTE fn bar(_: &str) {} //~ NOTE function defined here - + //~^ NOTE fn main() { foo(true); //~^ ERROR mismatched types [E0308] diff --git a/tests/ui/mismatched_types/similar_paths_primitive.stderr b/tests/ui/mismatched_types/similar_paths_primitive.stderr index cf26234dba85..9c1aa0d7105b 100644 --- a/tests/ui/mismatched_types/similar_paths_primitive.stderr +++ b/tests/ui/mismatched_types/similar_paths_primitive.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/similar_paths_primitive.rs:10:9 + --> $DIR/similar_paths_primitive.rs:11:9 | LL | foo(true); | --- ^^^^ expected `bool`, found a different `bool` @@ -20,7 +20,7 @@ LL | fn foo(_: bool) {} | ^^^ ------- error[E0308]: mismatched types - --> $DIR/similar_paths_primitive.rs:16:9 + --> $DIR/similar_paths_primitive.rs:17:9 | LL | bar("hello"); | --- ^^^^^^^ expected `str`, found a different `str` @@ -35,7 +35,7 @@ note: the other `str` is defined in the current crate LL | struct str; | ^^^^^^^^^^ note: function defined here - --> $DIR/similar_paths_primitive.rs:7:4 + --> $DIR/similar_paths_primitive.rs:8:4 | LL | fn bar(_: &str) {} | ^^^ ------- diff --git a/tests/ui/mismatched_types/suggest-adding-or-removing-ref-for-binding-pattern.fixed b/tests/ui/mismatched_types/suggest-adding-or-removing-ref-for-binding-pattern.fixed index cf923362ad81..04e0fcca32d6 100644 --- a/tests/ui/mismatched_types/suggest-adding-or-removing-ref-for-binding-pattern.fixed +++ b/tests/ui/mismatched_types/suggest-adding-or-removing-ref-for-binding-pattern.fixed @@ -16,6 +16,6 @@ fn main() { match Blah::A(1, 1, 2) { Blah::A(_, x, y) | Blah::B(x, y) => {} //~^ ERROR mismatched types - //~| variable `y` is bound inconsistently across alternatives separated by `|` + //~| ERROR variable `y` is bound inconsistently across alternatives separated by `|` } } diff --git a/tests/ui/mismatched_types/suggest-adding-or-removing-ref-for-binding-pattern.rs b/tests/ui/mismatched_types/suggest-adding-or-removing-ref-for-binding-pattern.rs index dc556f6576ae..dd6329c90905 100644 --- a/tests/ui/mismatched_types/suggest-adding-or-removing-ref-for-binding-pattern.rs +++ b/tests/ui/mismatched_types/suggest-adding-or-removing-ref-for-binding-pattern.rs @@ -16,6 +16,6 @@ fn main() { match Blah::A(1, 1, 2) { Blah::A(_, x, y) | Blah::B(x, ref y) => {} //~^ ERROR mismatched types - //~| variable `y` is bound inconsistently across alternatives separated by `|` + //~| ERROR variable `y` is bound inconsistently across alternatives separated by `|` } } diff --git a/tests/ui/missing/missing-return.rs b/tests/ui/missing/missing-return.rs index 5d9839a969c1..4d48e7c13e2c 100644 --- a/tests/ui/missing/missing-return.rs +++ b/tests/ui/missing/missing-return.rs @@ -1,5 +1,4 @@ -//@ error-pattern: return - fn f() -> isize { } //~ ERROR mismatched types - + //~| NOTE implicitly returns `()` as its body has no tail or `return` expression + //~| NOTE expected `isize`, found `()` fn main() { f(); } diff --git a/tests/ui/missing/missing-return.stderr b/tests/ui/missing/missing-return.stderr index 5f7fb504075c..b2d202b9b572 100644 --- a/tests/ui/missing/missing-return.stderr +++ b/tests/ui/missing/missing-return.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/missing-return.rs:3:11 + --> $DIR/missing-return.rs:1:11 | LL | fn f() -> isize { } | - ^^^^^ expected `isize`, found `()` diff --git a/tests/ui/missing_non_modrs_mod/foo.rs b/tests/ui/missing_non_modrs_mod/foo.rs index dd3e970b8c6e..afdc5e39b84d 100644 --- a/tests/ui/missing_non_modrs_mod/foo.rs +++ b/tests/ui/missing_non_modrs_mod/foo.rs @@ -1,4 +1,3 @@ -// -//@ ignore-test this is just a helper for the real test in this dir +//@ ignore-auxiliary (used by `./missing_non_modrs_mod.rs`) mod missing; diff --git a/tests/ui/missing_non_modrs_mod/foo_inline.rs b/tests/ui/missing_non_modrs_mod/foo_inline.rs index 9d46e9bdd0c3..ed6d3a49101d 100644 --- a/tests/ui/missing_non_modrs_mod/foo_inline.rs +++ b/tests/ui/missing_non_modrs_mod/foo_inline.rs @@ -1,4 +1,4 @@ -//@ ignore-test this is just a helper for the real test in this dir +//@ ignore-auxiliary (used by `./missing_non_modrs_mod_inline.rs`) mod inline { mod missing; diff --git a/tests/ui/missing_non_modrs_mod/missing_non_modrs_mod.stderr b/tests/ui/missing_non_modrs_mod/missing_non_modrs_mod.stderr index 4e48799318b6..c084fbf00c26 100644 --- a/tests/ui/missing_non_modrs_mod/missing_non_modrs_mod.stderr +++ b/tests/ui/missing_non_modrs_mod/missing_non_modrs_mod.stderr @@ -1,5 +1,5 @@ error[E0583]: file not found for module `missing` - --> $DIR/foo.rs:4:1 + --> $DIR/foo.rs:3:1 | LL | mod missing; | ^^^^^^^^^^^^ diff --git a/tests/ui/modules/issue-107649.rs b/tests/ui/modules/issue-107649.rs index af5758d79858..f93fb07e17af 100644 --- a/tests/ui/modules/issue-107649.rs +++ b/tests/ui/modules/issue-107649.rs @@ -102,5 +102,5 @@ fn main() { (); (); (); - dbg!(lib::Dummy); //~ Error: `Dummy` doesn't implement `Debug` + dbg!(lib::Dummy); //~ ERROR `Dummy` doesn't implement `Debug` } diff --git a/tests/ui/modules/mod_file_aux.rs b/tests/ui/modules/mod_file_aux.rs index f37296b3af0b..eec38d189b4a 100644 --- a/tests/ui/modules/mod_file_aux.rs +++ b/tests/ui/modules/mod_file_aux.rs @@ -1,4 +1,3 @@ -//@ run-pass -//@ ignore-test Not a test. Used by other tests +//@ ignore-auxiliary (used by `./mod_file_with_path_attr.rs` and `mod_file.rs`) pub fn foo() -> isize { 10 } diff --git a/tests/ui/modules_and_files_visibility/mod_file_aux.rs b/tests/ui/modules_and_files_visibility/mod_file_aux.rs index 77390da75f8f..6fac8dae3d76 100644 --- a/tests/ui/modules_and_files_visibility/mod_file_aux.rs +++ b/tests/ui/modules_and_files_visibility/mod_file_aux.rs @@ -1,3 +1,3 @@ -//@ ignore-test Not a test. Used by other tests +//@ ignore-auxiliary (used by `./mod_file_correct_spans.rs`) pub fn foo() -> isize { 10 } diff --git a/tests/ui/modules_and_files_visibility/mod_file_disambig_aux.rs b/tests/ui/modules_and_files_visibility/mod_file_disambig_aux.rs index e00b5629c083..9a0b1c4b0d8e 100644 --- a/tests/ui/modules_and_files_visibility/mod_file_disambig_aux.rs +++ b/tests/ui/modules_and_files_visibility/mod_file_disambig_aux.rs @@ -1 +1 @@ -//@ ignore-test not a test. aux file +//@ ignore-auxiliary (used by `./mod_file_disambig.rs`) diff --git a/tests/ui/modules_and_files_visibility/mod_file_disambig_aux/mod.rs b/tests/ui/modules_and_files_visibility/mod_file_disambig_aux/mod.rs index e00b5629c083..232c933c4cbf 100644 --- a/tests/ui/modules_and_files_visibility/mod_file_disambig_aux/mod.rs +++ b/tests/ui/modules_and_files_visibility/mod_file_disambig_aux/mod.rs @@ -1 +1 @@ -//@ ignore-test not a test. aux file +//@ ignore-auxiliary (used by `../mod_file_disambig.rs`) diff --git a/tests/ui/moves/moves-based-on-type-tuple.rs b/tests/ui/moves/moves-based-on-type-tuple.rs index 2e67d8f8a691..c9951a930225 100644 --- a/tests/ui/moves/moves-based-on-type-tuple.rs +++ b/tests/ui/moves/moves-based-on-type-tuple.rs @@ -2,7 +2,7 @@ fn dup(x: Box) -> Box<(Box,Box)> { Box::new((x, x)) - //~^ use of moved value: `x` [E0382] + //~^ ERROR use of moved value: `x` [E0382] } fn main() { diff --git a/tests/ui/moves/nested-loop-moved-value-wrong-continue.rs b/tests/ui/moves/nested-loop-moved-value-wrong-continue.rs index 0235b291df54..87800d314ed5 100644 --- a/tests/ui/moves/nested-loop-moved-value-wrong-continue.rs +++ b/tests/ui/moves/nested-loop-moved-value-wrong-continue.rs @@ -9,6 +9,8 @@ fn foo() { //~| NOTE inside of this loop //~| HELP consider moving the expression out of the loop //~| NOTE in this expansion of desugaring of `for` loop + //~| NOTE + //~| NOTE baz.push(foo); //~^ NOTE value moved here //~| HELP consider cloning the value @@ -30,17 +32,19 @@ fn main() { for foo in foos { //~^ NOTE this reinitialization might get skipped //~| NOTE move occurs because `foo` has type `String` + //~| NOTE for bar in &bars { //~^ NOTE inside of this loop //~| HELP consider moving the expression out of the loop //~| NOTE in this expansion of desugaring of `for` loop + //~| NOTE if foo == *bar { baz.push(foo); //~^ NOTE value moved here //~| HELP consider cloning the value continue; //~^ NOTE verify that your loop breaking logic is correct - //~| NOTE this `continue` advances the loop at line 33 + //~| NOTE this `continue` advances the loop at line 36 } } qux.push(foo); diff --git a/tests/ui/moves/nested-loop-moved-value-wrong-continue.stderr b/tests/ui/moves/nested-loop-moved-value-wrong-continue.stderr index cf863ff8af14..6ef1a4193b1a 100644 --- a/tests/ui/moves/nested-loop-moved-value-wrong-continue.stderr +++ b/tests/ui/moves/nested-loop-moved-value-wrong-continue.stderr @@ -1,5 +1,5 @@ error[E0382]: use of moved value: `foo` - --> $DIR/nested-loop-moved-value-wrong-continue.rs:19:14 + --> $DIR/nested-loop-moved-value-wrong-continue.rs:21:14 | LL | for foo in foos { for bar in &bars { if foo == *bar { | --- ---------------- inside of this loop @@ -14,13 +14,13 @@ LL | qux.push(foo); | ^^^ value used here after move | note: verify that your loop breaking logic is correct - --> $DIR/nested-loop-moved-value-wrong-continue.rs:15:9 + --> $DIR/nested-loop-moved-value-wrong-continue.rs:17:9 | LL | for foo in foos { for bar in &bars { if foo == *bar { | --------------- ---------------- ... LL | continue; - | ^^^^^^^^ this `continue` advances the loop at $DIR/nested-loop-moved-value-wrong-continue.rs:6:23: 18:8 + | ^^^^^^^^ this `continue` advances the loop at $DIR/nested-loop-moved-value-wrong-continue.rs:6:23: 20:8 help: consider moving the expression out of the loop so it is only moved once | LL ~ for foo in foos { let mut value = baz.push(foo); @@ -36,7 +36,7 @@ LL | baz.push(foo.clone()); | ++++++++ error[E0382]: use of moved value: `foo` - --> $DIR/nested-loop-moved-value-wrong-continue.rs:46:18 + --> $DIR/nested-loop-moved-value-wrong-continue.rs:50:18 | LL | for foo in foos { | --- @@ -54,7 +54,7 @@ LL | qux.push(foo); | ^^^ value used here after move | note: verify that your loop breaking logic is correct - --> $DIR/nested-loop-moved-value-wrong-continue.rs:41:17 + --> $DIR/nested-loop-moved-value-wrong-continue.rs:45:17 | LL | for foo in foos { | --------------- @@ -63,7 +63,7 @@ LL | for bar in &bars { | ---------------- ... LL | continue; - | ^^^^^^^^ this `continue` advances the loop at line 33 + | ^^^^^^^^ this `continue` advances the loop at line 36 help: consider moving the expression out of the loop so it is only moved once | LL ~ let mut value = baz.push(foo); diff --git a/tests/ui/moves/use_of_moved_value_clone_suggestions.rs b/tests/ui/moves/use_of_moved_value_clone_suggestions.rs index d5c8d4e6bdf2..9a0a397a7338 100644 --- a/tests/ui/moves/use_of_moved_value_clone_suggestions.rs +++ b/tests/ui/moves/use_of_moved_value_clone_suggestions.rs @@ -1,6 +1,6 @@ // `Rc` is not ever `Copy`, we should not suggest adding `T: Copy` constraint fn duplicate_rc(t: std::rc::Rc) -> (std::rc::Rc, std::rc::Rc) { - (t, t) //~ use of moved value: `t` + (t, t) //~ ERROR use of moved value: `t` } fn main() {} diff --git a/tests/ui/moves/use_of_moved_value_copy_suggestions.fixed b/tests/ui/moves/use_of_moved_value_copy_suggestions.fixed index a5e0dd819b46..53d9cb20b3de 100644 --- a/tests/ui/moves/use_of_moved_value_copy_suggestions.fixed +++ b/tests/ui/moves/use_of_moved_value_copy_suggestions.fixed @@ -4,27 +4,27 @@ fn duplicate_t(t: T) -> (T, T) { //~^ HELP consider restricting type parameter `T` //~| HELP if `T` implemented `Clone`, you could clone the value - (t, t) //~ use of moved value: `t` + (t, t) //~ ERROR use of moved value: `t` } fn duplicate_opt(t: Option) -> (Option, Option) { //~^ HELP consider restricting type parameter `T` - (t, t) //~ use of moved value: `t` + (t, t) //~ ERROR use of moved value: `t` } fn duplicate_tup1(t: (T,)) -> ((T,), (T,)) { //~^ HELP consider restricting type parameter `T` - (t, t) //~ use of moved value: `t` + (t, t) //~ ERROR use of moved value: `t` } fn duplicate_tup2(t: (A, B)) -> ((A, B), (A, B)) { //~^ HELP consider restricting type parameters - (t, t) //~ use of moved value: `t` + (t, t) //~ ERROR use of moved value: `t` } fn duplicate_custom(t: S) -> (S, S) { //~^ HELP consider restricting type parameter `T` - (t, t) //~ use of moved value: `t` + (t, t) //~ ERROR use of moved value: `t` } struct S(T); @@ -42,7 +42,7 @@ trait B {} // Test where bounds are added with different bound placements fn duplicate_custom_1(t: S) -> (S, S) where { //~^ HELP consider restricting type parameter `T` - (t, t) //~ use of moved value: `t` + (t, t) //~ ERROR use of moved value: `t` } fn duplicate_custom_2(t: S) -> (S, S) @@ -50,7 +50,7 @@ where T: A + Copy + Trait, //~^ HELP consider further restricting { - (t, t) //~ use of moved value: `t` + (t, t) //~ ERROR use of moved value: `t` } fn duplicate_custom_3(t: S) -> (S, S) @@ -59,7 +59,7 @@ where //~^ HELP consider further restricting T: B, { - (t, t) //~ use of moved value: `t` + (t, t) //~ ERROR use of moved value: `t` } fn duplicate_custom_4(t: S) -> (S, S) @@ -67,14 +67,14 @@ fn duplicate_custom_4(t: S) -> (S, S) where T: B, { - (t, t) //~ use of moved value: `t` + (t, t) //~ ERROR use of moved value: `t` } #[rustfmt::skip] fn existing_colon(t: T) { //~^ HELP consider restricting type parameter `T` //~| HELP if `T` implemented `Clone`, you could clone the value - [t, t]; //~ use of moved value: `t` + [t, t]; //~ ERROR use of moved value: `t` } fn existing_colon_in_where(t: T) //~ HELP if `T` implemented `Clone`, you could clone the value @@ -82,7 +82,7 @@ where T:, T: Copy //~^ HELP consider further restricting type parameter `T` { - [t, t]; //~ use of moved value: `t` + [t, t]; //~ ERROR use of moved value: `t` } fn main() {} diff --git a/tests/ui/moves/use_of_moved_value_copy_suggestions.rs b/tests/ui/moves/use_of_moved_value_copy_suggestions.rs index 60ca03ed6984..c8cfc80cd82d 100644 --- a/tests/ui/moves/use_of_moved_value_copy_suggestions.rs +++ b/tests/ui/moves/use_of_moved_value_copy_suggestions.rs @@ -4,27 +4,27 @@ fn duplicate_t(t: T) -> (T, T) { //~^ HELP consider restricting type parameter `T` //~| HELP if `T` implemented `Clone`, you could clone the value - (t, t) //~ use of moved value: `t` + (t, t) //~ ERROR use of moved value: `t` } fn duplicate_opt(t: Option) -> (Option, Option) { //~^ HELP consider restricting type parameter `T` - (t, t) //~ use of moved value: `t` + (t, t) //~ ERROR use of moved value: `t` } fn duplicate_tup1(t: (T,)) -> ((T,), (T,)) { //~^ HELP consider restricting type parameter `T` - (t, t) //~ use of moved value: `t` + (t, t) //~ ERROR use of moved value: `t` } fn duplicate_tup2(t: (A, B)) -> ((A, B), (A, B)) { //~^ HELP consider restricting type parameters - (t, t) //~ use of moved value: `t` + (t, t) //~ ERROR use of moved value: `t` } fn duplicate_custom(t: S) -> (S, S) { //~^ HELP consider restricting type parameter `T` - (t, t) //~ use of moved value: `t` + (t, t) //~ ERROR use of moved value: `t` } struct S(T); @@ -42,7 +42,7 @@ trait B {} // Test where bounds are added with different bound placements fn duplicate_custom_1(t: S) -> (S, S) where { //~^ HELP consider restricting type parameter `T` - (t, t) //~ use of moved value: `t` + (t, t) //~ ERROR use of moved value: `t` } fn duplicate_custom_2(t: S) -> (S, S) @@ -50,7 +50,7 @@ where T: A, //~^ HELP consider further restricting { - (t, t) //~ use of moved value: `t` + (t, t) //~ ERROR use of moved value: `t` } fn duplicate_custom_3(t: S) -> (S, S) @@ -59,7 +59,7 @@ where //~^ HELP consider further restricting T: B, { - (t, t) //~ use of moved value: `t` + (t, t) //~ ERROR use of moved value: `t` } fn duplicate_custom_4(t: S) -> (S, S) @@ -67,14 +67,14 @@ fn duplicate_custom_4(t: S) -> (S, S) where T: B, { - (t, t) //~ use of moved value: `t` + (t, t) //~ ERROR use of moved value: `t` } #[rustfmt::skip] fn existing_colon(t: T) { //~^ HELP consider restricting type parameter `T` //~| HELP if `T` implemented `Clone`, you could clone the value - [t, t]; //~ use of moved value: `t` + [t, t]; //~ ERROR use of moved value: `t` } fn existing_colon_in_where(t: T) //~ HELP if `T` implemented `Clone`, you could clone the value @@ -82,7 +82,7 @@ where T:, //~^ HELP consider further restricting type parameter `T` { - [t, t]; //~ use of moved value: `t` + [t, t]; //~ ERROR use of moved value: `t` } fn main() {} diff --git a/tests/ui/nested-cfg-attrs.rs b/tests/ui/nested-cfg-attrs.rs index 0af28fc3d8ec..941807a84310 100644 --- a/tests/ui/nested-cfg-attrs.rs +++ b/tests/ui/nested-cfg-attrs.rs @@ -1,4 +1,4 @@ -#[cfg_attr(all(), cfg_attr(all(), cfg(FALSE)))] +#[cfg_attr(all(), cfg_attr(all(), cfg(false)))] fn f() {} fn main() { f() } //~ ERROR cannot find function `f` in this scope diff --git a/tests/ui/nested-ty-params.rs b/tests/ui/nested-ty-params.rs index 866e6230f9ea..c00c3bc33723 100644 --- a/tests/ui/nested-ty-params.rs +++ b/tests/ui/nested-ty-params.rs @@ -1,4 +1,3 @@ -//@ error-pattern:can't use generic parameters from outer item fn hd(v: Vec ) -> U { fn hd1(w: [U]) -> U { return w[0]; } //~^ ERROR can't use generic parameters from outer item diff --git a/tests/ui/nested-ty-params.stderr b/tests/ui/nested-ty-params.stderr index a9cdec667199..7ca65b421b25 100644 --- a/tests/ui/nested-ty-params.stderr +++ b/tests/ui/nested-ty-params.stderr @@ -1,5 +1,5 @@ error[E0401]: can't use generic parameters from outer item - --> $DIR/nested-ty-params.rs:3:16 + --> $DIR/nested-ty-params.rs:2:16 | LL | fn hd(v: Vec ) -> U { | - type parameter from outer item @@ -9,7 +9,7 @@ LL | fn hd1(w: [U]) -> U { return w[0]; } | help: try introducing a local generic parameter here: `` error[E0401]: can't use generic parameters from outer item - --> $DIR/nested-ty-params.rs:3:23 + --> $DIR/nested-ty-params.rs:2:23 | LL | fn hd(v: Vec ) -> U { | - type parameter from outer item diff --git a/tests/ui/never_type/fallback-closure-wrap.rs b/tests/ui/never_type/fallback-closure-wrap.rs index e7f7d5aae3f8..106b82b5f781 100644 --- a/tests/ui/never_type/fallback-closure-wrap.rs +++ b/tests/ui/never_type/fallback-closure-wrap.rs @@ -17,7 +17,7 @@ use std::marker::PhantomData; fn main() { let error = Closure::wrap(Box::new(move || { panic!("Can't connect to server."); - //[fallback]~^ to return `()`, but it returns `!` + //[fallback]~^ ERROR to return `()`, but it returns `!` }) as Box); } diff --git a/tests/ui/nll/borrowed-match-issue-45045.rs b/tests/ui/nll/borrowed-match-issue-45045.rs index 978eeb868edc..a252dc817caf 100644 --- a/tests/ui/nll/borrowed-match-issue-45045.rs +++ b/tests/ui/nll/borrowed-match-issue-45045.rs @@ -10,7 +10,7 @@ fn main() { let f = &mut e; let g = f; match e { - //~^ cannot use `e` because it was mutably borrowed [E0503] + //~^ ERROR cannot use `e` because it was mutably borrowed [E0503] Xyz::A => println!("a"), Xyz::B => println!("b"), }; diff --git a/tests/ui/nll/issue-48697.rs b/tests/ui/nll/issue-48697.rs index 16e29ab2a8ad..8cb5fc36949a 100644 --- a/tests/ui/nll/issue-48697.rs +++ b/tests/ui/nll/issue-48697.rs @@ -4,7 +4,7 @@ fn foo(x: &i32) -> &i32 { let z = 4; let f = &|y| y; let k = f(&z); - f(x) //~ cannot return value referencing local variable + f(x) //~ ERROR cannot return value referencing local variable } fn main() {} diff --git a/tests/ui/nll/issue-54779-anon-static-lifetime.rs b/tests/ui/nll/issue-54779-anon-static-lifetime.rs index 6b8fa608ebbb..49e4180fe8ce 100644 --- a/tests/ui/nll/issue-54779-anon-static-lifetime.rs +++ b/tests/ui/nll/issue-54779-anon-static-lifetime.rs @@ -29,7 +29,7 @@ impl DebugWith for Foo { fmt: &mut std::fmt::Formatter<'_>, ) -> std::fmt::Result { let Foo { bar } = self; - bar.debug_with(cx); //~ borrowed data escapes outside of method + bar.debug_with(cx); //~ ERROR borrowed data escapes outside of method Ok(()) } } diff --git a/tests/ui/nll/member-constraints/nested-impl-trait-fail.rs b/tests/ui/nll/member-constraints/nested-impl-trait-fail.rs index d676c967f30f..0bf32a2624fc 100644 --- a/tests/ui/nll/member-constraints/nested-impl-trait-fail.rs +++ b/tests/ui/nll/member-constraints/nested-impl-trait-fail.rs @@ -15,8 +15,8 @@ where 's: 'b, { [a] - //~^ E0700 - //~| E0700 + //~^ ERROR E0700 + //~| ERROR E0700 } // Same as the above but with late-bound regions. @@ -26,8 +26,8 @@ fn fail_late_bound<'s, 'a, 'b>( _: &'b &'s u8, ) -> impl IntoIterator + Cap<'b>> { [a] - //~^ E0700 - //~| E0700 + //~^ ERROR E0700 + //~| ERROR E0700 } fn main() {} diff --git a/tests/ui/no_std/no-std-no-start-binary.rs b/tests/ui/no_std/no-std-no-start-binary.rs index df68b99346af..6853e2d4228f 100644 --- a/tests/ui/no_std/no-std-no-start-binary.rs +++ b/tests/ui/no_std/no-std-no-start-binary.rs @@ -1,5 +1,4 @@ //@ compile-flags: -Cpanic=abort --emit link -//@ error-pattern:using `fn main` requires the standard library // Make sure that we don't emit an error message mentioning internal lang items. diff --git a/tests/ui/no_std/simple-runs.rs b/tests/ui/no_std/simple-runs.rs new file mode 100644 index 000000000000..8931ac7ed11b --- /dev/null +++ b/tests/ui/no_std/simple-runs.rs @@ -0,0 +1,41 @@ +//! Check that `no_std` binaries can link and run without depending on `libstd`. + +//@ run-pass +//@ compile-flags: -Cpanic=abort +//@ ignore-wasm different `main` convention + +#![no_std] +#![no_main] + +use core::ffi::{c_char, c_int}; +use core::panic::PanicInfo; + +// # Linux +// +// Linking `libc` is required by crt1.o, otherwise the linker fails with: +// > /usr/bin/ld: in function `_start': undefined reference to `__libc_start_main' +// +// # Apple +// +// Linking `libSystem` is required, otherwise the linker fails with: +// > ld: dynamic executables or dylibs must link with libSystem.dylib +// +// With the new linker introduced in Xcode 15, the error is instead: +// > Undefined symbols: "dyld_stub_binder", referenced from: +// +// This _can_ be worked around by raising the deployment target with +// MACOSX_DEPLOYMENT_TARGET=13.0, though it's a bit hard to test that while +// still allowing the test suite to support running with older Xcode versions. +#[cfg_attr(all(not(target_vendor = "apple"), unix), link(name = "c"))] +#[cfg_attr(target_vendor = "apple", link(name = "System"))] +extern "C" {} + +#[panic_handler] +fn panic_handler(_info: &PanicInfo<'_>) -> ! { + loop {} +} + +#[no_mangle] +extern "C" fn main(_argc: c_int, _argv: *const *const c_char) -> c_int { + 0 +} diff --git a/tests/ui/non_modrs_mods/foors_mod.rs b/tests/ui/non_modrs_mods/foors_mod.rs index b215e5f09e93..dfaa11bfe13f 100644 --- a/tests/ui/non_modrs_mods/foors_mod.rs +++ b/tests/ui/non_modrs_mods/foors_mod.rs @@ -1,6 +1,4 @@ -//@ run-pass -// -//@ ignore-test: not a test, used by non_modrs_mods.rs +//@ ignore-auxiliary (used by `./non_modrs_mods.rs`) pub mod inner_modrs_mod; pub mod inner_foors_mod; diff --git a/tests/ui/non_modrs_mods_and_inline_mods/x.rs b/tests/ui/non_modrs_mods_and_inline_mods/x.rs index c4548d39fad8..38ff011d4095 100644 --- a/tests/ui/non_modrs_mods_and_inline_mods/x.rs +++ b/tests/ui/non_modrs_mods_and_inline_mods/x.rs @@ -1,4 +1,4 @@ -//@ ignore-test: not a test +//@ ignore-auxiliary (used by `./non_modrs_mods_and_inline_mods.rs`) pub mod y { pub mod z; diff --git a/tests/ui/non_modrs_mods_and_inline_mods/x/y/z/mod.rs b/tests/ui/non_modrs_mods_and_inline_mods/x/y/z/mod.rs index ec7b7de78d8b..cac5e274fbed 100644 --- a/tests/ui/non_modrs_mods_and_inline_mods/x/y/z/mod.rs +++ b/tests/ui/non_modrs_mods_and_inline_mods/x/y/z/mod.rs @@ -1 +1 @@ -//@ ignore-test: not a test +//@ ignore-auxiliary (used by `../../../non_modrs_mods_and_inline_mods.rs`) diff --git a/tests/ui/nonscalar-cast.fixed b/tests/ui/nonscalar-cast.fixed index f6154222ca22..cb5591dbb9de 100644 --- a/tests/ui/nonscalar-cast.fixed +++ b/tests/ui/nonscalar-cast.fixed @@ -12,5 +12,5 @@ impl From for isize { } fn main() { - println!("{}", isize::from(Foo { x: 1 })); //~ non-primitive cast: `Foo` as `isize` [E0605] + println!("{}", isize::from(Foo { x: 1 })); //~ ERROR non-primitive cast: `Foo` as `isize` [E0605] } diff --git a/tests/ui/nonscalar-cast.rs b/tests/ui/nonscalar-cast.rs index 71e7c43a1db0..27429b44cd08 100644 --- a/tests/ui/nonscalar-cast.rs +++ b/tests/ui/nonscalar-cast.rs @@ -12,5 +12,5 @@ impl From for isize { } fn main() { - println!("{}", Foo { x: 1 } as isize); //~ non-primitive cast: `Foo` as `isize` [E0605] + println!("{}", Foo { x: 1 } as isize); //~ ERROR non-primitive cast: `Foo` as `isize` [E0605] } diff --git a/tests/ui/numbers-arithmetic/int.rs b/tests/ui/numbers-arithmetic/int.rs deleted file mode 100644 index 42f8e50d6efa..000000000000 --- a/tests/ui/numbers-arithmetic/int.rs +++ /dev/null @@ -1,6 +0,0 @@ -//@ run-pass - - - - -pub fn main() { let _x: isize = 10; } diff --git a/tests/ui/numbers-arithmetic/isize-base.rs b/tests/ui/numbers-arithmetic/isize-base.rs new file mode 100644 index 000000000000..412e7ac7a2e9 --- /dev/null +++ b/tests/ui/numbers-arithmetic/isize-base.rs @@ -0,0 +1,25 @@ +//! Tests basic `isize` functionality + +//@ run-pass + +pub fn main() { + // Literal matches assignment type + let a: isize = 42isize; + // Literal cast + let b: isize = 42 as isize; + // Literal type inference from assignment type + let c: isize = 42; + // Assignment type inference from literal (and later comparison) + let d = 42isize; + // Function return value type inference + let e = return_val(); + + assert_eq!(a, b); + assert_eq!(a, c); + assert_eq!(a, d); + assert_eq!(a, e); +} + +fn return_val() -> isize { + 42 +} diff --git a/tests/ui/numbers-arithmetic/saturating-float-casts-impl.rs b/tests/ui/numbers-arithmetic/saturating-float-casts-impl.rs index 4b176ef5caa6..4e578f6132fc 100644 --- a/tests/ui/numbers-arithmetic/saturating-float-casts-impl.rs +++ b/tests/ui/numbers-arithmetic/saturating-float-casts-impl.rs @@ -1,4 +1,4 @@ -//@ ignore-test (auxiliary, used by other tests) +//@ ignore-auxiliary (used by `./saturating-float-casts.rs` and `./saturating-float-casts-wasm.rs`) // Tests saturating float->int casts. See u128-as-f32.rs for the opposite direction. // diff --git a/tests/ui/numbers-arithmetic/uint.rs b/tests/ui/numbers-arithmetic/uint.rs deleted file mode 100644 index c2087b5a06c6..000000000000 --- a/tests/ui/numbers-arithmetic/uint.rs +++ /dev/null @@ -1,6 +0,0 @@ -//@ run-pass - - - - -pub fn main() { let _x: usize = 10 as usize; } diff --git a/tests/ui/numbers-arithmetic/usize-base.rs b/tests/ui/numbers-arithmetic/usize-base.rs new file mode 100644 index 000000000000..833fc0497989 --- /dev/null +++ b/tests/ui/numbers-arithmetic/usize-base.rs @@ -0,0 +1,25 @@ +//! Tests basic `usize` functionality + +//@ run-pass + +pub fn main() { + // Literal matches assignment type + let a: usize = 42usize; + // Literal cast + let b: usize = 42 as usize; + // Literal type inference from assignment type + let c: usize = 42; + // Assignment type inference from literal (and later comparison) + let d = 42usize; + // Function return value type inference + let e = return_val(); + + assert_eq!(a, b); + assert_eq!(a, c); + assert_eq!(a, d); + assert_eq!(a, e); +} + +fn return_val() -> usize { + 42 +} diff --git a/tests/ui/offset-of/offset-of-self.rs b/tests/ui/offset-of/offset-of-self.rs index e5730b8cf6cd..0a6de2ebbb35 100644 --- a/tests/ui/offset-of/offset-of-self.rs +++ b/tests/ui/offset-of/offset-of-self.rs @@ -15,8 +15,8 @@ impl S { offset_of!(Self, v) } fn v_offs_wrong_syntax() { - offset_of!(Self, Self::v); //~ offset_of expects dot-separated field and variant names - offset_of!(S, Self); //~ no field `Self` on type `S` + offset_of!(Self, Self::v); //~ ERROR offset_of expects dot-separated field and variant names + offset_of!(S, Self); //~ ERROR no field `Self` on type `S` } fn offs_in_c() -> usize { offset_of!(C, w) @@ -48,6 +48,6 @@ fn main() { offset_of!(self::S, v); offset_of!(Self, v); //~ ERROR cannot find type `Self` in this scope - offset_of!(S, self); //~ no field `self` on type `S` - offset_of!(S, v.self); //~ no field `self` on type `u8` + offset_of!(S, self); //~ ERROR no field `self` on type `S` + offset_of!(S, v.self); //~ ERROR no field `self` on type `u8` } diff --git a/tests/ui/offset-of/offset-of-tuple.rs b/tests/ui/offset-of/offset-of-tuple.rs index db00fe05583f..e84472494413 100644 --- a/tests/ui/offset-of/offset-of-tuple.rs +++ b/tests/ui/offset-of/offset-of-tuple.rs @@ -11,7 +11,7 @@ fn main() { offset_of!((u8, u8), +1); //~ ERROR no rules expected offset_of!((u8, u8), -1); //~ ERROR offset_of expects dot-separated field and variant names offset_of!((u8, u8), 1.); //~ ERROR offset_of expects dot-separated field and variant names - offset_of!((u8, u8), 1 .); //~ unexpected token: `)` + offset_of!((u8, u8), 1 .); //~ ERROR unexpected token: `)` builtin # offset_of((u8, u8), 1e2); //~ ERROR no field `1e2` builtin # offset_of((u8, u8), _0); //~ ERROR no field `_0` builtin # offset_of((u8, u8), 01); //~ ERROR no field `01` diff --git a/tests/ui/on-unimplemented/bad-annotation.rs b/tests/ui/on-unimplemented/bad-annotation.rs index 4c6610f88643..3f0f69749bf7 100644 --- a/tests/ui/on-unimplemented/bad-annotation.rs +++ b/tests/ui/on-unimplemented/bad-annotation.rs @@ -25,39 +25,39 @@ trait BadAnnotation2 {} #[rustc_on_unimplemented = "Unimplemented trait error on `{Self}` with params `<{A},{B},{}>`"] -//~^ only named generic parameters are allowed +//~^ ERROR only named generic parameters are allowed trait BadAnnotation3 {} #[rustc_on_unimplemented(lorem="")] -//~^ this attribute must have a valid +//~^ ERROR this attribute must have a valid trait BadAnnotation4 {} #[rustc_on_unimplemented(lorem(ipsum(dolor)))] -//~^ this attribute must have a valid +//~^ ERROR this attribute must have a valid trait BadAnnotation5 {} #[rustc_on_unimplemented(message="x", message="y")] -//~^ this attribute must have a valid +//~^ ERROR this attribute must have a valid trait BadAnnotation6 {} #[rustc_on_unimplemented(message="x", on(desugared, message="y"))] -//~^ this attribute must have a valid +//~^ ERROR this attribute must have a valid trait BadAnnotation7 {} #[rustc_on_unimplemented(on(), message="y")] -//~^ empty `on`-clause +//~^ ERROR empty `on`-clause trait BadAnnotation8 {} #[rustc_on_unimplemented(on="x", message="y")] -//~^ this attribute must have a valid +//~^ ERROR this attribute must have a valid trait BadAnnotation9 {} #[rustc_on_unimplemented(on(x="y"), message="y")] trait BadAnnotation10 {} #[rustc_on_unimplemented(on(desugared, on(desugared, message="x")), message="y")] -//~^ this attribute must have a valid +//~^ ERROR this attribute must have a valid trait BadAnnotation11 {} pub fn main() { diff --git a/tests/ui/optimization-remark.rs b/tests/ui/optimization-remark.rs index ebcf3b40ab25..165fc63c0076 100644 --- a/tests/ui/optimization-remark.rs +++ b/tests/ui/optimization-remark.rs @@ -12,9 +12,8 @@ // //@ [merge1] compile-flags: -Cremark=all -Cremark=giraffe //@ [merge2] compile-flags: -Cremark=inline -Cremark=giraffe -// -//@ error-pattern: inline (missed): 'f' not inlined into 'g' //@ dont-check-compiler-stderr +//@ dont-require-annotations: NOTE #[no_mangle] #[inline(never)] @@ -25,3 +24,5 @@ pub fn f() { pub fn g() { f(); } + +//~? NOTE inline (missed): 'f' not inlined into 'g' diff --git a/tests/ui/or-patterns/fn-param-wrap-parens.fixed b/tests/ui/or-patterns/fn-param-wrap-parens.fixed index 7b0bbd04d978..fbf60069c7d4 100644 --- a/tests/ui/or-patterns/fn-param-wrap-parens.fixed +++ b/tests/ui/or-patterns/fn-param-wrap-parens.fixed @@ -9,5 +9,5 @@ fn main() {} enum E { A, B } use E::*; -#[cfg(FALSE)] +#[cfg(false)] fn fun1((A | B): E) {} //~ ERROR top-level or-patterns are not allowed diff --git a/tests/ui/or-patterns/fn-param-wrap-parens.rs b/tests/ui/or-patterns/fn-param-wrap-parens.rs index dadbb8a906a7..d796f998e97c 100644 --- a/tests/ui/or-patterns/fn-param-wrap-parens.rs +++ b/tests/ui/or-patterns/fn-param-wrap-parens.rs @@ -9,5 +9,5 @@ fn main() {} enum E { A, B } use E::*; -#[cfg(FALSE)] +#[cfg(false)] fn fun1(A | B: E) {} //~ ERROR top-level or-patterns are not allowed diff --git a/tests/ui/or-patterns/inner-or-pat.rs b/tests/ui/or-patterns/inner-or-pat.rs index 4d136de00535..6c7968df7265 100644 --- a/tests/ui/or-patterns/inner-or-pat.rs +++ b/tests/ui/or-patterns/inner-or-pat.rs @@ -49,7 +49,7 @@ fn hey() { match x { x @ ("foo" | "bar") | (x @ "red" | (x @ "blue" | "red")) => { - //[or4]~^ variable `x` is not bound in all patterns + //[or4]~^ ERROR variable `x` is not bound in all patterns } _ => (), } diff --git a/tests/ui/or-patterns/or-patterns-syntactic-fail.stderr b/tests/ui/or-patterns/or-patterns-syntactic-fail.stderr index 5608138078fb..74e4ceab80e8 100644 --- a/tests/ui/or-patterns/or-patterns-syntactic-fail.stderr +++ b/tests/ui/or-patterns/or-patterns-syntactic-fail.stderr @@ -6,7 +6,6 @@ LL | let _ = |A | B: E| (); | | | while parsing the body of this closure | - = note: type ascription syntax has been removed, see issue #101728 help: you might have meant to open the body of the closure | LL | let _ = |A | { B: E| (); diff --git a/tests/ui/or-patterns/or-patterns-syntactic-pass.rs b/tests/ui/or-patterns/or-patterns-syntactic-pass.rs index 6a8d0a5adb49..6fd5840e801a 100644 --- a/tests/ui/or-patterns/or-patterns-syntactic-pass.rs +++ b/tests/ui/or-patterns/or-patterns-syntactic-pass.rs @@ -18,7 +18,7 @@ accept_pat!([p | q]); // Non-macro tests: -#[cfg(FALSE)] +#[cfg(false)] fn or_patterns() { // Top level of `let`: let (| A | B); diff --git a/tests/ui/or-patterns/remove-leading-vert.fixed b/tests/ui/or-patterns/remove-leading-vert.fixed index 3ec815c84684..136ca5765b7e 100644 --- a/tests/ui/or-patterns/remove-leading-vert.fixed +++ b/tests/ui/or-patterns/remove-leading-vert.fixed @@ -6,7 +6,7 @@ fn main() {} -#[cfg(FALSE)] +#[cfg(false)] fn leading() { fn fun1( A: E) {} //~ ERROR top-level or-patterns are not allowed fn fun2( A: E) {} //~ ERROR unexpected `||` before function parameter @@ -21,7 +21,7 @@ fn leading() { let NS { f: | A }: NS; //~ ERROR unexpected token `||` in pattern } -#[cfg(FALSE)] +#[cfg(false)] fn trailing() { let ( A ): E; //~ ERROR a trailing `|` is not allowed in an or-pattern let (a ,): (E,); //~ ERROR a trailing `|` is not allowed in an or-pattern diff --git a/tests/ui/or-patterns/remove-leading-vert.rs b/tests/ui/or-patterns/remove-leading-vert.rs index 2aeeb0e979f6..d9e9c9fe4d2f 100644 --- a/tests/ui/or-patterns/remove-leading-vert.rs +++ b/tests/ui/or-patterns/remove-leading-vert.rs @@ -6,7 +6,7 @@ fn main() {} -#[cfg(FALSE)] +#[cfg(false)] fn leading() { fn fun1( | A: E) {} //~ ERROR top-level or-patterns are not allowed fn fun2( || A: E) {} //~ ERROR unexpected `||` before function parameter @@ -21,7 +21,7 @@ fn leading() { let NS { f: || A }: NS; //~ ERROR unexpected token `||` in pattern } -#[cfg(FALSE)] +#[cfg(false)] fn trailing() { let ( A | ): E; //~ ERROR a trailing `|` is not allowed in an or-pattern let (a |,): (E,); //~ ERROR a trailing `|` is not allowed in an or-pattern diff --git a/tests/ui/or-patterns/while-parsing-this-or-pattern.rs b/tests/ui/or-patterns/while-parsing-this-or-pattern.rs index b9bfb8638b2c..b034a52ac945 100644 --- a/tests/ui/or-patterns/while-parsing-this-or-pattern.rs +++ b/tests/ui/or-patterns/while-parsing-this-or-pattern.rs @@ -3,7 +3,7 @@ fn main() { match Some(42) { Some(42) | .=. => {} //~ ERROR expected pattern, found `.` - //~^ while parsing this or-pattern starting here + //~^ NOTE while parsing this or-pattern starting here //~| NOTE expected pattern } } diff --git a/tests/ui/packed/packed-struct-generic-transmute.rs b/tests/ui/packed/packed-struct-generic-transmute.rs index 17e72bebc7dc..66972633d800 100644 --- a/tests/ui/packed/packed-struct-generic-transmute.rs +++ b/tests/ui/packed/packed-struct-generic-transmute.rs @@ -3,8 +3,6 @@ // the error points to the start of the file, not the line with the // transmute -//@ error-pattern: cannot transmute between types of different sizes, or dependently-sized types - use std::mem; #[repr(packed)] diff --git a/tests/ui/packed/packed-struct-generic-transmute.stderr b/tests/ui/packed/packed-struct-generic-transmute.stderr index e91f49884298..983742b78be1 100644 --- a/tests/ui/packed/packed-struct-generic-transmute.stderr +++ b/tests/ui/packed/packed-struct-generic-transmute.stderr @@ -1,5 +1,5 @@ error[E0512]: cannot transmute between types of different sizes, or dependently-sized types - --> $DIR/packed-struct-generic-transmute.rs:24:38 + --> $DIR/packed-struct-generic-transmute.rs:22:38 | LL | let oof: Oof<[u8; 5], i32> = mem::transmute(foo); | ^^^^^^^^^^^^^^ diff --git a/tests/ui/packed/packed-struct-transmute.rs b/tests/ui/packed/packed-struct-transmute.rs index 5ad6524ff817..24ac1f4ac41c 100644 --- a/tests/ui/packed/packed-struct-transmute.rs +++ b/tests/ui/packed/packed-struct-transmute.rs @@ -4,7 +4,6 @@ // transmute //@ normalize-stderr: "\d+ bits" -> "N bits" -//@ error-pattern: cannot transmute between types of different sizes, or dependently-sized types use std::mem; diff --git a/tests/ui/packed/packed-struct-transmute.stderr b/tests/ui/packed/packed-struct-transmute.stderr index 4d75820e9449..c5f556f6d0c1 100644 --- a/tests/ui/packed/packed-struct-transmute.stderr +++ b/tests/ui/packed/packed-struct-transmute.stderr @@ -1,5 +1,5 @@ error[E0512]: cannot transmute between types of different sizes, or dependently-sized types - --> $DIR/packed-struct-transmute.rs:26:24 + --> $DIR/packed-struct-transmute.rs:25:24 | LL | let oof: Oof = mem::transmute(foo); | ^^^^^^^^^^^^^^ diff --git a/tests/ui/panic-handler/panic-handler-bad-signature-1.rs b/tests/ui/panic-handler/panic-handler-bad-signature-1.rs index 8f42f3a8897f..71911afaa843 100644 --- a/tests/ui/panic-handler/panic-handler-bad-signature-1.rs +++ b/tests/ui/panic-handler/panic-handler-bad-signature-1.rs @@ -7,4 +7,4 @@ use core::panic::PanicInfo; #[panic_handler] fn panic(info: PanicInfo) -> () {} -//~^ `#[panic_handler]` function has wrong type [E0308] +//~^ ERROR `#[panic_handler]` function has wrong type [E0308] diff --git a/tests/ui/panic-handler/panic-handler-bad-signature-2.rs b/tests/ui/panic-handler/panic-handler-bad-signature-2.rs index 79ad4598e10c..9c0130eff21f 100644 --- a/tests/ui/panic-handler/panic-handler-bad-signature-2.rs +++ b/tests/ui/panic-handler/panic-handler-bad-signature-2.rs @@ -7,7 +7,7 @@ use core::panic::PanicInfo; #[panic_handler] fn panic(info: &'static PanicInfo) -> ! -//~^ #[panic_handler]` function has wrong type [E0308] +//~^ ERROR #[panic_handler]` function has wrong type [E0308] { loop {} } diff --git a/tests/ui/panic-handler/panic-handler-bad-signature-3.rs b/tests/ui/panic-handler/panic-handler-bad-signature-3.rs index 1c6e2e2ff492..14c8c7c63b70 100644 --- a/tests/ui/panic-handler/panic-handler-bad-signature-3.rs +++ b/tests/ui/panic-handler/panic-handler-bad-signature-3.rs @@ -6,6 +6,6 @@ use core::panic::PanicInfo; #[panic_handler] -fn panic() -> ! { //~ #[panic_handler]` function has wrong type [E0308] +fn panic() -> ! { //~ ERROR #[panic_handler]` function has wrong type [E0308] loop {} } diff --git a/tests/ui/panic-handler/panic-handler-bad-signature-5.rs b/tests/ui/panic-handler/panic-handler-bad-signature-5.rs index d7ee8f25b114..a2a0e46ec682 100644 --- a/tests/ui/panic-handler/panic-handler-bad-signature-5.rs +++ b/tests/ui/panic-handler/panic-handler-bad-signature-5.rs @@ -7,7 +7,7 @@ use core::panic::PanicInfo; #[panic_handler] fn panic(info: &PanicInfo<'static>) -> ! -//~^ #[panic_handler]` function has wrong type [E0308] +//~^ ERROR #[panic_handler]` function has wrong type [E0308] { loop {} } diff --git a/tests/ui/panic-runtime/abort-link-to-unwind-dylib.rs b/tests/ui/panic-runtime/abort-link-to-unwind-dylib.rs index 8b782413f6a4..a691ceb566b0 100644 --- a/tests/ui/panic-runtime/abort-link-to-unwind-dylib.rs +++ b/tests/ui/panic-runtime/abort-link-to-unwind-dylib.rs @@ -1,9 +1,7 @@ //@ build-fail //@ compile-flags:-C panic=abort -C prefer-dynamic //@ needs-unwind -//@ ignore-musl - no dylibs here -//@ ignore-emscripten -//@ ignore-sgx no dynamic lib support +//@ needs-crate-type: dylib // This is a test where the local crate, compiled with `panic=abort`, links to // the standard library **dynamically** which is already linked against diff --git a/tests/ui/panic-runtime/two-panic-runtimes.rs b/tests/ui/panic-runtime/two-panic-runtimes.rs index 15c08cbe30d3..80591edd1077 100644 --- a/tests/ui/panic-runtime/two-panic-runtimes.rs +++ b/tests/ui/panic-runtime/two-panic-runtimes.rs @@ -1,7 +1,6 @@ // ignore-tidy-linelength //@ build-fail -//@ compile-flags: --error-format=human -//@ error-pattern: cannot link together two panic runtimes: panic_runtime_unwind and panic_runtime_unwind2 +//@ dont-require-annotations: ERROR //@ dont-check-compiler-stderr //@ aux-build:panic-runtime-unwind.rs //@ aux-build:panic-runtime-unwind2.rs @@ -16,7 +15,8 @@ extern crate panic_runtime_lang_items; fn main() {} -// FIXME: The second and third errors are target-dependent. -//FIXME~? ERROR cannot link together two panic runtimes: panic_runtime_unwind and panic_runtime_unwind2 +//~? ERROR cannot link together two panic runtimes: panic_runtime_unwind and panic_runtime_unwind2 +// FIXME: These errors are target-dependent, could be served by some "optional error" annotation +// instead of `dont-require-annotations`. //FIXME~? ERROR the linked panic runtime `panic_runtime_unwind2` is not compiled with this crate's panic strategy `abort` //FIXME~? ERROR the crate `panic_runtime_unwind` requires panic strategy `unwind` which is incompatible with this crate's strategy of `abort` diff --git a/tests/ui/panic-runtime/want-abort-got-unwind.rs b/tests/ui/panic-runtime/want-abort-got-unwind.rs index ed61c2613df8..42cdf8bc6626 100644 --- a/tests/ui/panic-runtime/want-abort-got-unwind.rs +++ b/tests/ui/panic-runtime/want-abort-got-unwind.rs @@ -1,7 +1,6 @@ // ignore-tidy-linelength //@ build-fail -//@ compile-flags: --error-format=human -//@ error-pattern: the linked panic runtime `panic_runtime_unwind` is not compiled with this crate's panic strategy `abort` +//@ dont-require-annotations: ERROR //@ dont-check-compiler-stderr //@ aux-build:panic-runtime-unwind.rs //@ compile-flags:-C panic=abort @@ -10,7 +9,8 @@ extern crate panic_runtime_unwind; fn main() {} -// FIXME: The first and third errors are target-dependent. +//~? ERROR the linked panic runtime `panic_runtime_unwind` is not compiled with this crate's panic strategy `abort` +// FIXME: These errors are target-dependent, could be served by some "optional error" annotation +// instead of `dont-require-annotations`. //FIXME~? ERROR cannot link together two panic runtimes: panic_unwind and panic_runtime_unwind -//FIXME~? ERROR the linked panic runtime `panic_runtime_unwind` is not compiled with this crate's panic strategy `abort` //FIXME~? ERROR the crate `panic_unwind` requires panic strategy `unwind` which is incompatible with this crate's strategy of `abort` diff --git a/tests/ui/panic-runtime/want-abort-got-unwind2.rs b/tests/ui/panic-runtime/want-abort-got-unwind2.rs index 504fd779e09a..ddf12cd2a9a5 100644 --- a/tests/ui/panic-runtime/want-abort-got-unwind2.rs +++ b/tests/ui/panic-runtime/want-abort-got-unwind2.rs @@ -1,7 +1,6 @@ // ignore-tidy-linelength //@ build-fail -//@ compile-flags: --error-format=human -//@ error-pattern: the linked panic runtime `panic_runtime_unwind` is not compiled with this crate's panic strategy `abort` +//@ dont-require-annotations: ERROR //@ dont-check-compiler-stderr //@ aux-build:panic-runtime-unwind.rs //@ aux-build:wants-panic-runtime-unwind.rs @@ -11,7 +10,8 @@ extern crate wants_panic_runtime_unwind; fn main() {} -// FIXME: The first and third errors are target-dependent. +//~? ERROR the linked panic runtime `panic_runtime_unwind` is not compiled with this crate's panic strategy `abort` +// FIXME: These errors are target-dependent, could be served by some "optional error" annotation +// instead of `dont-require-annotations`. //FIXME~? ERROR cannot link together two panic runtimes: panic_unwind and panic_runtime_unwind -//FIXME~? ERROR the linked panic runtime `panic_runtime_unwind` is not compiled with this crate's panic strategy `abort` //FIXME~? ERROR the crate `panic_unwind` requires panic strategy `unwind` which is incompatible with this crate's strategy of `abort` diff --git a/tests/ui/parallel-rustc/cache-after-waiting-issue-111528.rs b/tests/ui/parallel-rustc/cache-after-waiting-issue-111528.rs index b23cb9ce917b..73d173022f6a 100644 --- a/tests/ui/parallel-rustc/cache-after-waiting-issue-111528.rs +++ b/tests/ui/parallel-rustc/cache-after-waiting-issue-111528.rs @@ -10,7 +10,7 @@ pub fn a() { #[export_name="fail"] pub fn b() { -//~^ Error symbol `fail` is already defined +//~^ ERROR symbol `fail` is already defined } fn main() {} diff --git a/tests/ui/parser/assoc/assoc-const-underscore-syntactic-pass.rs b/tests/ui/parser/assoc/assoc-const-underscore-syntactic-pass.rs index 6c0453791916..63c567b2d033 100644 --- a/tests/ui/parser/assoc/assoc-const-underscore-syntactic-pass.rs +++ b/tests/ui/parser/assoc/assoc-const-underscore-syntactic-pass.rs @@ -4,7 +4,7 @@ fn main() {} -#[cfg(FALSE)] +#[cfg(false)] const _: () = { pub trait A { const _: () = (); diff --git a/tests/ui/parser/assoc/assoc-static-syntactic-fail.rs b/tests/ui/parser/assoc/assoc-static-syntactic-fail.rs index 492f2ea16ef5..e875d733bd62 100644 --- a/tests/ui/parser/assoc/assoc-static-syntactic-fail.rs +++ b/tests/ui/parser/assoc/assoc-static-syntactic-fail.rs @@ -2,7 +2,7 @@ fn main() {} -#[cfg(FALSE)] +#[cfg(false)] impl S { static IA: u8 = 0; //~ ERROR associated `static` items are not allowed static IB: u8; //~ ERROR associated `static` items are not allowed @@ -12,7 +12,7 @@ impl S { //~^ ERROR a static item cannot be `default` } -#[cfg(FALSE)] +#[cfg(false)] trait T { static TA: u8 = 0; //~ ERROR associated `static` items are not allowed static TB: u8; //~ ERROR associated `static` items are not allowed @@ -22,7 +22,7 @@ trait T { //~^ ERROR a static item cannot be `default` } -#[cfg(FALSE)] +#[cfg(false)] impl T for S { static TA: u8 = 0; //~ ERROR associated `static` items are not allowed static TB: u8; //~ ERROR associated `static` items are not allowed diff --git a/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.rs b/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.rs index 26761a1d2544..1380974538a5 100644 --- a/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.rs +++ b/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.rs @@ -1,108 +1,108 @@ fn main() {} -#[cfg(FALSE)] fn e() { let _ = [#[attr]]; } +#[cfg(false)] fn e() { let _ = [#[attr]]; } //~^ ERROR expected expression, found `]` -#[cfg(FALSE)] fn e() { let _ = foo#[attr](); } +#[cfg(false)] fn e() { let _ = foo#[attr](); } //~^ ERROR expected one of -#[cfg(FALSE)] fn e() { let _ = foo(#![attr]); } +#[cfg(false)] fn e() { let _ = foo(#![attr]); } //~^ ERROR an inner attribute is not permitted in this context //~| ERROR an inner attribute is not permitted in this context //~| ERROR expected expression, found `)` -#[cfg(FALSE)] fn e() { let _ = x.foo(#![attr]); } +#[cfg(false)] fn e() { let _ = x.foo(#![attr]); } //~^ ERROR an inner attribute is not permitted in this context //~| ERROR expected expression, found `)` -#[cfg(FALSE)] fn e() { let _ = 0 + #![attr] 0; } +#[cfg(false)] fn e() { let _ = 0 + #![attr] 0; } //~^ ERROR an inner attribute is not permitted in this context -#[cfg(FALSE)] fn e() { let _ = !#![attr] 0; } +#[cfg(false)] fn e() { let _ = !#![attr] 0; } //~^ ERROR an inner attribute is not permitted in this context -#[cfg(FALSE)] fn e() { let _ = -#![attr] 0; } +#[cfg(false)] fn e() { let _ = -#![attr] 0; } //~^ ERROR an inner attribute is not permitted in this context -#[cfg(FALSE)] fn e() { let _ = x #![attr] as Y; } +#[cfg(false)] fn e() { let _ = x #![attr] as Y; } //~^ ERROR expected one of -#[cfg(FALSE)] fn e() { let _ = || #![attr] foo; } +#[cfg(false)] fn e() { let _ = || #![attr] foo; } //~^ ERROR an inner attribute is not permitted in this context -#[cfg(FALSE)] fn e() { let _ = move || #![attr] foo; } +#[cfg(false)] fn e() { let _ = move || #![attr] foo; } //~^ ERROR an inner attribute is not permitted in this context -#[cfg(FALSE)] fn e() { let _ = || #![attr] {foo}; } +#[cfg(false)] fn e() { let _ = || #![attr] {foo}; } //~^ ERROR an inner attribute is not permitted in this context -#[cfg(FALSE)] fn e() { let _ = move || #![attr] {foo}; } +#[cfg(false)] fn e() { let _ = move || #![attr] {foo}; } //~^ ERROR an inner attribute is not permitted in this context -#[cfg(FALSE)] fn e() { let _ = #[attr] ..#[attr] 0; } +#[cfg(false)] fn e() { let _ = #[attr] ..#[attr] 0; } //~^ ERROR attributes are not allowed on range expressions starting with `..` -#[cfg(FALSE)] fn e() { let _ = #[attr] ..; } +#[cfg(false)] fn e() { let _ = #[attr] ..; } //~^ ERROR attributes are not allowed on range expressions starting with `..` -#[cfg(FALSE)] fn e() { let _ = #[attr] &#![attr] 0; } +#[cfg(false)] fn e() { let _ = #[attr] &#![attr] 0; } //~^ ERROR an inner attribute is not permitted in this context -#[cfg(FALSE)] fn e() { let _ = #[attr] &mut #![attr] 0; } +#[cfg(false)] fn e() { let _ = #[attr] &mut #![attr] 0; } //~^ ERROR an inner attribute is not permitted in this context -#[cfg(FALSE)] fn e() { let _ = if 0 #[attr] {}; } +#[cfg(false)] fn e() { let _ = if 0 #[attr] {}; } //~^ ERROR outer attributes are not allowed on `if` -#[cfg(FALSE)] fn e() { let _ = if 0 {#![attr]}; } +#[cfg(false)] fn e() { let _ = if 0 {#![attr]}; } //~^ ERROR an inner attribute is not permitted in this context -#[cfg(FALSE)] fn e() { let _ = if 0 {} #[attr] else {}; } +#[cfg(false)] fn e() { let _ = if 0 {} #[attr] else {}; } //~^ ERROR expected one of -#[cfg(FALSE)] fn e() { let _ = if 0 {} else #[attr] {}; } +#[cfg(false)] fn e() { let _ = if 0 {} else #[attr] {}; } //~^ ERROR outer attributes are not allowed on `if` -#[cfg(FALSE)] fn e() { let _ = if 0 {} else {#![attr]}; } +#[cfg(false)] fn e() { let _ = if 0 {} else {#![attr]}; } //~^ ERROR an inner attribute is not permitted in this context -#[cfg(FALSE)] fn e() { let _ = if 0 {} else #[attr] if 0 {}; } +#[cfg(false)] fn e() { let _ = if 0 {} else #[attr] if 0 {}; } //~^ ERROR outer attributes are not allowed on `if` -#[cfg(FALSE)] fn e() { let _ = if 0 {} else if 0 #[attr] {}; } +#[cfg(false)] fn e() { let _ = if 0 {} else if 0 #[attr] {}; } //~^ ERROR outer attributes are not allowed on `if` -#[cfg(FALSE)] fn e() { let _ = if 0 {} else if 0 {#![attr]}; } +#[cfg(false)] fn e() { let _ = if 0 {} else if 0 {#![attr]}; } //~^ ERROR an inner attribute is not permitted in this context -#[cfg(FALSE)] fn e() { let _ = if let _ = 0 #[attr] {}; } +#[cfg(false)] fn e() { let _ = if let _ = 0 #[attr] {}; } //~^ ERROR outer attributes are not allowed on `if` -#[cfg(FALSE)] fn e() { let _ = if let _ = 0 {#![attr]}; } +#[cfg(false)] fn e() { let _ = if let _ = 0 {#![attr]}; } //~^ ERROR an inner attribute is not permitted in this context -#[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} #[attr] else {}; } +#[cfg(false)] fn e() { let _ = if let _ = 0 {} #[attr] else {}; } //~^ ERROR expected one of -#[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else #[attr] {}; } +#[cfg(false)] fn e() { let _ = if let _ = 0 {} else #[attr] {}; } //~^ ERROR outer attributes are not allowed on `if` -#[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else {#![attr]}; } +#[cfg(false)] fn e() { let _ = if let _ = 0 {} else {#![attr]}; } //~^ ERROR an inner attribute is not permitted in this context -#[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else #[attr] if let _ = 0 {}; } +#[cfg(false)] fn e() { let _ = if let _ = 0 {} else #[attr] if let _ = 0 {}; } //~^ ERROR outer attributes are not allowed on `if` -#[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 #[attr] {}; } +#[cfg(false)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 #[attr] {}; } //~^ ERROR outer attributes are not allowed on `if` -#[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 {#![attr]}; } +#[cfg(false)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 {#![attr]}; } //~^ ERROR an inner attribute is not permitted in this context -#[cfg(FALSE)] fn s() { #[attr] #![attr] let _ = 0; } +#[cfg(false)] fn s() { #[attr] #![attr] let _ = 0; } //~^ ERROR an inner attribute is not permitted following an outer attribute -#[cfg(FALSE)] fn s() { #[attr] #![attr] 0; } +#[cfg(false)] fn s() { #[attr] #![attr] 0; } //~^ ERROR an inner attribute is not permitted following an outer attribute -#[cfg(FALSE)] fn s() { #[attr] #![attr] foo!(); } +#[cfg(false)] fn s() { #[attr] #![attr] foo!(); } //~^ ERROR an inner attribute is not permitted following an outer attribute -#[cfg(FALSE)] fn s() { #[attr] #![attr] foo![]; } +#[cfg(false)] fn s() { #[attr] #![attr] foo![]; } //~^ ERROR an inner attribute is not permitted following an outer attribute -#[cfg(FALSE)] fn s() { #[attr] #![attr] foo!{}; } +#[cfg(false)] fn s() { #[attr] #![attr] foo!{}; } //~^ ERROR an inner attribute is not permitted following an outer attribute // FIXME: Allow attributes in pattern constexprs? // note: requires parens in patterns to allow disambiguation -#[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] 10 => () } } +#[cfg(false)] fn e() { match 0 { 0..=#[attr] 10 => () } } //~^ ERROR inclusive range with no end //~| ERROR expected one of `=>`, `if`, or `|`, found `#` -#[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] -10 => () } } +#[cfg(false)] fn e() { match 0 { 0..=#[attr] -10 => () } } //~^ ERROR inclusive range with no end //~| ERROR expected one of `=>`, `if`, or `|`, found `#` -#[cfg(FALSE)] fn e() { match 0 { 0..=-#[attr] 10 => () } } +#[cfg(false)] fn e() { match 0 { 0..=-#[attr] 10 => () } } //~^ ERROR unexpected token: `#` -#[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] FOO => () } } +#[cfg(false)] fn e() { match 0 { 0..=#[attr] FOO => () } } //~^ ERROR inclusive range with no end //~| ERROR expected one of `=>`, `if`, or `|`, found `#` -#[cfg(FALSE)] fn e() { let _ = x.#![attr]foo(); } +#[cfg(false)] fn e() { let _ = x.#![attr]foo(); } //~^ ERROR unexpected token: `#` //~| ERROR expected one of `.` -#[cfg(FALSE)] fn e() { let _ = x.#[attr]foo(); } +#[cfg(false)] fn e() { let _ = x.#[attr]foo(); } //~^ ERROR unexpected token: `#` //~| ERROR expected one of `.` // make sure we don't catch this bug again... -#[cfg(FALSE)] fn e() { { fn foo() { #[attr]; } } } +#[cfg(false)] fn e() { { fn foo() { #[attr]; } } } //~^ ERROR expected statement after outer attribute -#[cfg(FALSE)] fn e() { { fn foo() { #[attr] } } } +#[cfg(false)] fn e() { { fn foo() { #[attr] } } } //~^ ERROR expected statement after outer attribute diff --git a/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.stderr b/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.stderr index bd860841b806..5d94a8dcbdb8 100644 --- a/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.stderr +++ b/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.stderr @@ -1,19 +1,19 @@ error: expected expression, found `]` --> $DIR/attr-stmt-expr-attr-bad.rs:3:40 | -LL | #[cfg(FALSE)] fn e() { let _ = [#[attr]]; } +LL | #[cfg(false)] fn e() { let _ = [#[attr]]; } | ^ expected expression error: expected one of `!`, `.`, `::`, `;`, `?`, `else`, `{`, or an operator, found `#` --> $DIR/attr-stmt-expr-attr-bad.rs:5:35 | -LL | #[cfg(FALSE)] fn e() { let _ = foo#[attr](); } +LL | #[cfg(false)] fn e() { let _ = foo#[attr](); } | ^ expected one of 8 possible tokens error: an inner attribute is not permitted in this context --> $DIR/attr-stmt-expr-attr-bad.rs:7:36 | -LL | #[cfg(FALSE)] fn e() { let _ = foo(#![attr]); } +LL | #[cfg(false)] fn e() { let _ = foo(#![attr]); } | ^^^^^^^^ | = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files @@ -22,7 +22,7 @@ LL | #[cfg(FALSE)] fn e() { let _ = foo(#![attr]); } error: an inner attribute is not permitted in this context --> $DIR/attr-stmt-expr-attr-bad.rs:7:36 | -LL | #[cfg(FALSE)] fn e() { let _ = foo(#![attr]); } +LL | #[cfg(false)] fn e() { let _ = foo(#![attr]); } | ^^^^^^^^ | = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files @@ -32,13 +32,13 @@ LL | #[cfg(FALSE)] fn e() { let _ = foo(#![attr]); } error: expected expression, found `)` --> $DIR/attr-stmt-expr-attr-bad.rs:7:44 | -LL | #[cfg(FALSE)] fn e() { let _ = foo(#![attr]); } +LL | #[cfg(false)] fn e() { let _ = foo(#![attr]); } | ^ expected expression error: an inner attribute is not permitted in this context --> $DIR/attr-stmt-expr-attr-bad.rs:11:38 | -LL | #[cfg(FALSE)] fn e() { let _ = x.foo(#![attr]); } +LL | #[cfg(false)] fn e() { let _ = x.foo(#![attr]); } | ^^^^^^^^ | = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files @@ -47,13 +47,13 @@ LL | #[cfg(FALSE)] fn e() { let _ = x.foo(#![attr]); } error: expected expression, found `)` --> $DIR/attr-stmt-expr-attr-bad.rs:11:46 | -LL | #[cfg(FALSE)] fn e() { let _ = x.foo(#![attr]); } +LL | #[cfg(false)] fn e() { let _ = x.foo(#![attr]); } | ^ expected expression error: an inner attribute is not permitted in this context --> $DIR/attr-stmt-expr-attr-bad.rs:14:36 | -LL | #[cfg(FALSE)] fn e() { let _ = 0 + #![attr] 0; } +LL | #[cfg(false)] fn e() { let _ = 0 + #![attr] 0; } | ^^^^^^^^ | = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files @@ -62,7 +62,7 @@ LL | #[cfg(FALSE)] fn e() { let _ = 0 + #![attr] 0; } error: an inner attribute is not permitted in this context --> $DIR/attr-stmt-expr-attr-bad.rs:16:33 | -LL | #[cfg(FALSE)] fn e() { let _ = !#![attr] 0; } +LL | #[cfg(false)] fn e() { let _ = !#![attr] 0; } | ^^^^^^^^ | = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files @@ -71,7 +71,7 @@ LL | #[cfg(FALSE)] fn e() { let _ = !#![attr] 0; } error: an inner attribute is not permitted in this context --> $DIR/attr-stmt-expr-attr-bad.rs:18:33 | -LL | #[cfg(FALSE)] fn e() { let _ = -#![attr] 0; } +LL | #[cfg(false)] fn e() { let _ = -#![attr] 0; } | ^^^^^^^^ | = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files @@ -80,13 +80,13 @@ LL | #[cfg(FALSE)] fn e() { let _ = -#![attr] 0; } error: expected one of `!`, `.`, `::`, `;`, `?`, `else`, `{`, or an operator, found `#` --> $DIR/attr-stmt-expr-attr-bad.rs:20:34 | -LL | #[cfg(FALSE)] fn e() { let _ = x #![attr] as Y; } +LL | #[cfg(false)] fn e() { let _ = x #![attr] as Y; } | ^ expected one of 8 possible tokens error: an inner attribute is not permitted in this context --> $DIR/attr-stmt-expr-attr-bad.rs:22:35 | -LL | #[cfg(FALSE)] fn e() { let _ = || #![attr] foo; } +LL | #[cfg(false)] fn e() { let _ = || #![attr] foo; } | ^^^^^^^^ | = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files @@ -95,7 +95,7 @@ LL | #[cfg(FALSE)] fn e() { let _ = || #![attr] foo; } error: an inner attribute is not permitted in this context --> $DIR/attr-stmt-expr-attr-bad.rs:24:40 | -LL | #[cfg(FALSE)] fn e() { let _ = move || #![attr] foo; } +LL | #[cfg(false)] fn e() { let _ = move || #![attr] foo; } | ^^^^^^^^ | = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files @@ -104,7 +104,7 @@ LL | #[cfg(FALSE)] fn e() { let _ = move || #![attr] foo; } error: an inner attribute is not permitted in this context --> $DIR/attr-stmt-expr-attr-bad.rs:26:35 | -LL | #[cfg(FALSE)] fn e() { let _ = || #![attr] {foo}; } +LL | #[cfg(false)] fn e() { let _ = || #![attr] {foo}; } | ^^^^^^^^ | = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files @@ -113,7 +113,7 @@ LL | #[cfg(FALSE)] fn e() { let _ = || #![attr] {foo}; } error: an inner attribute is not permitted in this context --> $DIR/attr-stmt-expr-attr-bad.rs:28:40 | -LL | #[cfg(FALSE)] fn e() { let _ = move || #![attr] {foo}; } +LL | #[cfg(false)] fn e() { let _ = move || #![attr] {foo}; } | ^^^^^^^^ | = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files @@ -122,19 +122,19 @@ LL | #[cfg(FALSE)] fn e() { let _ = move || #![attr] {foo}; } error: attributes are not allowed on range expressions starting with `..` --> $DIR/attr-stmt-expr-attr-bad.rs:30:40 | -LL | #[cfg(FALSE)] fn e() { let _ = #[attr] ..#[attr] 0; } +LL | #[cfg(false)] fn e() { let _ = #[attr] ..#[attr] 0; } | ^^ error: attributes are not allowed on range expressions starting with `..` --> $DIR/attr-stmt-expr-attr-bad.rs:32:40 | -LL | #[cfg(FALSE)] fn e() { let _ = #[attr] ..; } +LL | #[cfg(false)] fn e() { let _ = #[attr] ..; } | ^^ error: an inner attribute is not permitted in this context --> $DIR/attr-stmt-expr-attr-bad.rs:34:41 | -LL | #[cfg(FALSE)] fn e() { let _ = #[attr] &#![attr] 0; } +LL | #[cfg(false)] fn e() { let _ = #[attr] &#![attr] 0; } | ^^^^^^^^ | = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files @@ -143,7 +143,7 @@ LL | #[cfg(FALSE)] fn e() { let _ = #[attr] &#![attr] 0; } error: an inner attribute is not permitted in this context --> $DIR/attr-stmt-expr-attr-bad.rs:36:45 | -LL | #[cfg(FALSE)] fn e() { let _ = #[attr] &mut #![attr] 0; } +LL | #[cfg(false)] fn e() { let _ = #[attr] &mut #![attr] 0; } | ^^^^^^^^ | = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files @@ -152,21 +152,21 @@ LL | #[cfg(FALSE)] fn e() { let _ = #[attr] &mut #![attr] 0; } error: outer attributes are not allowed on `if` and `else` branches --> $DIR/attr-stmt-expr-attr-bad.rs:38:37 | -LL | #[cfg(FALSE)] fn e() { let _ = if 0 #[attr] {}; } +LL | #[cfg(false)] fn e() { let _ = if 0 #[attr] {}; } | -- ^^^^^^^ -- the attributes are attached to this branch | | | the branch belongs to this `if` | help: remove the attributes | -LL - #[cfg(FALSE)] fn e() { let _ = if 0 #[attr] {}; } -LL + #[cfg(FALSE)] fn e() { let _ = if 0 {}; } +LL - #[cfg(false)] fn e() { let _ = if 0 #[attr] {}; } +LL + #[cfg(false)] fn e() { let _ = if 0 {}; } | error: an inner attribute is not permitted in this context --> $DIR/attr-stmt-expr-attr-bad.rs:40:38 | -LL | #[cfg(FALSE)] fn e() { let _ = if 0 {#![attr]}; } +LL | #[cfg(false)] fn e() { let _ = if 0 {#![attr]}; } | ^^^^^^^^ | = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files @@ -175,27 +175,27 @@ LL | #[cfg(FALSE)] fn e() { let _ = if 0 {#![attr]}; } error: expected one of `.`, `;`, `?`, `else`, or an operator, found `#` --> $DIR/attr-stmt-expr-attr-bad.rs:42:40 | -LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} #[attr] else {}; } +LL | #[cfg(false)] fn e() { let _ = if 0 {} #[attr] else {}; } | ^ expected one of `.`, `;`, `?`, `else`, or an operator error: outer attributes are not allowed on `if` and `else` branches --> $DIR/attr-stmt-expr-attr-bad.rs:44:45 | -LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} else #[attr] {}; } +LL | #[cfg(false)] fn e() { let _ = if 0 {} else #[attr] {}; } | ---- ^^^^^^^ -- the attributes are attached to this branch | | | the branch belongs to this `else` | help: remove the attributes | -LL - #[cfg(FALSE)] fn e() { let _ = if 0 {} else #[attr] {}; } -LL + #[cfg(FALSE)] fn e() { let _ = if 0 {} else {}; } +LL - #[cfg(false)] fn e() { let _ = if 0 {} else #[attr] {}; } +LL + #[cfg(false)] fn e() { let _ = if 0 {} else {}; } | error: an inner attribute is not permitted in this context --> $DIR/attr-stmt-expr-attr-bad.rs:46:46 | -LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} else {#![attr]}; } +LL | #[cfg(false)] fn e() { let _ = if 0 {} else {#![attr]}; } | ^^^^^^^^ | = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files @@ -204,35 +204,35 @@ LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} else {#![attr]}; } error: outer attributes are not allowed on `if` and `else` branches --> $DIR/attr-stmt-expr-attr-bad.rs:48:45 | -LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} else #[attr] if 0 {}; } +LL | #[cfg(false)] fn e() { let _ = if 0 {} else #[attr] if 0 {}; } | ---- ^^^^^^^ ------- the attributes are attached to this branch | | | the branch belongs to this `else` | help: remove the attributes | -LL - #[cfg(FALSE)] fn e() { let _ = if 0 {} else #[attr] if 0 {}; } -LL + #[cfg(FALSE)] fn e() { let _ = if 0 {} else if 0 {}; } +LL - #[cfg(false)] fn e() { let _ = if 0 {} else #[attr] if 0 {}; } +LL + #[cfg(false)] fn e() { let _ = if 0 {} else if 0 {}; } | error: outer attributes are not allowed on `if` and `else` branches --> $DIR/attr-stmt-expr-attr-bad.rs:50:50 | -LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} else if 0 #[attr] {}; } +LL | #[cfg(false)] fn e() { let _ = if 0 {} else if 0 #[attr] {}; } | -- ^^^^^^^ -- the attributes are attached to this branch | | | the branch belongs to this `if` | help: remove the attributes | -LL - #[cfg(FALSE)] fn e() { let _ = if 0 {} else if 0 #[attr] {}; } -LL + #[cfg(FALSE)] fn e() { let _ = if 0 {} else if 0 {}; } +LL - #[cfg(false)] fn e() { let _ = if 0 {} else if 0 #[attr] {}; } +LL + #[cfg(false)] fn e() { let _ = if 0 {} else if 0 {}; } | error: an inner attribute is not permitted in this context --> $DIR/attr-stmt-expr-attr-bad.rs:52:51 | -LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} else if 0 {#![attr]}; } +LL | #[cfg(false)] fn e() { let _ = if 0 {} else if 0 {#![attr]}; } | ^^^^^^^^ | = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files @@ -241,21 +241,21 @@ LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} else if 0 {#![attr]}; } error: outer attributes are not allowed on `if` and `else` branches --> $DIR/attr-stmt-expr-attr-bad.rs:54:45 | -LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 #[attr] {}; } +LL | #[cfg(false)] fn e() { let _ = if let _ = 0 #[attr] {}; } | -- ^^^^^^^ -- the attributes are attached to this branch | | | the branch belongs to this `if` | help: remove the attributes | -LL - #[cfg(FALSE)] fn e() { let _ = if let _ = 0 #[attr] {}; } -LL + #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {}; } +LL - #[cfg(false)] fn e() { let _ = if let _ = 0 #[attr] {}; } +LL + #[cfg(false)] fn e() { let _ = if let _ = 0 {}; } | error: an inner attribute is not permitted in this context --> $DIR/attr-stmt-expr-attr-bad.rs:56:46 | -LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {#![attr]}; } +LL | #[cfg(false)] fn e() { let _ = if let _ = 0 {#![attr]}; } | ^^^^^^^^ | = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files @@ -264,27 +264,27 @@ LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {#![attr]}; } error: expected one of `.`, `;`, `?`, `else`, or an operator, found `#` --> $DIR/attr-stmt-expr-attr-bad.rs:58:48 | -LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} #[attr] else {}; } +LL | #[cfg(false)] fn e() { let _ = if let _ = 0 {} #[attr] else {}; } | ^ expected one of `.`, `;`, `?`, `else`, or an operator error: outer attributes are not allowed on `if` and `else` branches --> $DIR/attr-stmt-expr-attr-bad.rs:60:53 | -LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else #[attr] {}; } +LL | #[cfg(false)] fn e() { let _ = if let _ = 0 {} else #[attr] {}; } | ---- ^^^^^^^ -- the attributes are attached to this branch | | | the branch belongs to this `else` | help: remove the attributes | -LL - #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else #[attr] {}; } -LL + #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else {}; } +LL - #[cfg(false)] fn e() { let _ = if let _ = 0 {} else #[attr] {}; } +LL + #[cfg(false)] fn e() { let _ = if let _ = 0 {} else {}; } | error: an inner attribute is not permitted in this context --> $DIR/attr-stmt-expr-attr-bad.rs:62:54 | -LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else {#![attr]}; } +LL | #[cfg(false)] fn e() { let _ = if let _ = 0 {} else {#![attr]}; } | ^^^^^^^^ | = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files @@ -293,35 +293,35 @@ LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else {#![attr]}; } error: outer attributes are not allowed on `if` and `else` branches --> $DIR/attr-stmt-expr-attr-bad.rs:64:53 | -LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else #[attr] if let _ = 0 {}; } +LL | #[cfg(false)] fn e() { let _ = if let _ = 0 {} else #[attr] if let _ = 0 {}; } | ---- ^^^^^^^ --------------- the attributes are attached to this branch | | | the branch belongs to this `else` | help: remove the attributes | -LL - #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else #[attr] if let _ = 0 {}; } -LL + #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 {}; } +LL - #[cfg(false)] fn e() { let _ = if let _ = 0 {} else #[attr] if let _ = 0 {}; } +LL + #[cfg(false)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 {}; } | error: outer attributes are not allowed on `if` and `else` branches --> $DIR/attr-stmt-expr-attr-bad.rs:66:66 | -LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 #[attr] {}; } +LL | #[cfg(false)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 #[attr] {}; } | -- ^^^^^^^ -- the attributes are attached to this branch | | | the branch belongs to this `if` | help: remove the attributes | -LL - #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 #[attr] {}; } -LL + #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 {}; } +LL - #[cfg(false)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 #[attr] {}; } +LL + #[cfg(false)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 {}; } | error: an inner attribute is not permitted in this context --> $DIR/attr-stmt-expr-attr-bad.rs:68:67 | -LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 {#![attr]}; } +LL | #[cfg(false)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 {#![attr]}; } | ^^^^^^^^ | = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files @@ -330,7 +330,7 @@ LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 {#![attr]} error: an inner attribute is not permitted following an outer attribute --> $DIR/attr-stmt-expr-attr-bad.rs:71:32 | -LL | #[cfg(FALSE)] fn s() { #[attr] #![attr] let _ = 0; } +LL | #[cfg(false)] fn s() { #[attr] #![attr] let _ = 0; } | ------- ^^^^^^^^ not permitted following an outer attribute | | | previous outer attribute @@ -341,7 +341,7 @@ LL | #[cfg(FALSE)] fn s() { #[attr] #![attr] let _ = 0; } error: an inner attribute is not permitted following an outer attribute --> $DIR/attr-stmt-expr-attr-bad.rs:73:32 | -LL | #[cfg(FALSE)] fn s() { #[attr] #![attr] 0; } +LL | #[cfg(false)] fn s() { #[attr] #![attr] 0; } | ------- ^^^^^^^^ not permitted following an outer attribute | | | previous outer attribute @@ -352,7 +352,7 @@ LL | #[cfg(FALSE)] fn s() { #[attr] #![attr] 0; } error: an inner attribute is not permitted following an outer attribute --> $DIR/attr-stmt-expr-attr-bad.rs:75:32 | -LL | #[cfg(FALSE)] fn s() { #[attr] #![attr] foo!(); } +LL | #[cfg(false)] fn s() { #[attr] #![attr] foo!(); } | ------- ^^^^^^^^ ------- the inner attribute doesn't annotate this item macro invocation | | | | | not permitted following an outer attribute @@ -363,7 +363,7 @@ LL | #[cfg(FALSE)] fn s() { #[attr] #![attr] foo!(); } error: an inner attribute is not permitted following an outer attribute --> $DIR/attr-stmt-expr-attr-bad.rs:77:32 | -LL | #[cfg(FALSE)] fn s() { #[attr] #![attr] foo![]; } +LL | #[cfg(false)] fn s() { #[attr] #![attr] foo![]; } | ------- ^^^^^^^^ ------- the inner attribute doesn't annotate this item macro invocation | | | | | not permitted following an outer attribute @@ -374,7 +374,7 @@ LL | #[cfg(FALSE)] fn s() { #[attr] #![attr] foo![]; } error: an inner attribute is not permitted following an outer attribute --> $DIR/attr-stmt-expr-attr-bad.rs:79:32 | -LL | #[cfg(FALSE)] fn s() { #[attr] #![attr] foo!{}; } +LL | #[cfg(false)] fn s() { #[attr] #![attr] foo!{}; } | ------- ^^^^^^^^ ------ the inner attribute doesn't annotate this item macro invocation | | | | | not permitted following an outer attribute @@ -385,100 +385,100 @@ LL | #[cfg(FALSE)] fn s() { #[attr] #![attr] foo!{}; } error[E0586]: inclusive range with no end --> $DIR/attr-stmt-expr-attr-bad.rs:85:35 | -LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] 10 => () } } +LL | #[cfg(false)] fn e() { match 0 { 0..=#[attr] 10 => () } } | ^^^ | = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) help: use `..` instead | -LL - #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] 10 => () } } -LL + #[cfg(FALSE)] fn e() { match 0 { 0..#[attr] 10 => () } } +LL - #[cfg(false)] fn e() { match 0 { 0..=#[attr] 10 => () } } +LL + #[cfg(false)] fn e() { match 0 { 0..#[attr] 10 => () } } | error: expected one of `=>`, `if`, or `|`, found `#` --> $DIR/attr-stmt-expr-attr-bad.rs:85:38 | -LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] 10 => () } } +LL | #[cfg(false)] fn e() { match 0 { 0..=#[attr] 10 => () } } | ^ expected one of `=>`, `if`, or `|` error[E0586]: inclusive range with no end --> $DIR/attr-stmt-expr-attr-bad.rs:88:35 | -LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] -10 => () } } +LL | #[cfg(false)] fn e() { match 0 { 0..=#[attr] -10 => () } } | ^^^ | = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) help: use `..` instead | -LL - #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] -10 => () } } -LL + #[cfg(FALSE)] fn e() { match 0 { 0..#[attr] -10 => () } } +LL - #[cfg(false)] fn e() { match 0 { 0..=#[attr] -10 => () } } +LL + #[cfg(false)] fn e() { match 0 { 0..#[attr] -10 => () } } | error: expected one of `=>`, `if`, or `|`, found `#` --> $DIR/attr-stmt-expr-attr-bad.rs:88:38 | -LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] -10 => () } } +LL | #[cfg(false)] fn e() { match 0 { 0..=#[attr] -10 => () } } | ^ expected one of `=>`, `if`, or `|` error: unexpected token: `#` --> $DIR/attr-stmt-expr-attr-bad.rs:91:39 | -LL | #[cfg(FALSE)] fn e() { match 0 { 0..=-#[attr] 10 => () } } +LL | #[cfg(false)] fn e() { match 0 { 0..=-#[attr] 10 => () } } | ^ error[E0586]: inclusive range with no end --> $DIR/attr-stmt-expr-attr-bad.rs:93:35 | -LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] FOO => () } } +LL | #[cfg(false)] fn e() { match 0 { 0..=#[attr] FOO => () } } | ^^^ | = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) help: use `..` instead | -LL - #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] FOO => () } } -LL + #[cfg(FALSE)] fn e() { match 0 { 0..#[attr] FOO => () } } +LL - #[cfg(false)] fn e() { match 0 { 0..=#[attr] FOO => () } } +LL + #[cfg(false)] fn e() { match 0 { 0..#[attr] FOO => () } } | error: expected one of `=>`, `if`, or `|`, found `#` --> $DIR/attr-stmt-expr-attr-bad.rs:93:38 | -LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] FOO => () } } +LL | #[cfg(false)] fn e() { match 0 { 0..=#[attr] FOO => () } } | ^ expected one of `=>`, `if`, or `|` error: unexpected token: `#` --> $DIR/attr-stmt-expr-attr-bad.rs:97:34 | -LL | #[cfg(FALSE)] fn e() { let _ = x.#![attr]foo(); } +LL | #[cfg(false)] fn e() { let _ = x.#![attr]foo(); } | ^ error: expected one of `.`, `;`, `?`, `else`, or an operator, found `#` --> $DIR/attr-stmt-expr-attr-bad.rs:97:34 | -LL | #[cfg(FALSE)] fn e() { let _ = x.#![attr]foo(); } +LL | #[cfg(false)] fn e() { let _ = x.#![attr]foo(); } | ^ expected one of `.`, `;`, `?`, `else`, or an operator error: unexpected token: `#` --> $DIR/attr-stmt-expr-attr-bad.rs:100:34 | -LL | #[cfg(FALSE)] fn e() { let _ = x.#[attr]foo(); } +LL | #[cfg(false)] fn e() { let _ = x.#[attr]foo(); } | ^ error: expected one of `.`, `;`, `?`, `else`, or an operator, found `#` --> $DIR/attr-stmt-expr-attr-bad.rs:100:34 | -LL | #[cfg(FALSE)] fn e() { let _ = x.#[attr]foo(); } +LL | #[cfg(false)] fn e() { let _ = x.#[attr]foo(); } | ^ expected one of `.`, `;`, `?`, `else`, or an operator error: expected statement after outer attribute --> $DIR/attr-stmt-expr-attr-bad.rs:105:37 | -LL | #[cfg(FALSE)] fn e() { { fn foo() { #[attr]; } } } +LL | #[cfg(false)] fn e() { { fn foo() { #[attr]; } } } | ^^^^^^^ error: expected statement after outer attribute --> $DIR/attr-stmt-expr-attr-bad.rs:107:37 | -LL | #[cfg(FALSE)] fn e() { { fn foo() { #[attr] } } } +LL | #[cfg(false)] fn e() { { fn foo() { #[attr] } } } | ^^^^^^^ error: aborting due to 53 previous errors diff --git a/tests/ui/parser/attribute/multiple-tail-expr-behind-cfg.rs b/tests/ui/parser/attribute/multiple-tail-expr-behind-cfg.rs index 33671df94928..371f19d48726 100644 --- a/tests/ui/parser/attribute/multiple-tail-expr-behind-cfg.rs +++ b/tests/ui/parser/attribute/multiple-tail-expr-behind-cfg.rs @@ -1,7 +1,7 @@ #![feature(stmt_expr_attributes)] fn foo() -> String { - #[cfg(FALSE)] + #[cfg(false)] [1, 2, 3].iter().map(|c| c.to_string()).collect::() //~ ERROR expected `;`, found `#` #[cfg(not(FALSE))] String::new() diff --git a/tests/ui/parser/attribute/multiple-tail-expr-behind-cfg.stderr b/tests/ui/parser/attribute/multiple-tail-expr-behind-cfg.stderr index 6266718162f8..3a97a14b3c30 100644 --- a/tests/ui/parser/attribute/multiple-tail-expr-behind-cfg.stderr +++ b/tests/ui/parser/attribute/multiple-tail-expr-behind-cfg.stderr @@ -1,7 +1,7 @@ error: expected `;`, found `#` --> $DIR/multiple-tail-expr-behind-cfg.rs:5:64 | -LL | #[cfg(FALSE)] +LL | #[cfg(false)] | ------------- only `;` terminated statements or tail expressions are allowed after this attribute LL | [1, 2, 3].iter().map(|c| c.to_string()).collect::() | ^ expected `;` here @@ -18,7 +18,7 @@ LL | { [1, 2, 3].iter().map(|c| c.to_string()).collect::() } | + + help: it seems like you are trying to provide different expressions depending on `cfg`, consider using `if cfg!(..)` | -LL ~ if cfg!(FALSE) { +LL ~ if cfg!(false) { LL ~ [1, 2, 3].iter().map(|c| c.to_string()).collect::() LL ~ } else if cfg!(not(FALSE)) { LL ~ String::new() diff --git a/tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body-2.rs b/tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body-2.rs index e2a62922bcc5..1cd3f13d7b67 100644 --- a/tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body-2.rs +++ b/tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body-2.rs @@ -5,7 +5,7 @@ macro_rules! the_macro { #[cfg()] $foo //~ ERROR expected `;`, found `#` - #[cfg(FALSE)] + #[cfg(false)] $bar }; } diff --git a/tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body-2.stderr b/tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body-2.stderr index fa4409f73fa5..41e7b5ab759d 100644 --- a/tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body-2.stderr +++ b/tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body-2.stderr @@ -6,7 +6,7 @@ LL | #[cfg()] LL | $foo | ^ expected `;` here LL | -LL | #[cfg(FALSE)] +LL | #[cfg(false)] | - unexpected token ... LL | the_macro!( (); (); ); diff --git a/tests/ui/parser/bad-lit-suffixes.stderr b/tests/ui/parser/bad-lit-suffixes.stderr index d6b50b0e0d1f..86ef35bf7833 100644 --- a/tests/ui/parser/bad-lit-suffixes.stderr +++ b/tests/ui/parser/bad-lit-suffixes.stderr @@ -51,7 +51,7 @@ LL | #[rustc_layout_scalar_valid_range_start(0suffix)] | = help: the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.) -warning: extern declarations without an explicit ABI are deprecated +warning: `extern` declarations without an explicit ABI are deprecated --> $DIR/bad-lit-suffixes.rs:3:1 | LL | extern @@ -59,7 +59,7 @@ LL | extern | = note: `#[warn(missing_abi)]` on by default -warning: extern declarations without an explicit ABI are deprecated +warning: `extern` declarations without an explicit ABI are deprecated --> $DIR/bad-lit-suffixes.rs:7:1 | LL | extern diff --git a/tests/ui/parser/circular_modules_hello.rs b/tests/ui/parser/circular_modules_hello.rs index eb0284d8b410..540752ea2311 100644 --- a/tests/ui/parser/circular_modules_hello.rs +++ b/tests/ui/parser/circular_modules_hello.rs @@ -1,4 +1,4 @@ -//@ ignore-test: this is an auxiliary file for circular-modules-main.rs +//@ ignore-auxiliary (used by `./circular-modules-main.rs`) #[path = "circular_modules_main.rs"] mod circular_modules_main; diff --git a/tests/ui/parser/constraints-before-generic-args-syntactic-pass.rs b/tests/ui/parser/constraints-before-generic-args-syntactic-pass.rs index ed3ffed2f802..acc58a47fbcf 100644 --- a/tests/ui/parser/constraints-before-generic-args-syntactic-pass.rs +++ b/tests/ui/parser/constraints-before-generic-args-syntactic-pass.rs @@ -1,6 +1,6 @@ //@ check-pass -#[cfg(FALSE)] +#[cfg(false)] fn syntax() { foo::(); foo::(); diff --git a/tests/ui/parser/default-on-wrong-item-kind.rs b/tests/ui/parser/default-on-wrong-item-kind.rs index 98a95cfa35a9..da990a4b4212 100644 --- a/tests/ui/parser/default-on-wrong-item-kind.rs +++ b/tests/ui/parser/default-on-wrong-item-kind.rs @@ -4,7 +4,7 @@ fn main() {} -#[cfg(FALSE)] +#[cfg(false)] mod free_items { default extern crate foo; //~ ERROR an extern crate cannot be `default` default use foo; //~ ERROR a `use` import cannot be `default` @@ -28,7 +28,7 @@ mod free_items { default macro_rules! foo {} //~ ERROR a macro definition cannot be `default` } -#[cfg(FALSE)] +#[cfg(false)] extern "C" { default extern crate foo; //~ ERROR an extern crate cannot be `default` //~^ ERROR extern crate is not supported in `extern` blocks @@ -65,7 +65,7 @@ extern "C" { //~^ ERROR macro definition is not supported in `extern` blocks } -#[cfg(FALSE)] +#[cfg(false)] impl S { default extern crate foo; //~ ERROR an extern crate cannot be `default` //~^ ERROR extern crate is not supported in `trait`s or `impl`s @@ -102,7 +102,7 @@ impl S { //~^ ERROR macro definition is not supported in `trait`s or `impl`s } -#[cfg(FALSE)] +#[cfg(false)] trait T { default extern crate foo; //~ ERROR an extern crate cannot be `default` //~^ ERROR extern crate is not supported in `trait`s or `impl`s diff --git a/tests/ui/parser/diff-markers/unclosed-delims-in-macro.rs b/tests/ui/parser/diff-markers/unclosed-delims-in-macro.rs index 41a7de03d4b7..acd608e27c61 100644 --- a/tests/ui/parser/diff-markers/unclosed-delims-in-macro.rs +++ b/tests/ui/parser/diff-markers/unclosed-delims-in-macro.rs @@ -8,4 +8,4 @@ macro_rules! foo { () { // >>>>>>> 7a4f13c blah blah blah } -} //~ this file contains an unclosed delimiter +} //~ ERROR this file contains an unclosed delimiter diff --git a/tests/ui/parser/diff-markers/unclosed-delims-in-macro.stderr b/tests/ui/parser/diff-markers/unclosed-delims-in-macro.stderr index b33f2b5d1b8b..a5558352b694 100644 --- a/tests/ui/parser/diff-markers/unclosed-delims-in-macro.stderr +++ b/tests/ui/parser/diff-markers/unclosed-delims-in-macro.stderr @@ -1,5 +1,5 @@ error: this file contains an unclosed delimiter - --> $DIR/unclosed-delims-in-macro.rs:11:48 + --> $DIR/unclosed-delims-in-macro.rs:11:54 | LL | macro_rules! foo { | - unclosed delimiter @@ -8,7 +8,7 @@ LL | () { | - this delimiter might not be properly closed... ... LL | } - | - ^ + | - ^ | | | ...as it matches this but it has different indentation diff --git a/tests/ui/parser/diff-markers/unclosed-delims.rs b/tests/ui/parser/diff-markers/unclosed-delims.rs index 827c1eebb9d5..daf2a9bac98a 100644 --- a/tests/ui/parser/diff-markers/unclosed-delims.rs +++ b/tests/ui/parser/diff-markers/unclosed-delims.rs @@ -9,4 +9,4 @@ mod tests { fn test2() { >>>>>>> 7a4f13c blah blah blah } -} //~ this file contains an unclosed delimiter +} //~ ERROR this file contains an unclosed delimiter diff --git a/tests/ui/parser/diff-markers/unclosed-delims.stderr b/tests/ui/parser/diff-markers/unclosed-delims.stderr index b2541aa47bae..cb083a043b8e 100644 --- a/tests/ui/parser/diff-markers/unclosed-delims.stderr +++ b/tests/ui/parser/diff-markers/unclosed-delims.stderr @@ -1,5 +1,5 @@ error: this file contains an unclosed delimiter - --> $DIR/unclosed-delims.rs:12:48 + --> $DIR/unclosed-delims.rs:12:54 | LL | mod tests { | - unclosed delimiter @@ -8,7 +8,7 @@ LL | fn test1() { | - this delimiter might not be properly closed... ... LL | } - | - ^ + | - ^ | | | ...as it matches this but it has different indentation diff --git a/tests/ui/parser/do-catch-suggests-try.rs b/tests/ui/parser/do-catch-suggests-try.rs index f64568d06e96..fcd55ce4059f 100644 --- a/tests/ui/parser/do-catch-suggests-try.rs +++ b/tests/ui/parser/do-catch-suggests-try.rs @@ -3,7 +3,7 @@ fn main() { let _: Option<()> = do catch {}; //~^ ERROR found removed `do catch` syntax - //~| replace with the new syntax + //~| HELP replace with the new syntax //~| following RFC #2388, the new non-placeholder syntax is `try` let _recovery_witness: () = 1; //~ ERROR mismatched types diff --git a/tests/ui/parser/extern-abi-syntactic.rs b/tests/ui/parser/extern-abi-syntactic.rs index d3e2ba0e2d3f..28565a3f4bef 100644 --- a/tests/ui/parser/extern-abi-syntactic.rs +++ b/tests/ui/parser/extern-abi-syntactic.rs @@ -5,13 +5,13 @@ fn main() {} -#[cfg(FALSE)] +#[cfg(false)] extern "some_abi_that_we_are_sure_does_not_exist_semantically" fn foo() {} -#[cfg(FALSE)] +#[cfg(false)] extern "some_abi_that_we_are_sure_does_not_exist_semantically" { fn foo(); } -#[cfg(FALSE)] +#[cfg(false)] type T = extern "some_abi_that_we_are_sure_does_not_exist_semantically" fn(); diff --git a/tests/ui/parser/extern-crate-async.rs b/tests/ui/parser/extern-crate-async.rs index 7c7769075b65..529e0f1ab5cb 100644 --- a/tests/ui/parser/extern-crate-async.rs +++ b/tests/ui/parser/extern-crate-async.rs @@ -5,8 +5,8 @@ fn main() {} -#[cfg(FALSE)] +#[cfg(false)] extern crate async; -#[cfg(FALSE)] +#[cfg(false)] extern crate async as something_else; diff --git a/tests/ui/parser/float-field.rs b/tests/ui/parser/float-field.rs index 59fefee26aa6..9bf4d90fb46b 100644 --- a/tests/ui/parser/float-field.rs +++ b/tests/ui/parser/float-field.rs @@ -39,11 +39,11 @@ fn main() { { s.0x1.1; } //~ ERROR hexadecimal float literal is not supported //~| ERROR unexpected token: `0x1.1` - //~| expected one of `.`, `;`, `?`, `}`, or an operator, found `0x1.1` + //~| ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `0x1.1` { s.0x1.1e1; } //~ ERROR hexadecimal float literal is not supported //~| ERROR unexpected token: `0x1.1e1` - //~| expected one of `.`, `;`, `?`, `}`, or an operator, found `0x1.1e1` + //~| ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `0x1.1e1` { s.0x1e+; } //~ ERROR expected expression, found `;` diff --git a/tests/ui/parser/fn-body-optional-syntactic-pass.rs b/tests/ui/parser/fn-body-optional-syntactic-pass.rs index 140471dfc774..762247e63e99 100644 --- a/tests/ui/parser/fn-body-optional-syntactic-pass.rs +++ b/tests/ui/parser/fn-body-optional-syntactic-pass.rs @@ -4,7 +4,7 @@ fn main() {} -#[cfg(FALSE)] +#[cfg(false)] fn syntax() { fn f(); fn f() {} diff --git a/tests/ui/parser/fn-header-syntactic-pass.rs b/tests/ui/parser/fn-header-syntactic-pass.rs index 065ded31b073..1e15886e5645 100644 --- a/tests/ui/parser/fn-header-syntactic-pass.rs +++ b/tests/ui/parser/fn-header-syntactic-pass.rs @@ -5,7 +5,7 @@ fn main() {} -#[cfg(FALSE)] +#[cfg(false)] fn syntax() { async fn f(); unsafe fn f(); diff --git a/tests/ui/parser/foreign-const-syntactic-fail.rs b/tests/ui/parser/foreign-const-syntactic-fail.rs index a6e77f846638..fc3cd0b3430d 100644 --- a/tests/ui/parser/foreign-const-syntactic-fail.rs +++ b/tests/ui/parser/foreign-const-syntactic-fail.rs @@ -2,7 +2,7 @@ fn main() {} -#[cfg(FALSE)] +#[cfg(false)] extern "C" { const A: isize; //~ ERROR extern items cannot be `const` const B: isize = 42; //~ ERROR extern items cannot be `const` diff --git a/tests/ui/parser/foreign-static-syntactic-pass.rs b/tests/ui/parser/foreign-static-syntactic-pass.rs index a76b9bab4911..d7c21c672ab6 100644 --- a/tests/ui/parser/foreign-static-syntactic-pass.rs +++ b/tests/ui/parser/foreign-static-syntactic-pass.rs @@ -4,7 +4,7 @@ fn main() {} -#[cfg(FALSE)] +#[cfg(false)] extern "C" { static X: u8; static mut Y: u8; diff --git a/tests/ui/parser/foreign-ty-syntactic-pass.rs b/tests/ui/parser/foreign-ty-syntactic-pass.rs index 50bb68cd83be..337276852010 100644 --- a/tests/ui/parser/foreign-ty-syntactic-pass.rs +++ b/tests/ui/parser/foreign-ty-syntactic-pass.rs @@ -2,7 +2,7 @@ fn main() {} -#[cfg(FALSE)] +#[cfg(false)] extern "C" { type A: Ord; type A<'a> where 'a: 'static; diff --git a/tests/ui/parser/impl-item-const-pass.rs b/tests/ui/parser/impl-item-const-pass.rs index 8ebdf633b5b9..6ca4cd9cd930 100644 --- a/tests/ui/parser/impl-item-const-pass.rs +++ b/tests/ui/parser/impl-item-const-pass.rs @@ -2,7 +2,7 @@ fn main() {} -#[cfg(FALSE)] +#[cfg(false)] impl X { const Y: u8; } diff --git a/tests/ui/parser/impl-item-fn-no-body-pass.rs b/tests/ui/parser/impl-item-fn-no-body-pass.rs index 5a593fe1d124..b8269fc42708 100644 --- a/tests/ui/parser/impl-item-fn-no-body-pass.rs +++ b/tests/ui/parser/impl-item-fn-no-body-pass.rs @@ -2,7 +2,7 @@ fn main() {} -#[cfg(FALSE)] +#[cfg(false)] impl X { fn f(); } diff --git a/tests/ui/parser/impl-item-type-no-body-pass.rs b/tests/ui/parser/impl-item-type-no-body-pass.rs index 039825bcc538..979b5f765960 100644 --- a/tests/ui/parser/impl-item-type-no-body-pass.rs +++ b/tests/ui/parser/impl-item-type-no-body-pass.rs @@ -2,7 +2,7 @@ fn main() {} -#[cfg(FALSE)] +#[cfg(false)] impl X { type Y; type Z: Ord; diff --git a/tests/ui/parser/impl-parsing-2.rs b/tests/ui/parser/impl-parsing-2.rs new file mode 100644 index 000000000000..7a71217b21c5 --- /dev/null +++ b/tests/ui/parser/impl-parsing-2.rs @@ -0,0 +1,4 @@ +impl ! {} // OK + +default unsafe FAIL //~ ERROR expected item, found keyword `unsafe` +//~^ ERROR `default` is not followed by an item diff --git a/tests/ui/parser/impl-parsing-2.stderr b/tests/ui/parser/impl-parsing-2.stderr new file mode 100644 index 000000000000..45e2c428242d --- /dev/null +++ b/tests/ui/parser/impl-parsing-2.stderr @@ -0,0 +1,18 @@ +error: `default` is not followed by an item + --> $DIR/impl-parsing-2.rs:3:1 + | +LL | default unsafe FAIL + | ^^^^^^^ the `default` qualifier + | + = note: only `fn`, `const`, `type`, or `impl` items may be prefixed by `default` + +error: expected item, found keyword `unsafe` + --> $DIR/impl-parsing-2.rs:3:9 + | +LL | default unsafe FAIL + | ^^^^^^ expected item + | + = note: for a full list of items that can appear in modules, see + +error: aborting due to 2 previous errors + diff --git a/tests/ui/parser/impl-parsing.rs b/tests/ui/parser/impl-parsing.rs index 80ce88855707..7692a81dd42c 100644 --- a/tests/ui/parser/impl-parsing.rs +++ b/tests/ui/parser/impl-parsing.rs @@ -2,9 +2,4 @@ impl ! {} // OK impl ! where u8: Copy {} // OK impl Trait Type {} //~ ERROR missing `for` in a trait impl -impl Trait .. {} //~ ERROR missing `for` in a trait impl impl ?Sized for Type {} //~ ERROR expected a trait, found type -impl ?Sized for .. {} //~ ERROR expected a trait, found type - -default unsafe FAIL //~ ERROR expected item, found keyword `unsafe` -//~^ ERROR `default` is not followed by an item diff --git a/tests/ui/parser/impl-parsing.stderr b/tests/ui/parser/impl-parsing.stderr index 6a24a9453e63..b2512120dc87 100644 --- a/tests/ui/parser/impl-parsing.stderr +++ b/tests/ui/parser/impl-parsing.stderr @@ -9,44 +9,11 @@ help: add `for` here LL | impl Trait for Type {} | +++ -error: missing `for` in a trait impl - --> $DIR/impl-parsing.rs:5:11 - | -LL | impl Trait .. {} - | ^ - | -help: add `for` here - | -LL | impl Trait for .. {} - | +++ - error: expected a trait, found type - --> $DIR/impl-parsing.rs:6:6 + --> $DIR/impl-parsing.rs:5:6 | LL | impl ?Sized for Type {} | ^^^^^^ -error: expected a trait, found type - --> $DIR/impl-parsing.rs:7:6 - | -LL | impl ?Sized for .. {} - | ^^^^^^ - -error: `default` is not followed by an item - --> $DIR/impl-parsing.rs:9:1 - | -LL | default unsafe FAIL - | ^^^^^^^ the `default` qualifier - | - = note: only `fn`, `const`, `type`, or `impl` items may be prefixed by `default` - -error: expected item, found keyword `unsafe` - --> $DIR/impl-parsing.rs:9:9 - | -LL | default unsafe FAIL - | ^^^^^^ expected item - | - = note: for a full list of items that can appear in modules, see - -error: aborting due to 6 previous errors +error: aborting due to 2 previous errors diff --git a/tests/ui/parser/intersection-patterns-1.fixed b/tests/ui/parser/intersection-patterns-1.fixed index f63d57472cf1..8ade795f7eef 100644 --- a/tests/ui/parser/intersection-patterns-1.fixed +++ b/tests/ui/parser/intersection-patterns-1.fixed @@ -16,8 +16,8 @@ fn main() { match s { y @ Some(x) => {} //~^ ERROR pattern on wrong side of `@` - //~| pattern on the left, should be on the right - //~| binding on the right, should be on the left + //~| NOTE pattern on the left, should be on the right + //~| NOTE binding on the right, should be on the left //~| HELP switch the order //~| SUGGESTION y @ Some(x) _ => {} @@ -26,8 +26,8 @@ fn main() { match 2 { e @ 1..=5 => {} //~^ ERROR pattern on wrong side of `@` - //~| pattern on the left, should be on the right - //~| binding on the right, should be on the left + //~| NOTE pattern on the left, should be on the right + //~| NOTE binding on the right, should be on the left //~| HELP switch the order //~| SUGGESTION e @ 1..=5 _ => {} diff --git a/tests/ui/parser/intersection-patterns-1.rs b/tests/ui/parser/intersection-patterns-1.rs index 3a457659aac2..b5a7892fd1c5 100644 --- a/tests/ui/parser/intersection-patterns-1.rs +++ b/tests/ui/parser/intersection-patterns-1.rs @@ -16,8 +16,8 @@ fn main() { match s { Some(x) @ y => {} //~^ ERROR pattern on wrong side of `@` - //~| pattern on the left, should be on the right - //~| binding on the right, should be on the left + //~| NOTE pattern on the left, should be on the right + //~| NOTE binding on the right, should be on the left //~| HELP switch the order //~| SUGGESTION y @ Some(x) _ => {} @@ -26,8 +26,8 @@ fn main() { match 2 { 1 ..= 5 @ e => {} //~^ ERROR pattern on wrong side of `@` - //~| pattern on the left, should be on the right - //~| binding on the right, should be on the left + //~| NOTE pattern on the left, should be on the right + //~| NOTE binding on the right, should be on the left //~| HELP switch the order //~| SUGGESTION e @ 1..=5 _ => {} diff --git a/tests/ui/parser/intersection-patterns-2.rs b/tests/ui/parser/intersection-patterns-2.rs index 408415e87ef9..387127fc4d97 100644 --- a/tests/ui/parser/intersection-patterns-2.rs +++ b/tests/ui/parser/intersection-patterns-2.rs @@ -12,8 +12,8 @@ fn main() { match s { Some(x) @ Some(y) => {} //~^ ERROR left-hand side of `@` must be a binding - //~| interpreted as a pattern, not a binding - //~| also a pattern + //~| NOTE interpreted as a pattern, not a binding + //~| NOTE also a pattern //~| NOTE bindings are `x`, `mut x`, `ref x`, and `ref mut x` _ => {} } diff --git a/tests/ui/parser/inverted-parameters.rs b/tests/ui/parser/inverted-parameters.rs index 5c4272504e06..bc2f53f0be1b 100644 --- a/tests/ui/parser/inverted-parameters.rs +++ b/tests/ui/parser/inverted-parameters.rs @@ -1,3 +1,5 @@ +//@ dont-require-annotations: SUGGESTION + struct S; impl S { diff --git a/tests/ui/parser/inverted-parameters.stderr b/tests/ui/parser/inverted-parameters.stderr index 866227782039..7b969032d0f9 100644 --- a/tests/ui/parser/inverted-parameters.stderr +++ b/tests/ui/parser/inverted-parameters.stderr @@ -1,5 +1,5 @@ error: expected one of `:`, `@`, or `|`, found `bar` - --> $DIR/inverted-parameters.rs:4:24 + --> $DIR/inverted-parameters.rs:6:24 | LL | fn foo(&self, &str bar) {} | -----^^^ @@ -8,7 +8,7 @@ LL | fn foo(&self, &str bar) {} | help: declare the type after the parameter binding: `: ` error: expected one of `:`, `@`, or `|`, found `quux` - --> $DIR/inverted-parameters.rs:10:10 + --> $DIR/inverted-parameters.rs:12:10 | LL | fn baz(S quux, xyzzy: i32) {} | --^^^^ @@ -17,19 +17,19 @@ LL | fn baz(S quux, xyzzy: i32) {} | help: declare the type after the parameter binding: `: ` error: expected one of `:`, `@`, or `|`, found `a` - --> $DIR/inverted-parameters.rs:15:12 + --> $DIR/inverted-parameters.rs:17:12 | LL | fn one(i32 a b) {} | ^ expected one of `:`, `@`, or `|` error: expected one of `:` or `|`, found `(` - --> $DIR/inverted-parameters.rs:18:23 + --> $DIR/inverted-parameters.rs:20:23 | LL | fn pattern((i32, i32) (a, b)) {} | ^ expected one of `:` or `|` error: expected one of `:`, `@`, or `|`, found `)` - --> $DIR/inverted-parameters.rs:21:12 + --> $DIR/inverted-parameters.rs:23:12 | LL | fn fizz(i32) {} | ^ expected one of `:`, `@`, or `|` @@ -49,7 +49,7 @@ LL | fn fizz(_: i32) {} | ++ error: expected one of `:`, `@`, or `|`, found `S` - --> $DIR/inverted-parameters.rs:27:23 + --> $DIR/inverted-parameters.rs:29:23 | LL | fn missing_colon(quux S) {} | -----^ diff --git a/tests/ui/parser/issues/circular-module-with-doc-comment-issue-97589/recursive.rs b/tests/ui/parser/issues/circular-module-with-doc-comment-issue-97589/recursive.rs index 3d758be8c055..2e9a15eb06da 100644 --- a/tests/ui/parser/issues/circular-module-with-doc-comment-issue-97589/recursive.rs +++ b/tests/ui/parser/issues/circular-module-with-doc-comment-issue-97589/recursive.rs @@ -1,4 +1,4 @@ -//@ ignore-test: this is an auxiliary file for circular-module-with-doc-comment-issue-97589.rs +//@ ignore-auxiliary (used by `./circular-module-with-doc-comment-issue-97589.rs`) //! this comment caused the circular dependency checker to break diff --git a/tests/ui/parser/issues/issue-101477-enum.fixed b/tests/ui/parser/issues/issue-101477-enum.fixed index 92c2b7c470f9..7fd08b65929d 100644 --- a/tests/ui/parser/issues/issue-101477-enum.fixed +++ b/tests/ui/parser/issues/issue-101477-enum.fixed @@ -4,7 +4,7 @@ enum Demo { A = 1, B = 2 //~ ERROR unexpected `==` - //~^ expected item, found `==` + //~^ ERROR expected item, found `==` } fn main() {} diff --git a/tests/ui/parser/issues/issue-101477-enum.rs b/tests/ui/parser/issues/issue-101477-enum.rs index 21d377384d3f..2e9d6b25c144 100644 --- a/tests/ui/parser/issues/issue-101477-enum.rs +++ b/tests/ui/parser/issues/issue-101477-enum.rs @@ -4,7 +4,7 @@ enum Demo { A = 1, B == 2 //~ ERROR unexpected `==` - //~^ expected item, found `==` + //~^ ERROR expected item, found `==` } fn main() {} diff --git a/tests/ui/parser/issues/issue-102806.rs b/tests/ui/parser/issues/issue-102806.rs index ba297bdc9677..5ee8c5c1e3de 100644 --- a/tests/ui/parser/issues/issue-102806.rs +++ b/tests/ui/parser/issues/issue-102806.rs @@ -15,7 +15,7 @@ fn pz(v: V3) { //~^ ERROR expected `..` let _ = V3 { z: 0.0, ... }; - //~^ expected identifier + //~^ ERROR expected identifier //~| ERROR missing fields `x` and `y` in initializer of `V3` let V3 { z: val, ... } = v; diff --git a/tests/ui/parser/issues/issue-35813-postfix-after-cast.stderr b/tests/ui/parser/issues/issue-35813-postfix-after-cast.stderr index e34371be3d26..64cf8baf9a5d 100644 --- a/tests/ui/parser/issues/issue-35813-postfix-after-cast.stderr +++ b/tests/ui/parser/issues/issue-35813-postfix-after-cast.stderr @@ -49,24 +49,18 @@ error: expected one of `.`, `;`, `?`, `else`, or an operator, found `:` | LL | let _ = 0i32: i32: i32.count_ones(); | ^ expected one of `.`, `;`, `?`, `else`, or an operator - | - = note: type ascription syntax has been removed, see issue #101728 error: expected one of `!`, `(`, `.`, `::`, `;`, `<`, `?`, or `else`, found `:` --> $DIR/issue-35813-postfix-after-cast.rs:43:21 | LL | let _ = 0 as i32: i32.count_ones(); | ^ expected one of 8 possible tokens - | - = note: type ascription syntax has been removed, see issue #101728 error: expected one of `.`, `;`, `?`, `else`, or an operator, found `:` --> $DIR/issue-35813-postfix-after-cast.rs:47:17 | LL | let _ = 0i32: i32 as i32.count_ones(); | ^ expected one of `.`, `;`, `?`, `else`, or an operator - | - = note: type ascription syntax has been removed, see issue #101728 error: cast cannot be followed by a method call --> $DIR/issue-35813-postfix-after-cast.rs:51:13 @@ -84,16 +78,12 @@ error: expected one of `.`, `;`, `?`, `else`, or an operator, found `:` | LL | let _ = 0i32: i32: i32 as u32 as i32.count_ones(); | ^ expected one of `.`, `;`, `?`, `else`, or an operator - | - = note: type ascription syntax has been removed, see issue #101728 error: expected one of `.`, `;`, `?`, `else`, or an operator, found `:` --> $DIR/issue-35813-postfix-after-cast.rs:60:17 | LL | let _ = 0i32: i32.count_ones(): u32; | ^ expected one of `.`, `;`, `?`, `else`, or an operator - | - = note: type ascription syntax has been removed, see issue #101728 error: cast cannot be followed by a method call --> $DIR/issue-35813-postfix-after-cast.rs:64:13 @@ -111,16 +101,12 @@ error: expected one of `.`, `;`, `?`, or `else`, found `:` | LL | let _ = 0 as i32.count_ones(): u32; | ^ expected one of `.`, `;`, `?`, or `else` - | - = note: type ascription syntax has been removed, see issue #101728 error: expected one of `.`, `;`, `?`, `else`, or an operator, found `:` --> $DIR/issue-35813-postfix-after-cast.rs:69:17 | LL | let _ = 0i32: i32.count_ones() as u32; | ^ expected one of `.`, `;`, `?`, `else`, or an operator - | - = note: type ascription syntax has been removed, see issue #101728 error: cast cannot be followed by a method call --> $DIR/issue-35813-postfix-after-cast.rs:73:13 @@ -138,8 +124,6 @@ error: expected one of `.`, `;`, `?`, `else`, or an operator, found `:` | LL | let _ = 0i32: i32: i32.count_ones() as u32 as i32; | ^ expected one of `.`, `;`, `?`, `else`, or an operator - | - = note: type ascription syntax has been removed, see issue #101728 error: cast cannot be followed by a method call --> $DIR/issue-35813-postfix-after-cast.rs:82:13 @@ -262,8 +246,6 @@ error: expected identifier, found `:` | LL | drop_ptr: F(); | ^ expected identifier - | - = note: type ascription syntax has been removed, see issue #101728 error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `:` --> $DIR/issue-35813-postfix-after-cast.rs:160:13 diff --git a/tests/ui/parser/issues/issue-48508-aux.rs b/tests/ui/parser/issues/issue-48508-aux.rs index 0f2b4427383f..0bf6490edf4d 100644 --- a/tests/ui/parser/issues/issue-48508-aux.rs +++ b/tests/ui/parser/issues/issue-48508-aux.rs @@ -1,5 +1,4 @@ -//@ run-pass -//@ ignore-test Not a test. Used by issue-48508.rs +//@ ignore-auxiliary (used by `./issue-48508.rs`) pub fn other() -> f64 { let µ = 1.0; diff --git a/tests/ui/parser/issues/issue-65041-empty-vis-matcher-in-enum.rs b/tests/ui/parser/issues/issue-65041-empty-vis-matcher-in-enum.rs index 4fa803bb318e..13bb9351bb69 100644 --- a/tests/ui/parser/issues/issue-65041-empty-vis-matcher-in-enum.rs +++ b/tests/ui/parser/issues/issue-65041-empty-vis-matcher-in-enum.rs @@ -20,7 +20,7 @@ macro_rules! mac_variant { mac_variant!(MARKER); // We also accept visibilities on variants syntactically but not semantically. -#[cfg(FALSE)] +#[cfg(false)] enum E { pub U, pub(crate) T(u8), diff --git a/tests/ui/parser/issues/issue-65041-empty-vis-matcher-in-trait.rs b/tests/ui/parser/issues/issue-65041-empty-vis-matcher-in-trait.rs index cd474db63b71..55e69cd14d6b 100644 --- a/tests/ui/parser/issues/issue-65041-empty-vis-matcher-in-trait.rs +++ b/tests/ui/parser/issues/issue-65041-empty-vis-matcher-in-trait.rs @@ -20,7 +20,7 @@ trait Alpha { } // We also accept visibilities on items in traits syntactically but not semantically. -#[cfg(FALSE)] +#[cfg(false)] trait Foo { pub fn bar(); pub(crate) type baz; diff --git a/tests/ui/parser/issues/issue-73568-lifetime-after-mut.rs b/tests/ui/parser/issues/issue-73568-lifetime-after-mut.rs index cf754a6854ec..782a46ab060e 100644 --- a/tests/ui/parser/issues/issue-73568-lifetime-after-mut.rs +++ b/tests/ui/parser/issues/issue-73568-lifetime-after-mut.rs @@ -12,7 +12,7 @@ mac!('a); // avoid false positives fn y<'a>(y: &mut 'a + Send) { - //~^ ERROR expected a path on the left-hand side of `+`, not `&mut 'a` + //~^ ERROR expected a path on the left-hand side of `+` //~| ERROR at least one trait is required for an object type let z = y as &mut 'a + Send; //~^ ERROR expected value, found trait `Send` diff --git a/tests/ui/parser/issues/issue-73568-lifetime-after-mut.stderr b/tests/ui/parser/issues/issue-73568-lifetime-after-mut.stderr index 6b8f8e4fe4ee..ae1ed72853de 100644 --- a/tests/ui/parser/issues/issue-73568-lifetime-after-mut.stderr +++ b/tests/ui/parser/issues/issue-73568-lifetime-after-mut.stderr @@ -10,11 +10,11 @@ LL - fn x<'a>(x: &mut 'a i32){} LL + fn x<'a>(x: &'a mut i32){} | -error[E0178]: expected a path on the left-hand side of `+`, not `&mut 'a` +error[E0178]: expected a path on the left-hand side of `+` --> $DIR/issue-73568-lifetime-after-mut.rs:14:13 | LL | fn y<'a>(y: &mut 'a + Send) { - | ^^^^^^^^^^^^^^ + | ^^^^^^^ | help: try adding parentheses | diff --git a/tests/ui/parser/issues/issue-87217-keyword-order/const-async-const.rs b/tests/ui/parser/issues/issue-87217-keyword-order/const-async-const.rs index e6235b1e8923..c137e1363359 100644 --- a/tests/ui/parser/issues/issue-87217-keyword-order/const-async-const.rs +++ b/tests/ui/parser/issues/issue-87217-keyword-order/const-async-const.rs @@ -10,5 +10,6 @@ const async const fn test() {} //~| ERROR functions cannot be both `const` and `async` //~| NOTE `const` because of this //~| NOTE `async` because of this +//~| NOTE fn main() {} diff --git a/tests/ui/parser/issues/issue-87217-keyword-order/several-kw-jump.rs b/tests/ui/parser/issues/issue-87217-keyword-order/several-kw-jump.rs index 40f993eafbb1..49a49d337c47 100644 --- a/tests/ui/parser/issues/issue-87217-keyword-order/several-kw-jump.rs +++ b/tests/ui/parser/issues/issue-87217-keyword-order/several-kw-jump.rs @@ -15,5 +15,6 @@ async unsafe const fn test() {} //~| ERROR functions cannot be both `const` and `async` //~| NOTE `const` because of this //~| NOTE `async` because of this +//~| NOTE fn main() {} diff --git a/tests/ui/parser/issues/issue-89574.rs b/tests/ui/parser/issues/issue-89574.rs index 276abfe71102..4d28ad051dfa 100644 --- a/tests/ui/parser/issues/issue-89574.rs +++ b/tests/ui/parser/issues/issue-89574.rs @@ -1,5 +1,5 @@ fn main() { const EMPTY_ARRAY = []; - //~^ missing type for `const` item + //~^ ERROR missing type for `const` item //~| ERROR type annotations needed } diff --git a/tests/ui/parser/issues/issue-93867.rs b/tests/ui/parser/issues/issue-93867.rs index 507447923915..192b15818963 100644 --- a/tests/ui/parser/issues/issue-93867.rs +++ b/tests/ui/parser/issues/issue-93867.rs @@ -5,6 +5,6 @@ pub struct Entry<'a, K, V> { pub fn entry<'a, K, V>() -> Entry<'a K, V> { // ^ missing comma -//~^^ expected one of `,` or `>`, found `K` +//~^^ ERROR expected one of `,` or `>`, found `K` unimplemented!() } diff --git a/tests/ui/parser/item-free-const-no-body-syntactic-pass.rs b/tests/ui/parser/item-free-const-no-body-syntactic-pass.rs index 4edbee54de67..0b9229860bf8 100644 --- a/tests/ui/parser/item-free-const-no-body-syntactic-pass.rs +++ b/tests/ui/parser/item-free-const-no-body-syntactic-pass.rs @@ -4,5 +4,5 @@ fn main() {} -#[cfg(FALSE)] +#[cfg(false)] const X: u8; diff --git a/tests/ui/parser/item-free-static-no-body-syntactic-pass.rs b/tests/ui/parser/item-free-static-no-body-syntactic-pass.rs index df5192645e11..8dae4338ee7e 100644 --- a/tests/ui/parser/item-free-static-no-body-syntactic-pass.rs +++ b/tests/ui/parser/item-free-static-no-body-syntactic-pass.rs @@ -4,5 +4,5 @@ fn main() {} -#[cfg(FALSE)] +#[cfg(false)] static X: u8; diff --git a/tests/ui/parser/item-free-type-bounds-syntactic-pass.rs b/tests/ui/parser/item-free-type-bounds-syntactic-pass.rs index 80de3cfc668d..8603dc3eaf86 100644 --- a/tests/ui/parser/item-free-type-bounds-syntactic-pass.rs +++ b/tests/ui/parser/item-free-type-bounds-syntactic-pass.rs @@ -2,7 +2,7 @@ fn main() {} -#[cfg(FALSE)] +#[cfg(false)] fn syntax() { type A: Ord; type B: Ord = u8; diff --git a/tests/ui/parser/keyword-try-as-identifier-edition2018.rs b/tests/ui/parser/keyword-try-as-identifier-edition2018.rs index 27452f4d45e8..795f32059f22 100644 --- a/tests/ui/parser/keyword-try-as-identifier-edition2018.rs +++ b/tests/ui/parser/keyword-try-as-identifier-edition2018.rs @@ -1,4 +1,4 @@ -//@ compile-flags: --edition 2018 +//@ edition: 2018 fn main() { let try = "foo"; //~ error: expected identifier, found reserved keyword `try` diff --git a/tests/ui/parser/lit-err-in-macro.stderr b/tests/ui/parser/lit-err-in-macro.stderr index 9422f22f9c8f..08fe58643d40 100644 --- a/tests/ui/parser/lit-err-in-macro.stderr +++ b/tests/ui/parser/lit-err-in-macro.stderr @@ -4,7 +4,7 @@ error: suffixes on string literals are invalid LL | f!("Foo"__); | ^^^^^^^ invalid suffix `__` -warning: extern declarations without an explicit ABI are deprecated +warning: `extern` declarations without an explicit ABI are deprecated --> $DIR/lit-err-in-macro.rs:3:9 | LL | extern $abi fn f() {} diff --git a/tests/ui/parser/macro/macro-expand-to-field.rs b/tests/ui/parser/macro/macro-expand-to-field.rs index ccdcf013cd25..f5100a5d7003 100644 --- a/tests/ui/parser/macro/macro-expand-to-field.rs +++ b/tests/ui/parser/macro/macro-expand-to-field.rs @@ -49,7 +49,7 @@ enum EnumVariantField { field!(oopsies:()), //~^ NOTE macros cannot expand to struct fields //~| ERROR unexpected token: `!` - //~| unexpected token after this + //~| NOTE unexpected token after this field!(oopsies2:()), }, } diff --git a/tests/ui/parser/macro/trait-object-macro-matcher.e2015.stderr b/tests/ui/parser/macro/trait-object-macro-matcher.e2015.stderr new file mode 100644 index 000000000000..f2db351de4a7 --- /dev/null +++ b/tests/ui/parser/macro/trait-object-macro-matcher.e2015.stderr @@ -0,0 +1,32 @@ +error: lifetimes must be followed by `+` to form a trait object type + --> $DIR/trait-object-macro-matcher.rs:17:8 + | +LL | m!('static); + | ^^^^^^^ + | +help: consider adding a trait bound after the potential lifetime bound + | +LL | m!('static + /* Trait */); + | +++++++++++++ + +error: lifetimes must be followed by `+` to form a trait object type + --> $DIR/trait-object-macro-matcher.rs:17:8 + | +LL | m!('static); + | ^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider adding a trait bound after the potential lifetime bound + | +LL | m!('static + /* Trait */); + | +++++++++++++ + +error[E0224]: at least one trait is required for an object type + --> $DIR/trait-object-macro-matcher.rs:17:8 + | +LL | m!('static); + | ^^^^^^^ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0224`. diff --git a/tests/ui/parser/macro/trait-object-macro-matcher.e2021.stderr b/tests/ui/parser/macro/trait-object-macro-matcher.e2021.stderr new file mode 100644 index 000000000000..7d9e8d795d18 --- /dev/null +++ b/tests/ui/parser/macro/trait-object-macro-matcher.e2021.stderr @@ -0,0 +1,16 @@ +error: expected type, found lifetime + --> $DIR/trait-object-macro-matcher.rs:17:8 + | +LL | m!('static); + | ^^^^^^^ expected type + +error: expected type, found lifetime + --> $DIR/trait-object-macro-matcher.rs:17:8 + | +LL | m!('static); + | ^^^^^^^ expected type + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/parser/macro/trait-object-macro-matcher.rs b/tests/ui/parser/macro/trait-object-macro-matcher.rs index d4ec199070e7..ba61752fe402 100644 --- a/tests/ui/parser/macro/trait-object-macro-matcher.rs +++ b/tests/ui/parser/macro/trait-object-macro-matcher.rs @@ -1,6 +1,10 @@ // A single lifetime is not parsed as a type. // `ty` matcher in particular doesn't accept a single lifetime +//@ revisions: e2015 e2021 +//@[e2015] edition: 2015 +//@[e2021] edition: 2021 + macro_rules! m { ($t: ty) => { let _: $t; @@ -8,8 +12,10 @@ macro_rules! m { } fn main() { + //[e2021]~vv ERROR expected type, found lifetime + //[e2021]~v ERROR expected type, found lifetime m!('static); - //~^ ERROR lifetime in trait object type must be followed by `+` - //~| ERROR lifetime in trait object type must be followed by `+` - //~| ERROR at least one trait is required for an object type + //[e2015]~^ ERROR lifetimes must be followed by `+` to form a trait object type + //[e2015]~| ERROR lifetimes must be followed by `+` to form a trait object type + //[e2015]~| ERROR at least one trait is required for an object type } diff --git a/tests/ui/parser/macro/trait-object-macro-matcher.stderr b/tests/ui/parser/macro/trait-object-macro-matcher.stderr deleted file mode 100644 index 81dca6f71c43..000000000000 --- a/tests/ui/parser/macro/trait-object-macro-matcher.stderr +++ /dev/null @@ -1,23 +0,0 @@ -error: lifetime in trait object type must be followed by `+` - --> $DIR/trait-object-macro-matcher.rs:11:8 - | -LL | m!('static); - | ^^^^^^^ - -error: lifetime in trait object type must be followed by `+` - --> $DIR/trait-object-macro-matcher.rs:11:8 - | -LL | m!('static); - | ^^^^^^^ - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error[E0224]: at least one trait is required for an object type - --> $DIR/trait-object-macro-matcher.rs:11:8 - | -LL | m!('static); - | ^^^^^^^ - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0224`. diff --git a/tests/ui/parser/raw/issue-70677-panic-on-unterminated-raw-str-at-eof.rs b/tests/ui/parser/raw/issue-70677-panic-on-unterminated-raw-str-at-eof.rs index bdfc29a3d57a..b7afb8fff81d 100644 --- a/tests/ui/parser/raw/issue-70677-panic-on-unterminated-raw-str-at-eof.rs +++ b/tests/ui/parser/raw/issue-70677-panic-on-unterminated-raw-str-at-eof.rs @@ -2,4 +2,4 @@ // the last byte in the file (including not having a trailing newline) // Prior to the fix you get the error: 'expected item, found `r" ...`' // because the string being unterminated wasn't properly detected. -r" //~ unterminated raw string +r" //~ ERROR unterminated raw string diff --git a/tests/ui/parser/raw/raw-byte-string-eof.rs b/tests/ui/parser/raw/raw-byte-string-eof.rs index b74907b72b0c..d62aa332c2f2 100644 --- a/tests/ui/parser/raw/raw-byte-string-eof.rs +++ b/tests/ui/parser/raw/raw-byte-string-eof.rs @@ -1,3 +1,3 @@ pub fn main() { - br##"a"#; //~ unterminated raw string + br##"a"#; //~ ERROR unterminated raw string } diff --git a/tests/ui/parser/recover/raw-no-const-mut.rs b/tests/ui/parser/recover/raw-no-const-mut.rs new file mode 100644 index 000000000000..d0ae69cc3084 --- /dev/null +++ b/tests/ui/parser/recover/raw-no-const-mut.rs @@ -0,0 +1,31 @@ +fn a() { + let x = &raw 1; + //~^ ERROR expected one of +} + +fn b() { + [&raw const 1, &raw 2] + //~^ ERROR expected one of + //~| ERROR cannot find value `raw` in this scope + //~| ERROR cannot take address of a temporary +} + +fn c() { + if x == &raw z {} + //~^ ERROR expected `{` +} + +fn d() { + f(&raw 2); + //~^ ERROR expected one of + //~| ERROR cannot find value `raw` in this scope + //~| ERROR cannot find function `f` in this scope +} + +fn e() { + let x; + x = &raw 1; + //~^ ERROR expected one of +} + +fn main() {} diff --git a/tests/ui/parser/recover/raw-no-const-mut.stderr b/tests/ui/parser/recover/raw-no-const-mut.stderr new file mode 100644 index 000000000000..65032c807953 --- /dev/null +++ b/tests/ui/parser/recover/raw-no-const-mut.stderr @@ -0,0 +1,109 @@ +error: expected one of `!`, `.`, `::`, `;`, `?`, `const`, `else`, `mut`, `{`, or an operator, found `1` + --> $DIR/raw-no-const-mut.rs:2:18 + | +LL | let x = &raw 1; + | ^ expected one of 10 possible tokens + | +help: `&raw` must be followed by `const` or `mut` to be a raw reference expression + | +LL | let x = &raw const 1; + | +++++ +LL | let x = &raw mut 1; + | +++ + +error: expected one of `!`, `,`, `.`, `::`, `?`, `]`, `const`, `mut`, `{`, or an operator, found `2` + --> $DIR/raw-no-const-mut.rs:7:25 + | +LL | [&raw const 1, &raw 2] + | ^ expected one of 10 possible tokens + | +help: `&raw` must be followed by `const` or `mut` to be a raw reference expression + | +LL | [&raw const 1, &raw const 2] + | +++++ +LL | [&raw const 1, &raw mut 2] + | +++ +help: missing `,` + | +LL | [&raw const 1, &raw, 2] + | + + +error: expected `{`, found `z` + --> $DIR/raw-no-const-mut.rs:14:18 + | +LL | if x == &raw z {} + | ^ expected `{` + | +note: the `if` expression is missing a block after this condition + --> $DIR/raw-no-const-mut.rs:14:8 + | +LL | if x == &raw z {} + | ^^^^^^^^^ +help: `&raw` must be followed by `const` or `mut` to be a raw reference expression + | +LL | if x == &raw const z {} + | +++++ +LL | if x == &raw mut z {} + | +++ + +error: expected one of `!`, `)`, `,`, `.`, `::`, `?`, `const`, `mut`, `{`, or an operator, found `2` + --> $DIR/raw-no-const-mut.rs:19:12 + | +LL | f(&raw 2); + | ^ expected one of 10 possible tokens + | +help: `&raw` must be followed by `const` or `mut` to be a raw reference expression + | +LL | f(&raw const 2); + | +++++ +LL | f(&raw mut 2); + | +++ +help: missing `,` + | +LL | f(&raw, 2); + | + + +error: expected one of `!`, `.`, `::`, `;`, `?`, `const`, `mut`, `{`, `}`, or an operator, found `1` + --> $DIR/raw-no-const-mut.rs:27:14 + | +LL | x = &raw 1; + | ^ expected one of 10 possible tokens + | +help: `&raw` must be followed by `const` or `mut` to be a raw reference expression + | +LL | x = &raw const 1; + | +++++ +LL | x = &raw mut 1; + | +++ + +error[E0425]: cannot find value `raw` in this scope + --> $DIR/raw-no-const-mut.rs:7:21 + | +LL | [&raw const 1, &raw 2] + | ^^^ not found in this scope + +error[E0425]: cannot find value `raw` in this scope + --> $DIR/raw-no-const-mut.rs:19:8 + | +LL | f(&raw 2); + | ^^^ not found in this scope + +error[E0745]: cannot take address of a temporary + --> $DIR/raw-no-const-mut.rs:7:17 + | +LL | [&raw const 1, &raw 2] + | ^ temporary value + +error[E0425]: cannot find function `f` in this scope + --> $DIR/raw-no-const-mut.rs:19:5 + | +LL | fn a() { + | ------ similarly named function `a` defined here +... +LL | f(&raw 2); + | ^ help: a function with a similar name exists: `a` + +error: aborting due to 9 previous errors + +Some errors have detailed explanations: E0425, E0745. +For more information about an error, try `rustc --explain E0425`. diff --git a/tests/ui/parser/recover/recover-ampersand-less-ref-ty.rs b/tests/ui/parser/recover/recover-ampersand-less-ref-ty.rs new file mode 100644 index 000000000000..8f1a42473b5a --- /dev/null +++ b/tests/ui/parser/recover/recover-ampersand-less-ref-ty.rs @@ -0,0 +1,13 @@ +//@ edition: 2021 + +struct Entity<'a> { + name: 'a str, //~ ERROR expected type, found lifetime + //~^ HELP you might have meant to write a reference type here +} + +struct Buffer<'buf> { + bytes: 'buf mut [u8], //~ ERROR expected type, found lifetime + //~^ HELP you might have meant to write a reference type here +} + +fn main() {} diff --git a/tests/ui/parser/recover/recover-ampersand-less-ref-ty.stderr b/tests/ui/parser/recover/recover-ampersand-less-ref-ty.stderr new file mode 100644 index 000000000000..033348b2c405 --- /dev/null +++ b/tests/ui/parser/recover/recover-ampersand-less-ref-ty.stderr @@ -0,0 +1,24 @@ +error: expected type, found lifetime + --> $DIR/recover-ampersand-less-ref-ty.rs:4:11 + | +LL | name: 'a str, + | ^^ expected type + | +help: you might have meant to write a reference type here + | +LL | name: &'a str, + | + + +error: expected type, found lifetime + --> $DIR/recover-ampersand-less-ref-ty.rs:9:12 + | +LL | bytes: 'buf mut [u8], + | ^^^^ expected type + | +help: you might have meant to write a reference type here + | +LL | bytes: &'buf mut [u8], + | + + +error: aborting due to 2 previous errors + diff --git a/tests/ui/parser/recover/recover-assoc-const-constraint.rs b/tests/ui/parser/recover/recover-assoc-const-constraint.rs index 1453e6cb5cd7..d938b4ccaca7 100644 --- a/tests/ui/parser/recover/recover-assoc-const-constraint.rs +++ b/tests/ui/parser/recover/recover-assoc-const-constraint.rs @@ -1,4 +1,4 @@ -#[cfg(FALSE)] +#[cfg(false)] fn syntax() { bar::(); //~^ ERROR associated const equality is incomplete diff --git a/tests/ui/parser/recover/recover-assoc-eq-missing-term.rs b/tests/ui/parser/recover/recover-assoc-eq-missing-term.rs index 4b42c44dc64e..73b4e22cab6f 100644 --- a/tests/ui/parser/recover/recover-assoc-eq-missing-term.rs +++ b/tests/ui/parser/recover/recover-assoc-eq-missing-term.rs @@ -1,4 +1,4 @@ -#[cfg(FALSE)] +#[cfg(false)] fn syntax() { bar::(); //~ ERROR missing type to the right of `=` } diff --git a/tests/ui/parser/recover/recover-assoc-lifetime-constraint.rs b/tests/ui/parser/recover/recover-assoc-lifetime-constraint.rs index cb65f80b0890..30bac49e63a5 100644 --- a/tests/ui/parser/recover/recover-assoc-lifetime-constraint.rs +++ b/tests/ui/parser/recover/recover-assoc-lifetime-constraint.rs @@ -1,4 +1,4 @@ -#[cfg(FALSE)] +#[cfg(false)] fn syntax() { bar::(); //~ ERROR lifetimes are not permitted in this context } diff --git a/tests/ui/parser/recover/recover-fn-trait-from-fn-kw.rs b/tests/ui/parser/recover/recover-fn-trait-from-fn-kw.rs index b6611e6273d3..1f19f4b9c064 100644 --- a/tests/ui/parser/recover/recover-fn-trait-from-fn-kw.rs +++ b/tests/ui/parser/recover/recover-fn-trait-from-fn-kw.rs @@ -6,7 +6,7 @@ fn foo2(_: T) {} fn main() { foo(|| ()); - //~^ mismatched types + //~^ ERROR mismatched types foo2(|_: ()| {}); - //~^ type mismatch in closure arguments + //~^ ERROR type mismatch in closure arguments } diff --git a/tests/ui/parser/recover/turbofish-arg-with-stray-colon.stderr b/tests/ui/parser/recover/turbofish-arg-with-stray-colon.stderr index 583b98c650f0..c0f9db9184c0 100644 --- a/tests/ui/parser/recover/turbofish-arg-with-stray-colon.stderr +++ b/tests/ui/parser/recover/turbofish-arg-with-stray-colon.stderr @@ -4,7 +4,6 @@ error: expected one of `!`, `.`, `::`, `;`, `?`, `else`, `{`, or an operator, fo LL | let x = Tr; | ^ expected one of 8 possible tokens | - = note: type ascription syntax has been removed, see issue #101728 help: maybe write a path separator here | LL | let x = Tr; diff --git a/tests/ui/parser/require-parens-for-chained-comparison.rs b/tests/ui/parser/require-parens-for-chained-comparison.rs index 916f1b83db24..21a908923f22 100644 --- a/tests/ui/parser/require-parens-for-chained-comparison.rs +++ b/tests/ui/parser/require-parens-for-chained-comparison.rs @@ -27,7 +27,7 @@ fn main() { //~| ERROR invalid label name f<'_>(); - //~^ comparison operators cannot be chained + //~^ ERROR comparison operators cannot be chained //~| HELP use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments //~| ERROR expected //~| HELP add `'` to close the char literal diff --git a/tests/ui/parser/self-param-syntactic-pass.rs b/tests/ui/parser/self-param-syntactic-pass.rs index c7fdc5297164..331e652f9c57 100644 --- a/tests/ui/parser/self-param-syntactic-pass.rs +++ b/tests/ui/parser/self-param-syntactic-pass.rs @@ -5,7 +5,7 @@ fn main() {} -#[cfg(FALSE)] +#[cfg(false)] fn free() { fn f(self) {} fn f(mut self) {} @@ -17,7 +17,7 @@ fn free() { fn f(mut self: u8) {} } -#[cfg(FALSE)] +#[cfg(false)] extern "C" { fn f(self); fn f(mut self); @@ -29,7 +29,7 @@ extern "C" { fn f(mut self: u8); } -#[cfg(FALSE)] +#[cfg(false)] trait X { fn f(self) {} fn f(mut self) {} @@ -41,7 +41,7 @@ trait X { fn f(mut self: u8) {} } -#[cfg(FALSE)] +#[cfg(false)] impl X for Y { fn f(self) {} fn f(mut self) {} @@ -53,7 +53,7 @@ impl X for Y { fn f(mut self: u8) {} } -#[cfg(FALSE)] +#[cfg(false)] impl X for Y { type X = fn(self); type X = fn(mut self); diff --git a/tests/ui/parser/shebang/issue-71471-ignore-tidy.rs b/tests/ui/parser/shebang/issue-71471-ignore-tidy.rs index e9bff91f1e8c..858c06048cc6 100644 --- a/tests/ui/parser/shebang/issue-71471-ignore-tidy.rs +++ b/tests/ui/parser/shebang/issue-71471-ignore-tidy.rs @@ -1,4 +1,4 @@ -#!B //~ expected `[`, found `B` +#!B //~ ERROR expected `[`, found `B` //@ reference: input.shebang diff --git a/tests/ui/parser/shebang/shebang-must-start-file.rs b/tests/ui/parser/shebang/shebang-must-start-file.rs index f91e32f744e1..f956cff3b081 100644 --- a/tests/ui/parser/shebang/shebang-must-start-file.rs +++ b/tests/ui/parser/shebang/shebang-must-start-file.rs @@ -1,5 +1,5 @@ // something on the first line for tidy -#!/bin/bash //~ expected `[`, found `/` +#!/bin/bash //~ ERROR expected `[`, found `/` //@ reference: input.shebang diff --git a/tests/ui/parser/stripped-nested-outline-mod-pass.rs b/tests/ui/parser/stripped-nested-outline-mod-pass.rs index 8909d8ae0eb6..166a60f257a3 100644 --- a/tests/ui/parser/stripped-nested-outline-mod-pass.rs +++ b/tests/ui/parser/stripped-nested-outline-mod-pass.rs @@ -5,7 +5,7 @@ fn main() {} -#[cfg(FALSE)] +#[cfg(false)] mod foo { mod bar { mod baz; // This was an error before. diff --git a/tests/ui/parser/ternary_operator.stderr b/tests/ui/parser/ternary_operator.stderr index 6635e1672f78..e12a7ff3718e 100644 --- a/tests/ui/parser/ternary_operator.stderr +++ b/tests/ui/parser/ternary_operator.stderr @@ -33,8 +33,6 @@ error: expected one of `.`, `;`, `?`, `else`, or an operator, found `:` | LL | let x = 5 > 2 ? { let x = vec![]: Vec; x } : { false }; | ^ expected one of `.`, `;`, `?`, `else`, or an operator - | - = note: type ascription syntax has been removed, see issue #101728 error: Rust has no ternary operator --> $DIR/ternary_operator.rs:26:19 diff --git a/tests/ui/parser/trait-item-with-defaultness-pass.rs b/tests/ui/parser/trait-item-with-defaultness-pass.rs index c636342f6ca4..164d0b13b539 100644 --- a/tests/ui/parser/trait-item-with-defaultness-pass.rs +++ b/tests/ui/parser/trait-item-with-defaultness-pass.rs @@ -2,7 +2,7 @@ fn main() {} -#[cfg(FALSE)] +#[cfg(false)] trait X { default const A: u8; default const B: u8 = 0; diff --git a/tests/ui/parser/trait-object-bad-parens.rs b/tests/ui/parser/trait-object-bad-parens.rs index 8e267c7448fe..bb047a4b4314 100644 --- a/tests/ui/parser/trait-object-bad-parens.rs +++ b/tests/ui/parser/trait-object-bad-parens.rs @@ -5,12 +5,8 @@ auto trait Auto {} fn main() { - let _: Box<((Auto)) + Auto>; - //~^ ERROR expected a path on the left-hand side of `+`, not `((Auto))` - let _: Box<(Auto + Auto) + Auto>; - //~^ ERROR expected a path on the left-hand side of `+`, not `(Auto + Auto)` - let _: Box<(Auto +) + Auto>; - //~^ ERROR expected a path on the left-hand side of `+`, not `(Auto)` - let _: Box<(dyn Auto) + Auto>; - //~^ ERROR expected a path on the left-hand side of `+`, not `(dyn Auto)` + let _: Box<((Auto)) + Auto>; //~ ERROR expected a path on the left-hand side of `+` + let _: Box<(Auto + Auto) + Auto>; //~ ERROR expected a path on the left-hand side of `+` + let _: Box<(Auto +) + Auto>; //~ ERROR expected a path on the left-hand side of `+` + let _: Box<(dyn Auto) + Auto>; //~ ERROR expected a path on the left-hand side of `+` } diff --git a/tests/ui/parser/trait-object-bad-parens.stderr b/tests/ui/parser/trait-object-bad-parens.stderr index 74e484eebee1..7c2559ce89fd 100644 --- a/tests/ui/parser/trait-object-bad-parens.stderr +++ b/tests/ui/parser/trait-object-bad-parens.stderr @@ -1,26 +1,26 @@ -error[E0178]: expected a path on the left-hand side of `+`, not `((Auto))` +error[E0178]: expected a path on the left-hand side of `+` --> $DIR/trait-object-bad-parens.rs:8:16 | LL | let _: Box<((Auto)) + Auto>; - | ^^^^^^^^^^^^^^^ expected a path + | ^^^^^^^^ expected a path -error[E0178]: expected a path on the left-hand side of `+`, not `(Auto + Auto)` - --> $DIR/trait-object-bad-parens.rs:10:16 +error[E0178]: expected a path on the left-hand side of `+` + --> $DIR/trait-object-bad-parens.rs:9:16 | LL | let _: Box<(Auto + Auto) + Auto>; - | ^^^^^^^^^^^^^^^^^^^^ expected a path + | ^^^^^^^^^^^^^ expected a path -error[E0178]: expected a path on the left-hand side of `+`, not `(Auto)` - --> $DIR/trait-object-bad-parens.rs:12:16 +error[E0178]: expected a path on the left-hand side of `+` + --> $DIR/trait-object-bad-parens.rs:10:16 | LL | let _: Box<(Auto +) + Auto>; - | ^^^^^^^^^^^^^^^ expected a path + | ^^^^^^^^ expected a path -error[E0178]: expected a path on the left-hand side of `+`, not `(dyn Auto)` - --> $DIR/trait-object-bad-parens.rs:14:16 +error[E0178]: expected a path on the left-hand side of `+` + --> $DIR/trait-object-bad-parens.rs:11:16 | LL | let _: Box<(dyn Auto) + Auto>; - | ^^^^^^^^^^^^^^^^^ expected a path + | ^^^^^^^^^^ expected a path error: aborting due to 4 previous errors diff --git a/tests/ui/parser/trait-object-lifetime-parens.stderr b/tests/ui/parser/trait-object-lifetime-parens.e2015.stderr similarity index 60% rename from tests/ui/parser/trait-object-lifetime-parens.stderr rename to tests/ui/parser/trait-object-lifetime-parens.e2015.stderr index 280c0e40c640..cf0b3d77f5b5 100644 --- a/tests/ui/parser/trait-object-lifetime-parens.stderr +++ b/tests/ui/parser/trait-object-lifetime-parens.e2015.stderr @@ -1,5 +1,5 @@ error: parenthesized lifetime bounds are not supported - --> $DIR/trait-object-lifetime-parens.rs:5:21 + --> $DIR/trait-object-lifetime-parens.rs:9:21 | LL | fn f<'a, T: Trait + ('a)>() {} | ^^^^ @@ -11,7 +11,7 @@ LL + fn f<'a, T: Trait + 'a>() {} | error: parenthesized lifetime bounds are not supported - --> $DIR/trait-object-lifetime-parens.rs:8:24 + --> $DIR/trait-object-lifetime-parens.rs:12:24 | LL | let _: Box; | ^^^^ @@ -22,11 +22,16 @@ LL - let _: Box; LL + let _: Box; | -error: lifetime in trait object type must be followed by `+` - --> $DIR/trait-object-lifetime-parens.rs:10:17 +error: lifetimes must be followed by `+` to form a trait object type + --> $DIR/trait-object-lifetime-parens.rs:16:17 | LL | let _: Box<('a) + Trait>; | ^^ + | +help: consider adding a trait bound after the potential lifetime bound + | +LL | let _: Box<('a + /* Trait */) + Trait>; + | +++++++++++++ error: aborting due to 3 previous errors diff --git a/tests/ui/parser/trait-object-lifetime-parens.e2021.stderr b/tests/ui/parser/trait-object-lifetime-parens.e2021.stderr new file mode 100644 index 000000000000..b65c079788a9 --- /dev/null +++ b/tests/ui/parser/trait-object-lifetime-parens.e2021.stderr @@ -0,0 +1,51 @@ +error: parenthesized lifetime bounds are not supported + --> $DIR/trait-object-lifetime-parens.rs:9:21 + | +LL | fn f<'a, T: Trait + ('a)>() {} + | ^^^^ + | +help: remove the parentheses + | +LL - fn f<'a, T: Trait + ('a)>() {} +LL + fn f<'a, T: Trait + 'a>() {} + | + +error: parenthesized lifetime bounds are not supported + --> $DIR/trait-object-lifetime-parens.rs:12:24 + | +LL | let _: Box; + | ^^^^ + | +help: remove the parentheses + | +LL - let _: Box; +LL + let _: Box; + | + +error: expected type, found lifetime + --> $DIR/trait-object-lifetime-parens.rs:16:17 + | +LL | let _: Box<('a) + Trait>; + | ^^ expected type + +error[E0178]: expected a path on the left-hand side of `+` + --> $DIR/trait-object-lifetime-parens.rs:16:16 + | +LL | let _: Box<('a) + Trait>; + | ^^^^ expected a path + +error[E0782]: expected a type, found a trait + --> $DIR/trait-object-lifetime-parens.rs:12:16 + | +LL | let _: Box; + | ^^^^^^^^^^^^ + | +help: you can add the `dyn` keyword if you want a trait object + | +LL | let _: Box; + | +++ + +error: aborting due to 5 previous errors + +Some errors have detailed explanations: E0178, E0782. +For more information about an error, try `rustc --explain E0178`. diff --git a/tests/ui/parser/trait-object-lifetime-parens.rs b/tests/ui/parser/trait-object-lifetime-parens.rs index f44ebe5ba5bf..0ff4660bb0d5 100644 --- a/tests/ui/parser/trait-object-lifetime-parens.rs +++ b/tests/ui/parser/trait-object-lifetime-parens.rs @@ -1,4 +1,8 @@ -#![allow(bare_trait_objects)] +//@ revisions: e2015 e2021 +//@[e2015] edition: 2015 +//@[e2021] edition: 2021 + +#![cfg_attr(e2015, allow(bare_trait_objects))] trait Trait {} @@ -6,8 +10,12 @@ fn f<'a, T: Trait + ('a)>() {} //~ ERROR parenthesized lifetime bounds are not s fn check<'a>() { let _: Box; //~ ERROR parenthesized lifetime bounds are not supported - // FIXME: It'd be great if we could add suggestion to the following case. - let _: Box<('a) + Trait>; //~ ERROR lifetime in trait object type must be followed by `+` + //[e2021]~^ ERROR expected a type, found a trait + // FIXME: It'd be great if we could suggest removing the parentheses here too. + //[e2015]~v ERROR lifetimes must be followed by `+` to form a trait object type + let _: Box<('a) + Trait>; + //[e2021]~^ ERROR expected type, found lifetime + //[e2021]~| ERROR expected a path on the left-hand side of `+` } fn main() {} diff --git a/tests/ui/parser/trait-object-polytrait-priority.rs b/tests/ui/parser/trait-object-polytrait-priority.rs index e7f085104ae9..85568f0fe1b1 100644 --- a/tests/ui/parser/trait-object-polytrait-priority.rs +++ b/tests/ui/parser/trait-object-polytrait-priority.rs @@ -4,6 +4,6 @@ trait Trait<'a> {} fn main() { let _: &for<'a> Trait<'a> + 'static; - //~^ ERROR expected a path on the left-hand side of `+`, not `&for<'a> Trait<'a>` + //~^ ERROR expected a path on the left-hand side of `+` //~| HELP try adding parentheses } diff --git a/tests/ui/parser/trait-object-polytrait-priority.stderr b/tests/ui/parser/trait-object-polytrait-priority.stderr index 8cb564e79300..a291a8e229c4 100644 --- a/tests/ui/parser/trait-object-polytrait-priority.stderr +++ b/tests/ui/parser/trait-object-polytrait-priority.stderr @@ -1,8 +1,8 @@ -error[E0178]: expected a path on the left-hand side of `+`, not `&for<'a> Trait<'a>` +error[E0178]: expected a path on the left-hand side of `+` --> $DIR/trait-object-polytrait-priority.rs:6:12 | LL | let _: &for<'a> Trait<'a> + 'static; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^ | help: try adding parentheses | diff --git a/tests/ui/parser/utf16-be-without-bom.rs b/tests/ui/parser/utf16-be-without-bom.rs index 538728735f06..1f2abc1ad561 100644 Binary files a/tests/ui/parser/utf16-be-without-bom.rs and b/tests/ui/parser/utf16-be-without-bom.rs differ diff --git a/tests/ui/parser/utf16-le-without-bom.rs b/tests/ui/parser/utf16-le-without-bom.rs index fc413663c9c0..bb95f0dd0717 100644 Binary files a/tests/ui/parser/utf16-le-without-bom.rs and b/tests/ui/parser/utf16-le-without-bom.rs differ diff --git a/tests/ui/parser/variadic-ffi-syntactic-pass.rs b/tests/ui/parser/variadic-ffi-syntactic-pass.rs index da81f1362160..ebe0b6c2dd25 100644 --- a/tests/ui/parser/variadic-ffi-syntactic-pass.rs +++ b/tests/ui/parser/variadic-ffi-syntactic-pass.rs @@ -2,31 +2,31 @@ fn main() {} -#[cfg(FALSE)] +#[cfg(false)] fn f1_1(x: isize, ...) {} -#[cfg(FALSE)] +#[cfg(false)] fn f1_2(...) {} -#[cfg(FALSE)] +#[cfg(false)] extern "C" fn f2_1(x: isize, ...) {} -#[cfg(FALSE)] +#[cfg(false)] extern "C" fn f2_2(...) {} -#[cfg(FALSE)] +#[cfg(false)] extern "C" fn f2_3(..., x: isize) {} -#[cfg(FALSE)] +#[cfg(false)] extern fn f3_1(x: isize, ...) {} -#[cfg(FALSE)] +#[cfg(false)] extern fn f3_2(...) {} -#[cfg(FALSE)] +#[cfg(false)] extern fn f3_3(..., x: isize) {} -#[cfg(FALSE)] +#[cfg(false)] extern { fn e_f1(...); fn e_f2(..., x: isize); @@ -34,7 +34,7 @@ extern { struct X; -#[cfg(FALSE)] +#[cfg(false)] impl X { fn i_f1(x: isize, ...) {} fn i_f2(...) {} @@ -42,7 +42,7 @@ impl X { fn i_f4(..., x: isize, ...) {} } -#[cfg(FALSE)] +#[cfg(false)] trait T { fn t_f1(x: isize, ...) {} fn t_f2(x: isize, ...); diff --git a/tests/ui/pattern/bindings-after-at/nested-type-ascription-syntactically-invalid.rs b/tests/ui/pattern/bindings-after-at/nested-type-ascription-syntactically-invalid.rs index 01a978d55574..9582d2729a89 100644 --- a/tests/ui/pattern/bindings-after-at/nested-type-ascription-syntactically-invalid.rs +++ b/tests/ui/pattern/bindings-after-at/nested-type-ascription-syntactically-invalid.rs @@ -13,19 +13,19 @@ fn _ok() { fn _f(_a @ _b: u8) {} // OK. } -#[cfg(FALSE)] +#[cfg(false)] fn case_1() { let a: u8 @ b = 0; //~^ ERROR expected one of `!` } -#[cfg(FALSE)] +#[cfg(false)] fn case_2() { let a @ (b: u8); //~^ ERROR expected one of `)` } -#[cfg(FALSE)] +#[cfg(false)] fn case_3() { let a: T1 @ Outer(b: T2); //~^ ERROR expected one of `!` diff --git a/tests/ui/pattern/bindings-after-at/nested-type-ascription-syntactically-invalid.stderr b/tests/ui/pattern/bindings-after-at/nested-type-ascription-syntactically-invalid.stderr index 6ce8f6d31a03..1847e407f6ba 100644 --- a/tests/ui/pattern/bindings-after-at/nested-type-ascription-syntactically-invalid.stderr +++ b/tests/ui/pattern/bindings-after-at/nested-type-ascription-syntactically-invalid.stderr @@ -11,8 +11,6 @@ error: expected one of `)`, `,`, `@`, `if`, or `|`, found `:` | LL | let a @ (b: u8); | ^ expected one of `)`, `,`, `@`, `if`, or `|` - | - = note: type ascription syntax has been removed, see issue #101728 error: expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `=`, found `@` --> $DIR/nested-type-ascription-syntactically-invalid.rs:30:15 diff --git a/tests/ui/pattern/bindings-after-at/wild-before-at-syntactically-rejected.rs b/tests/ui/pattern/bindings-after-at/wild-before-at-syntactically-rejected.rs index 50ac0ef27834..c3994d35c421 100644 --- a/tests/ui/pattern/bindings-after-at/wild-before-at-syntactically-rejected.rs +++ b/tests/ui/pattern/bindings-after-at/wild-before-at-syntactically-rejected.rs @@ -3,7 +3,7 @@ fn main() {} -#[cfg(FALSE)] +#[cfg(false)] fn wild_before_at_is_bad_syntax() { let _ @ a = 0; //~^ ERROR pattern on wrong side of `@` diff --git a/tests/ui/pattern/deref-patterns/bindings.rs b/tests/ui/pattern/deref-patterns/bindings.rs index 5881e4166a46..c14d57f3f24e 100644 --- a/tests/ui/pattern/deref-patterns/bindings.rs +++ b/tests/ui/pattern/deref-patterns/bindings.rs @@ -1,7 +1,9 @@ +//@ revisions: explicit implicit //@ run-pass #![feature(deref_patterns)] #![allow(incomplete_features)] +#[cfg(explicit)] fn simple_vec(vec: Vec) -> u32 { match vec { deref!([]) => 100, @@ -13,6 +15,19 @@ fn simple_vec(vec: Vec) -> u32 { } } +#[cfg(implicit)] +fn simple_vec(vec: Vec) -> u32 { + match vec { + [] => 100, + [x] if x == 4 => x + 4, + [x] => x, + [1, x] => x + 200, + deref!(ref slice) => slice.iter().sum(), + _ => 2000, + } +} + +#[cfg(explicit)] fn nested_vec(vecvec: Vec>) -> u32 { match vecvec { deref!([]) => 0, @@ -24,6 +39,19 @@ fn nested_vec(vecvec: Vec>) -> u32 { } } +#[cfg(implicit)] +fn nested_vec(vecvec: Vec>) -> u32 { + match vecvec { + [] => 0, + [[x]] => x, + [[0, x] | [1, x]] => x, + [ref x] => x.iter().sum(), + [[], [1, x, y]] => y - x, + _ => 2000, + } +} + +#[cfg(explicit)] fn ref_mut(val: u32) -> u32 { let mut b = Box::new(0u32); match &mut b { @@ -37,6 +65,21 @@ fn ref_mut(val: u32) -> u32 { *x } +#[cfg(implicit)] +fn ref_mut(val: u32) -> u32 { + let mut b = Box::new((0u32,)); + match &mut b { + (_x,) if false => unreachable!(), + (x,) => { + *x = val; + } + _ => unreachable!(), + } + let (x,) = &b else { unreachable!() }; + *x +} + +#[cfg(explicit)] #[rustfmt::skip] fn or_and_guard(tuple: (u32, u32)) -> u32 { let mut sum = 0; @@ -48,6 +91,18 @@ fn or_and_guard(tuple: (u32, u32)) -> u32 { sum } +#[cfg(implicit)] +#[rustfmt::skip] +fn or_and_guard(tuple: (u32, u32)) -> u32 { + let mut sum = 0; + let b = Box::new(tuple); + match b { + (x, _) | (_, x) if { sum += x; false } => {}, + _ => {}, + } + sum +} + fn main() { assert_eq!(simple_vec(vec![1]), 1); assert_eq!(simple_vec(vec![1, 2]), 202); diff --git a/tests/ui/pattern/deref-patterns/branch.rs b/tests/ui/pattern/deref-patterns/branch.rs index 1bac1006d9dc..9d72b35fd2f1 100644 --- a/tests/ui/pattern/deref-patterns/branch.rs +++ b/tests/ui/pattern/deref-patterns/branch.rs @@ -1,8 +1,10 @@ +//@ revisions: explicit implicit //@ run-pass // Test the execution of deref patterns. #![feature(deref_patterns)] #![allow(incomplete_features)] +#[cfg(explicit)] fn branch(vec: Vec) -> u32 { match vec { deref!([]) => 0, @@ -12,6 +14,17 @@ fn branch(vec: Vec) -> u32 { } } +#[cfg(implicit)] +fn branch(vec: Vec) -> u32 { + match vec { + [] => 0, + [1, _, 3] => 1, + [2, ..] => 2, + _ => 1000, + } +} + +#[cfg(explicit)] fn nested(vec: Vec>) -> u32 { match vec { deref!([deref!([]), ..]) => 1, @@ -20,6 +33,15 @@ fn nested(vec: Vec>) -> u32 { } } +#[cfg(implicit)] +fn nested(vec: Vec>) -> u32 { + match vec { + [[], ..] => 1, + [[0, ..], [1, ..]] => 2, + _ => 1000, + } +} + fn main() { assert!(matches!(Vec::::new(), deref!([]))); assert!(matches!(vec![1], deref!([1]))); diff --git a/tests/ui/pattern/deref-patterns/cant_move_out_of_pattern.rs b/tests/ui/pattern/deref-patterns/cant_move_out_of_pattern.rs index 84b5ec09dc7d..791776be5aca 100644 --- a/tests/ui/pattern/deref-patterns/cant_move_out_of_pattern.rs +++ b/tests/ui/pattern/deref-patterns/cant_move_out_of_pattern.rs @@ -21,4 +21,22 @@ fn cant_move_out_rc(rc: Rc) -> Struct { } } +struct Container(Struct); + +fn cant_move_out_box_implicit(b: Box) -> Struct { + match b { + //~^ ERROR: cannot move out of a shared reference + Container(x) => x, + _ => unreachable!(), + } +} + +fn cant_move_out_rc_implicit(rc: Rc) -> Struct { + match rc { + //~^ ERROR: cannot move out of a shared reference + Container(x) => x, + _ => unreachable!(), + } +} + fn main() {} diff --git a/tests/ui/pattern/deref-patterns/cant_move_out_of_pattern.stderr b/tests/ui/pattern/deref-patterns/cant_move_out_of_pattern.stderr index 2cf435b11799..1887800fc38a 100644 --- a/tests/ui/pattern/deref-patterns/cant_move_out_of_pattern.stderr +++ b/tests/ui/pattern/deref-patterns/cant_move_out_of_pattern.stderr @@ -32,6 +32,40 @@ help: consider borrowing the pattern binding LL | deref!(ref x) => x, | +++ -error: aborting due to 2 previous errors +error[E0507]: cannot move out of a shared reference + --> $DIR/cant_move_out_of_pattern.rs:27:11 + | +LL | match b { + | ^ +LL | +LL | Container(x) => x, + | - + | | + | data moved here + | move occurs because `x` has type `Struct`, which does not implement the `Copy` trait + | +help: consider borrowing the pattern binding + | +LL | Container(ref x) => x, + | +++ + +error[E0507]: cannot move out of a shared reference + --> $DIR/cant_move_out_of_pattern.rs:35:11 + | +LL | match rc { + | ^^ +LL | +LL | Container(x) => x, + | - + | | + | data moved here + | move occurs because `x` has type `Struct`, which does not implement the `Copy` trait + | +help: consider borrowing the pattern binding + | +LL | Container(ref x) => x, + | +++ + +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0507`. diff --git a/tests/ui/pattern/deref-patterns/closure_capture.rs b/tests/ui/pattern/deref-patterns/closure_capture.rs index fc0ddedac2b7..08586b6c7abd 100644 --- a/tests/ui/pattern/deref-patterns/closure_capture.rs +++ b/tests/ui/pattern/deref-patterns/closure_capture.rs @@ -11,6 +11,15 @@ fn main() { assert_eq!(b.len(), 3); f(); + let v = vec![1, 2, 3]; + let f = || { + // this should count as a borrow of `v` as a whole + let [.., x] = v else { unreachable!() }; + assert_eq!(x, 3); + }; + assert_eq!(v, [1, 2, 3]); + f(); + let mut b = Box::new("aaa".to_string()); let mut f = || { let deref!(ref mut s) = b else { unreachable!() }; @@ -18,4 +27,22 @@ fn main() { }; f(); assert_eq!(b.len(), 5); + + let mut v = vec![1, 2, 3]; + let mut f = || { + // this should count as a mutable borrow of `v` as a whole + let [.., ref mut x] = v else { unreachable!() }; + *x = 4; + }; + f(); + assert_eq!(v, [1, 2, 4]); + + let mut v = vec![1, 2, 3]; + let mut f = || { + // here, `[.., x]` is adjusted by both an overloaded deref and a builtin deref + let [.., x] = &mut v else { unreachable!() }; + *x = 4; + }; + f(); + assert_eq!(v, [1, 2, 4]); } diff --git a/tests/ui/pattern/deref-patterns/fake_borrows.rs b/tests/ui/pattern/deref-patterns/fake_borrows.rs index 35fa9cbf7d85..bf614d7d66fd 100644 --- a/tests/ui/pattern/deref-patterns/fake_borrows.rs +++ b/tests/ui/pattern/deref-patterns/fake_borrows.rs @@ -11,4 +11,11 @@ fn main() { deref!(false) => {} _ => {}, } + match b { + true => {} + _ if { *b = true; false } => {} + //~^ ERROR cannot assign `*b` in match guard + false => {} + _ => {}, + } } diff --git a/tests/ui/pattern/deref-patterns/fake_borrows.stderr b/tests/ui/pattern/deref-patterns/fake_borrows.stderr index 6a591e6416c5..8c060236d0df 100644 --- a/tests/ui/pattern/deref-patterns/fake_borrows.stderr +++ b/tests/ui/pattern/deref-patterns/fake_borrows.stderr @@ -7,6 +7,15 @@ LL | deref!(true) => {} LL | _ if { *b = true; false } => {} | ^^^^^^^^^ cannot assign -error: aborting due to 1 previous error +error[E0510]: cannot assign `*b` in match guard + --> $DIR/fake_borrows.rs:16:16 + | +LL | match b { + | - value is immutable in match guard +LL | true => {} +LL | _ if { *b = true; false } => {} + | ^^^^^^^^^ cannot assign + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0510`. diff --git a/tests/ui/pattern/deref-patterns/implicit-const-deref.rs b/tests/ui/pattern/deref-patterns/implicit-const-deref.rs new file mode 100644 index 000000000000..70f89629bc22 --- /dev/null +++ b/tests/ui/pattern/deref-patterns/implicit-const-deref.rs @@ -0,0 +1,19 @@ +//! Test that we get an error about structural equality rather than a type error when attempting to +//! use const patterns of library pointer types. Currently there aren't any smart pointers that can +//! be used in constant patterns, but we still need to make sure we don't implicitly dereference the +//! scrutinee and end up with a type error; this would prevent us from reporting that only constants +//! supporting structural equality can be used as patterns. +#![feature(deref_patterns)] +#![allow(incomplete_features)] + +const EMPTY: Vec<()> = Vec::new(); + +fn main() { + // FIXME(inline_const_pat): if `inline_const_pat` is reinstated, there should be a case here for + // inline const block patterns as well; they're checked differently than named constants. + match vec![()] { + EMPTY => {} + //~^ ERROR: constant of non-structural type `Vec<()>` in a pattern + _ => {} + } +} diff --git a/tests/ui/pattern/deref-patterns/implicit-const-deref.stderr b/tests/ui/pattern/deref-patterns/implicit-const-deref.stderr new file mode 100644 index 000000000000..21d09ec44c4f --- /dev/null +++ b/tests/ui/pattern/deref-patterns/implicit-const-deref.stderr @@ -0,0 +1,16 @@ +error: constant of non-structural type `Vec<()>` in a pattern + --> $DIR/implicit-const-deref.rs:15:9 + | +LL | const EMPTY: Vec<()> = Vec::new(); + | -------------------- constant defined here +... +LL | EMPTY => {} + | ^^^^^ constant of non-structural type + --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL + | + = note: `Vec<()>` must be annotated with `#[derive(PartialEq)]` to be usable in patterns + | + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details + +error: aborting due to 1 previous error + diff --git a/tests/ui/pattern/deref-patterns/implicit-cow-deref.rs b/tests/ui/pattern/deref-patterns/implicit-cow-deref.rs new file mode 100644 index 000000000000..a9b8de860107 --- /dev/null +++ b/tests/ui/pattern/deref-patterns/implicit-cow-deref.rs @@ -0,0 +1,45 @@ +//@ run-pass +//! Test that implicit deref patterns interact as expected with `Cow` constructor patterns. +#![feature(deref_patterns)] +#![allow(incomplete_features)] + +use std::borrow::Cow; + +fn main() { + let cow: Cow<'static, [u8]> = Cow::Borrowed(&[1, 2, 3]); + + match cow { + [..] => {} + _ => unreachable!(), + } + + match cow { + Cow::Borrowed(_) => {} + Cow::Owned(_) => unreachable!(), + } + + match Box::new(&cow) { + Cow::Borrowed { 0: _ } => {} + Cow::Owned { 0: _ } => unreachable!(), + _ => unreachable!(), + } + + let cow_of_cow: Cow<'_, Cow<'static, [u8]>> = Cow::Owned(cow); + + match cow_of_cow { + [..] => {} + _ => unreachable!(), + } + + // This matches on the outer `Cow` (the owned one). + match cow_of_cow { + Cow::Borrowed(_) => unreachable!(), + Cow::Owned(_) => {} + } + + match Box::new(&cow_of_cow) { + Cow::Borrowed { 0: _ } => unreachable!(), + Cow::Owned { 0: _ } => {} + _ => unreachable!(), + } +} diff --git a/tests/ui/pattern/deref-patterns/needs-gate.rs b/tests/ui/pattern/deref-patterns/needs-gate.rs new file mode 100644 index 000000000000..2d5ec45217fb --- /dev/null +++ b/tests/ui/pattern/deref-patterns/needs-gate.rs @@ -0,0 +1,15 @@ +// gate-test-deref_patterns + +fn main() { + match Box::new(0) { + deref!(0) => {} + //~^ ERROR: use of unstable library feature `deref_patterns`: placeholder syntax for deref patterns + _ => {} + } + + match Box::new(0) { + 0 => {} + //~^ ERROR: mismatched types + _ => {} + } +} diff --git a/tests/ui/pattern/deref-patterns/needs-gate.stderr b/tests/ui/pattern/deref-patterns/needs-gate.stderr new file mode 100644 index 000000000000..8687b5dc977d --- /dev/null +++ b/tests/ui/pattern/deref-patterns/needs-gate.stderr @@ -0,0 +1,29 @@ +error[E0658]: use of unstable library feature `deref_patterns`: placeholder syntax for deref patterns + --> $DIR/needs-gate.rs:5:9 + | +LL | deref!(0) => {} + | ^^^^^ + | + = note: see issue #87121 for more information + = help: add `#![feature(deref_patterns)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0308]: mismatched types + --> $DIR/needs-gate.rs:11:9 + | +LL | match Box::new(0) { + | ----------- this expression has type `Box<{integer}>` +LL | 0 => {} + | ^ expected `Box<{integer}>`, found integer + | + = note: expected struct `Box<{integer}>` + found type `{integer}` +help: consider dereferencing to access the inner value using the Deref trait + | +LL | match *Box::new(0) { + | + + +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/tests/ui/pattern/deref-patterns/recursion-limit.rs b/tests/ui/pattern/deref-patterns/recursion-limit.rs new file mode 100644 index 000000000000..c5fe520f6f1a --- /dev/null +++ b/tests/ui/pattern/deref-patterns/recursion-limit.rs @@ -0,0 +1,23 @@ +//! Test that implicit deref patterns respect the recursion limit +#![feature(deref_patterns)] +#![allow(incomplete_features)] +#![recursion_limit = "8"] + +use std::ops::Deref; + +struct Cyclic; +impl Deref for Cyclic { + type Target = Cyclic; + fn deref(&self) -> &Cyclic { + &Cyclic + } +} + +fn main() { + match &Box::new(Cyclic) { + () => {} + //~^ ERROR: reached the recursion limit while auto-dereferencing `Cyclic` + //~| ERROR: the trait bound `Cyclic: DerefPure` is not satisfied + _ => {} + } +} diff --git a/tests/ui/pattern/deref-patterns/recursion-limit.stderr b/tests/ui/pattern/deref-patterns/recursion-limit.stderr new file mode 100644 index 000000000000..9a83d1eb5a4a --- /dev/null +++ b/tests/ui/pattern/deref-patterns/recursion-limit.stderr @@ -0,0 +1,18 @@ +error[E0055]: reached the recursion limit while auto-dereferencing `Cyclic` + --> $DIR/recursion-limit.rs:18:9 + | +LL | () => {} + | ^^ deref recursion limit reached + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "16"]` attribute to your crate (`recursion_limit`) + +error[E0277]: the trait bound `Cyclic: DerefPure` is not satisfied + --> $DIR/recursion-limit.rs:18:9 + | +LL | () => {} + | ^^ the trait `DerefPure` is not implemented for `Cyclic` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0055, E0277. +For more information about an error, try `rustc --explain E0055`. diff --git a/tests/ui/pattern/deref-patterns/ref-mut.rs b/tests/ui/pattern/deref-patterns/ref-mut.rs index 1918008a761a..43738671346d 100644 --- a/tests/ui/pattern/deref-patterns/ref-mut.rs +++ b/tests/ui/pattern/deref-patterns/ref-mut.rs @@ -8,10 +8,19 @@ fn main() { deref!(x) => {} _ => {} } + match &mut vec![1] { + [x] => {} + _ => {} + } match &mut Rc::new(1) { deref!(x) => {} //~^ ERROR the trait bound `Rc<{integer}>: DerefMut` is not satisfied _ => {} } + match &mut Rc::new((1,)) { + (x,) => {} + //~^ ERROR the trait bound `Rc<({integer},)>: DerefMut` is not satisfied + _ => {} + } } diff --git a/tests/ui/pattern/deref-patterns/ref-mut.stderr b/tests/ui/pattern/deref-patterns/ref-mut.stderr index 41f1c3061ce6..24a35b418e95 100644 --- a/tests/ui/pattern/deref-patterns/ref-mut.stderr +++ b/tests/ui/pattern/deref-patterns/ref-mut.stderr @@ -8,13 +8,19 @@ LL | #![feature(deref_patterns)] = note: `#[warn(incomplete_features)]` on by default error[E0277]: the trait bound `Rc<{integer}>: DerefMut` is not satisfied - --> $DIR/ref-mut.rs:13:9 + --> $DIR/ref-mut.rs:17:9 | LL | deref!(x) => {} | ^^^^^^^^^ the trait `DerefMut` is not implemented for `Rc<{integer}>` | = note: this error originates in the macro `deref` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 1 previous error; 1 warning emitted +error[E0277]: the trait bound `Rc<({integer},)>: DerefMut` is not satisfied + --> $DIR/ref-mut.rs:22:9 + | +LL | (x,) => {} + | ^^^^ the trait `DerefMut` is not implemented for `Rc<({integer},)>` + +error: aborting due to 2 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/pattern/deref-patterns/typeck.rs b/tests/ui/pattern/deref-patterns/typeck.rs index f23f7042cd89..3a7ce9d1deb3 100644 --- a/tests/ui/pattern/deref-patterns/typeck.rs +++ b/tests/ui/pattern/deref-patterns/typeck.rs @@ -10,26 +10,32 @@ fn main() { let vec: Vec = Vec::new(); match vec { deref!([..]) => {} + [..] => {} _ => {} } match Box::new(true) { deref!(true) => {} + true => {} _ => {} } match &Box::new(true) { deref!(true) => {} + true => {} _ => {} } match &Rc::new(0) { deref!(1..) => {} + 1.. => {} _ => {} } let _: &Struct = match &Rc::new(Struct) { deref!(x) => x, + Struct => &Struct, _ => unreachable!(), }; let _: &[Struct] = match &Rc::new(vec![Struct]) { deref!(deref!(x)) => x, + [Struct] => &[Struct], _ => unreachable!(), }; } diff --git a/tests/ui/pattern/deref-patterns/typeck_fail.rs b/tests/ui/pattern/deref-patterns/typeck_fail.rs index 040118449ecc..4b9ad7d25f09 100644 --- a/tests/ui/pattern/deref-patterns/typeck_fail.rs +++ b/tests/ui/pattern/deref-patterns/typeck_fail.rs @@ -7,11 +7,22 @@ fn main() { match "foo".to_string() { deref!("foo") => {} //~^ ERROR: mismatched types + "foo" => {} + //~^ ERROR: mismatched types _ => {} } match &"foo".to_string() { deref!("foo") => {} //~^ ERROR: mismatched types + "foo" => {} + //~^ ERROR: mismatched types + _ => {} + } + + // Make sure we don't try implicitly dereferncing any ADT. + match Some(0) { + Ok(0) => {} + //~^ ERROR: mismatched types _ => {} } } diff --git a/tests/ui/pattern/deref-patterns/typeck_fail.stderr b/tests/ui/pattern/deref-patterns/typeck_fail.stderr index 1c14802745a0..3e2f35618822 100644 --- a/tests/ui/pattern/deref-patterns/typeck_fail.stderr +++ b/tests/ui/pattern/deref-patterns/typeck_fail.stderr @@ -7,13 +7,45 @@ LL | deref!("foo") => {} | ^^^^^ expected `str`, found `&str` error[E0308]: mismatched types - --> $DIR/typeck_fail.rs:13:16 + --> $DIR/typeck_fail.rs:10:9 + | +LL | match "foo".to_string() { + | ----------------- this expression has type `String` +... +LL | "foo" => {} + | ^^^^^ expected `String`, found `&str` + +error[E0308]: mismatched types + --> $DIR/typeck_fail.rs:15:16 | LL | match &"foo".to_string() { | ------------------ this expression has type `&String` LL | deref!("foo") => {} | ^^^^^ expected `str`, found `&str` -error: aborting due to 2 previous errors +error[E0308]: mismatched types + --> $DIR/typeck_fail.rs:17:9 + | +LL | match &"foo".to_string() { + | ------------------ this expression has type `&String` +... +LL | "foo" => {} + | ^^^^^ expected `&String`, found `&str` + | + = note: expected reference `&String` + found reference `&'static str` + +error[E0308]: mismatched types + --> $DIR/typeck_fail.rs:24:9 + | +LL | match Some(0) { + | ------- this expression has type `Option<{integer}>` +LL | Ok(0) => {} + | ^^^^^ expected `Option<{integer}>`, found `Result<_, _>` + | + = note: expected enum `Option<{integer}>` + found enum `Result<_, _>` + +error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/pattern/deref-patterns/unsatisfied-bounds.rs b/tests/ui/pattern/deref-patterns/unsatisfied-bounds.rs new file mode 100644 index 000000000000..00064b2320c8 --- /dev/null +++ b/tests/ui/pattern/deref-patterns/unsatisfied-bounds.rs @@ -0,0 +1,21 @@ +#![feature(deref_patterns)] +#![allow(incomplete_features)] + +struct MyPointer; + +impl std::ops::Deref for MyPointer { + type Target = (); + fn deref(&self) -> &() { + &() + } +} + +fn main() { + // Test that we get a trait error if a user attempts implicit deref pats on their own impls. + // FIXME(deref_patterns): there should be a special diagnostic for missing `DerefPure`. + match MyPointer { + () => {} + //~^ the trait bound `MyPointer: DerefPure` is not satisfied + _ => {} + } +} diff --git a/tests/ui/pattern/deref-patterns/unsatisfied-bounds.stderr b/tests/ui/pattern/deref-patterns/unsatisfied-bounds.stderr new file mode 100644 index 000000000000..983ce27865c9 --- /dev/null +++ b/tests/ui/pattern/deref-patterns/unsatisfied-bounds.stderr @@ -0,0 +1,9 @@ +error[E0277]: the trait bound `MyPointer: DerefPure` is not satisfied + --> $DIR/unsatisfied-bounds.rs:17:9 + | +LL | () => {} + | ^^ the trait `DerefPure` is not implemented for `MyPointer` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/pattern/non-structural-match-types-cycle-err.rs b/tests/ui/pattern/non-structural-match-types-cycle-err.rs new file mode 100644 index 000000000000..a8e494c35b0c --- /dev/null +++ b/tests/ui/pattern/non-structural-match-types-cycle-err.rs @@ -0,0 +1,24 @@ +//@ edition:2021 + +struct AnyOption(T); +impl AnyOption { + const NONE: Option = None; +} + +// This is an unfortunate side-effect of borrowchecking nested items +// together with their parent. Evaluating the `AnyOption::<_>::NONE` +// pattern for exhaustiveness checking relies on the layout of the +// async block. This layout relies on `optimized_mir` of the nested +// item which is now borrowck'd together with its parent. As +// borrowck of the parent requires us to have already lowered the match, +// this is a query cycle. + +fn uwu() {} +fn defines() { + match Some(async {}) { + AnyOption::<_>::NONE => {} + //~^ ERROR cycle detected when building THIR for `defines` + _ => {} + } +} +fn main() {} diff --git a/tests/ui/pattern/non-structural-match-types-cycle-err.stderr b/tests/ui/pattern/non-structural-match-types-cycle-err.stderr new file mode 100644 index 000000000000..2f4ac63fc570 --- /dev/null +++ b/tests/ui/pattern/non-structural-match-types-cycle-err.stderr @@ -0,0 +1,64 @@ +error[E0391]: cycle detected when building THIR for `defines` + --> $DIR/non-structural-match-types-cycle-err.rs:19:9 + | +LL | AnyOption::<_>::NONE => {} + | ^^^^^^^^^^^^^^^^^^^^ + | +note: ...which requires evaluating type-level constant... + --> $DIR/non-structural-match-types-cycle-err.rs:5:5 + | +LL | const NONE: Option = None; + | ^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires const-evaluating + checking `::NONE`... + --> $DIR/non-structural-match-types-cycle-err.rs:5:5 + | +LL | const NONE: Option = None; + | ^^^^^^^^^^^^^^^^^^^^^ + = note: ...which requires computing layout of `core::option::Option<{async block@$DIR/non-structural-match-types-cycle-err.rs:18:16: 18:21}>`... + = note: ...which requires computing layout of `{async block@$DIR/non-structural-match-types-cycle-err.rs:18:16: 18:21}`... +note: ...which requires optimizing MIR for `defines::{closure#0}`... + --> $DIR/non-structural-match-types-cycle-err.rs:18:16 + | +LL | match Some(async {}) { + | ^^^^^ +note: ...which requires elaborating drops for `defines::{closure#0}`... + --> $DIR/non-structural-match-types-cycle-err.rs:18:16 + | +LL | match Some(async {}) { + | ^^^^^ +note: ...which requires borrow-checking `defines`... + --> $DIR/non-structural-match-types-cycle-err.rs:17:1 + | +LL | fn defines() { + | ^^^^^^^^^^^^ +note: ...which requires promoting constants in MIR for `defines`... + --> $DIR/non-structural-match-types-cycle-err.rs:17:1 + | +LL | fn defines() { + | ^^^^^^^^^^^^ +note: ...which requires checking if `defines` contains FFI-unwind calls... + --> $DIR/non-structural-match-types-cycle-err.rs:17:1 + | +LL | fn defines() { + | ^^^^^^^^^^^^ +note: ...which requires building MIR for `defines`... + --> $DIR/non-structural-match-types-cycle-err.rs:17:1 + | +LL | fn defines() { + | ^^^^^^^^^^^^ +note: ...which requires match-checking `defines`... + --> $DIR/non-structural-match-types-cycle-err.rs:17:1 + | +LL | fn defines() { + | ^^^^^^^^^^^^ + = note: ...which again requires building THIR for `defines`, completing the cycle +note: cycle used when unsafety-checking `defines` + --> $DIR/non-structural-match-types-cycle-err.rs:17:1 + | +LL | fn defines() { + | ^^^^^^^^^^^^ + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/pattern/non-structural-match-types.rs b/tests/ui/pattern/non-structural-match-types.rs index 5869767c936b..a5ff7fcdb5e4 100644 --- a/tests/ui/pattern/non-structural-match-types.rs +++ b/tests/ui/pattern/non-structural-match-types.rs @@ -1,6 +1,4 @@ //@ edition:2021 -#![feature(const_async_blocks)] - struct AnyOption(T); impl AnyOption { const NONE: Option = None; @@ -19,11 +17,5 @@ fn defines() { //~^ ERROR constant of non-structural type _ => {} } - - match Some(async {}) { - AnyOption::<_>::NONE => {} - //~^ ERROR constant of non-structural type - _ => {} - } } fn main() {} diff --git a/tests/ui/pattern/non-structural-match-types.stderr b/tests/ui/pattern/non-structural-match-types.stderr index da675a9f3ff5..3b74ffe7cb7f 100644 --- a/tests/ui/pattern/non-structural-match-types.stderr +++ b/tests/ui/pattern/non-structural-match-types.stderr @@ -1,5 +1,5 @@ error: constant of non-structural type `Option` in a pattern - --> $DIR/non-structural-match-types.rs:12:9 + --> $DIR/non-structural-match-types.rs:10:9 | LL | impl AnyOption { | -------------------- @@ -11,8 +11,8 @@ LL | AnyOption::<_>::NONE => {} | = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details -error: constant of non-structural type `Option<{closure@$DIR/non-structural-match-types.rs:17:16: 17:18}>` in a pattern - --> $DIR/non-structural-match-types.rs:18:9 +error: constant of non-structural type `Option<{closure@$DIR/non-structural-match-types.rs:15:16: 15:18}>` in a pattern + --> $DIR/non-structural-match-types.rs:16:9 | LL | impl AnyOption { | -------------------- @@ -24,19 +24,5 @@ LL | AnyOption::<_>::NONE => {} | = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details -error: constant of non-structural type `Option<{async block@$DIR/non-structural-match-types.rs:23:16: 23:21}>` in a pattern - --> $DIR/non-structural-match-types.rs:24:9 - | -LL | impl AnyOption { - | -------------------- -LL | const NONE: Option = None; - | --------------------- constant defined here -... -LL | AnyOption::<_>::NONE => {} - | ^^^^^^^^^^^^^^^^^^^^ constant of non-structural type - | - = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details - = note: `ResumeTy` must be annotated with `#[derive(PartialEq)]` to be usable in patterns - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors diff --git a/tests/ui/pattern/patkind-ref-binding-issue-114896.fixed b/tests/ui/pattern/patkind-ref-binding-issue-114896.fixed index 086a119eb776..2eeca4bdb7a5 100644 --- a/tests/ui/pattern/patkind-ref-binding-issue-114896.fixed +++ b/tests/ui/pattern/patkind-ref-binding-issue-114896.fixed @@ -5,6 +5,6 @@ fn main() { fn x(a: &char) { let &(mut b) = a; b.make_ascii_uppercase(); -//~^ cannot borrow `b` as mutable, as it is not declared as mutable + //~^ ERROR cannot borrow `b` as mutable, as it is not declared as mutable } } diff --git a/tests/ui/pattern/patkind-ref-binding-issue-114896.rs b/tests/ui/pattern/patkind-ref-binding-issue-114896.rs index b4d6b72c01f2..f074246b7829 100644 --- a/tests/ui/pattern/patkind-ref-binding-issue-114896.rs +++ b/tests/ui/pattern/patkind-ref-binding-issue-114896.rs @@ -5,6 +5,6 @@ fn main() { fn x(a: &char) { let &b = a; b.make_ascii_uppercase(); -//~^ cannot borrow `b` as mutable, as it is not declared as mutable + //~^ ERROR cannot borrow `b` as mutable, as it is not declared as mutable } } diff --git a/tests/ui/pattern/rest-pat-syntactic.rs b/tests/ui/pattern/rest-pat-syntactic.rs index 1de29e69b054..59c687bb5a8d 100644 --- a/tests/ui/pattern/rest-pat-syntactic.rs +++ b/tests/ui/pattern/rest-pat-syntactic.rs @@ -11,7 +11,7 @@ macro_rules! accept_pat { accept_pat!(..); -#[cfg(FALSE)] +#[cfg(false)] fn rest_patterns() { // Top level: fn foo(..: u8) {} diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.rs b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.rs index 621ca7cc792e..c171dcf0ca66 100644 --- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.rs +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.rs @@ -13,14 +13,14 @@ /// to fail in HIR typeck on stable. As such, they need to be separate from the other tests. fn errors_caught_in_hir_typeck_on_stable() { let [&x] = &[&mut 0]; - //[stable2021]~^ mismatched types + //[stable2021]~^ ERROR mismatched types //[stable2021]~| types differ in mutability //[classic2024]~^^^ ERROR: cannot move out of type #[cfg(any(classic2021, structural2021))] let _: u32 = x; #[cfg(structural2024)] let _: &u32 = x; let [&x] = &mut [&mut 0]; - //[stable2021]~^ mismatched types + //[stable2021]~^ ERROR mismatched types //[stable2021]~| types differ in mutability //[classic2024]~^^^ ERROR: cannot move out of type #[cfg(any(classic2021, structural2021))] let _: u32 = x; @@ -34,7 +34,7 @@ pub fn main() { } let &ref mut x = &0; - //~^ cannot borrow data in a `&` reference as mutable [E0596] + //~^ ERROR cannot borrow data in a `&` reference as mutable [E0596] // For 2021 edition, this is also a regression test for #136223 // since the maximum mutability is downgraded during the pattern check process. diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mut-ref-mut.rs b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mut-ref-mut.rs index c8e988ad76d9..94691e77bd8d 100644 --- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mut-ref-mut.rs +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mut-ref-mut.rs @@ -28,6 +28,6 @@ pub fn main() { let [&mut mut x] = &[&mut 0]; //[classic2024]~^ ERROR: mismatched types //[classic2024]~| cannot match inherited `&` with `&mut` pattern - //[structural2024]~^^^ binding cannot be both mutable and by-reference + //[structural2024]~^^^ ERROR binding cannot be both mutable and by-reference #[cfg(any(stable2021, classic2021, structural2021))] { x = 0 } } diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/well-typed-edition-2024.rs b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/well-typed-edition-2024.rs index 62c1c28022b7..877b10dcfd54 100644 --- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/well-typed-edition-2024.rs +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/well-typed-edition-2024.rs @@ -30,63 +30,63 @@ pub fn main() { #[cfg(any(classic2024, structural2024))] let _: &u32 = x; } if let Some(Some(&&x)) = &Some(Some(&0)) { - //[stable2021,classic2021,structural2021]~^ mismatched types + //[stable2021,classic2021,structural2021]~^ ERROR mismatched types //[stable2021,classic2021,structural2021]~| expected integer, found `&_` #[cfg(any(classic2024, structural2024))] let _: u32 = x; } // Tests for eating a lone inherited reference if let Some(Some(&x)) = &Some(&Some(0)) { - //[stable2021]~^ mismatched types + //[stable2021]~^ ERROR mismatched types //[stable2021]~| expected integer, found `&_` #[cfg(any(classic2021, structural2021, classic2024, structural2024))] let _: u32 = x; } if let Some(&Some(x)) = &Some(Some(0)) { - //[stable2021]~^ mismatched types + //[stable2021]~^ ERROR mismatched types //[stable2021]~| expected `Option<{integer}>`, found `&_` #[cfg(any(classic2021, structural2021, classic2024, structural2024))] let _: u32 = x; } if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) { - //[stable2021]~^ mismatched types + //[stable2021]~^ ERROR mismatched types //[stable2021]~| expected integer, found `&mut _` #[cfg(any(classic2021, structural2021, classic2024, structural2024))] let _: u32 = x; } // Tests for `&` patterns matching real `&mut` reference types if let Some(&Some(&x)) = Some(&Some(&mut 0)) { - //[stable2021]~^ mismatched types + //[stable2021]~^ ERROR mismatched types //[stable2021]~| types differ in mutability #[cfg(any(classic2021, structural2021, classic2024, structural2024))] let _: u32 = x; } // Tests for eating only one layer and also eating a lone inherited reference if let Some(&Some(&x)) = &Some(&Some(0)) { - //[stable2021,classic2021,structural2021]~^ mismatched types + //[stable2021,classic2021,structural2021]~^ ERROR mismatched types //[stable2021,classic2021,structural2021]~| expected integer, found `&_` #[cfg(any(classic2024, structural2024))] let _: u32 = x; } // Tests for `&` matching a lone inherited possibly-`&mut` reference if let Some(&Some(Some(&x))) = &Some(Some(&mut Some(0))) { - //[stable2021]~^ mismatched types + //[stable2021]~^ ERROR mismatched types //[stable2021]~| expected `Option<&mut Option<{integer}>>`, found `&_` #[cfg(any(classic2021, structural2021, classic2024, structural2024))] let _: u32 = x; } if let Some(&Some(x)) = &mut Some(Some(0)) { - //[stable2021]~^ mismatched types + //[stable2021]~^ ERROR mismatched types //[stable2021]~| expected `Option<{integer}>`, found `&_` #[cfg(any(classic2021, structural2021, classic2024, structural2024))] let _: u32 = x; } // Tests eating one layer, eating a lone inherited ref, and `&` eating `&mut` (realness varies) if let Some(&Some(&x)) = &Some(&mut Some(0)) { - //[stable2021,classic2021,structural2021]~^ mismatched types + //[stable2021,classic2021,structural2021]~^ ERROR mismatched types //[stable2021]~| types differ in mutability //[classic2021,structural2021]~| expected integer, found `&_` #[cfg(any(classic2024, structural2024))] let _: u32 = x; } if let Some(&Some(&x)) = &mut Some(&Some(0)) { - //[stable2021,classic2021,structural2021]~^ mismatched types + //[stable2021,classic2021,structural2021]~^ ERROR mismatched types //[stable2021,classic2021,structural2021]~| expected integer, found `&_` #[cfg(any(classic2024, structural2024))] let _: u32 = x; } @@ -94,46 +94,46 @@ pub fn main() { // Tests for eat-inner and eat-both rulesets matching on the outer reference if matching on the // inner reference causes a mutability mismatch. i.e. tests for "fallback-to-outer" deref rules. let [&mut x] = &mut [&0]; - //[stable2021]~^ mismatched types + //[stable2021]~^ ERROR mismatched types //[stable2021]~| types differ in mutability #[cfg(any(classic2021, structural2021))] let _: u32 = x; #[cfg(any(classic2024, structural2024))] let _: &u32 = x; let [&mut ref x] = &mut [&0]; - //[stable2021]~^ mismatched types + //[stable2021]~^ ERROR mismatched types //[stable2021]~| types differ in mutability #[cfg(any(classic2021, structural2021))] let _: &u32 = x; #[cfg(any(classic2024, structural2024))] let _: &&u32 = x; fn borrowck_error_on_structural2021() { let [&mut ref mut x] = &mut [&0]; - //[stable2021]~^ mismatched types + //[stable2021]~^ ERROR mismatched types //[stable2021]~| types differ in mutability - //[classic2021,structural2021]~^^^ cannot borrow data in a `&` reference as mutable + //[classic2021,structural2021]~^^^ ERROR cannot borrow data in a `&` reference as mutable #[cfg(any(classic2024, structural2024))] let _: &mut &u32 = x; } borrowck_error_on_structural2021(); let [&mut mut x] = &mut [&0]; - //[stable2021]~^ mismatched types + //[stable2021]~^ ERROR mismatched types //[stable2021]~| types differ in mutability #[cfg(any(classic2021, structural2021))] let _: u32 = x; #[cfg(any(classic2024, structural2024))] let _: &u32 = x; let [&mut &x] = &mut [&0]; - //[stable2021,classic2021,structural2021]~^ mismatched types + //[stable2021,classic2021,structural2021]~^ ERROR mismatched types //[stable2021]~| types differ in mutability //[classic2021,structural2021]~| expected integer, found `&_` #[cfg(any(classic2024, structural2024))] let _: u32 = x; let [&mut &ref x] = &mut [&0]; - //[stable2021,classic2021,structural2021]~^ mismatched types + //[stable2021,classic2021,structural2021]~^ ERROR mismatched types //[stable2021]~| types differ in mutability //[classic2021,structural2021]~| expected integer, found `&_` #[cfg(any(classic2024, structural2024))] let _: &u32 = x; let [&mut &(mut x)] = &mut [&0]; - //[stable2021,classic2021,structural2021]~^ mismatched types + //[stable2021,classic2021,structural2021]~^ ERROR mismatched types //[stable2021]~| types differ in mutability //[classic2021,structural2021]~| expected integer, found `&_` #[cfg(any(classic2024, structural2024))] let _: u32 = x; diff --git a/tests/ui/pattern/usefulness/doc-hidden-fields.rs b/tests/ui/pattern/usefulness/doc-hidden-fields.rs index 549e0d1af558..a3c3740b34ad 100644 --- a/tests/ui/pattern/usefulness/doc-hidden-fields.rs +++ b/tests/ui/pattern/usefulness/doc-hidden-fields.rs @@ -13,14 +13,14 @@ struct InCrate { fn main() { let HiddenStruct { one, two } = HiddenStruct::default(); - //~^ pattern requires `..` due to inaccessible fields + //~^ ERROR pattern requires `..` due to inaccessible fields let HiddenStruct { one } = HiddenStruct::default(); - //~^ pattern does not mention field `two` and inaccessible fields + //~^ ERROR pattern does not mention field `two` and inaccessible fields let HiddenStruct { one, hide } = HiddenStruct::default(); - //~^ pattern does not mention field `two` + //~^ ERROR pattern does not mention field `two` let InCrate { a, b } = InCrate { a: 0, b: false, im_hidden: 0 }; - //~^ pattern does not mention field `im_hidden` + //~^ ERROR pattern does not mention field `im_hidden` } diff --git a/tests/ui/pattern/usefulness/doc-hidden-non-exhaustive.rs b/tests/ui/pattern/usefulness/doc-hidden-non-exhaustive.rs index 56842917f500..4bbdc7b139f4 100644 --- a/tests/ui/pattern/usefulness/doc-hidden-non-exhaustive.rs +++ b/tests/ui/pattern/usefulness/doc-hidden-non-exhaustive.rs @@ -16,28 +16,28 @@ fn main() { HiddenEnum::A => {} HiddenEnum::B => {} } - //~^^^^ non-exhaustive patterns: `_` not covered + //~^^^^ ERROR non-exhaustive patterns: `_` not covered match HiddenEnum::A { HiddenEnum::A => {} HiddenEnum::C => {} } - //~^^^^ non-exhaustive patterns: `HiddenEnum::B` not covered + //~^^^^ ERROR non-exhaustive patterns: `HiddenEnum::B` not covered match HiddenEnum::A { HiddenEnum::A => {} } - //~^^^ non-exhaustive patterns: `HiddenEnum::B` and `_` not covered + //~^^^ ERROR non-exhaustive patterns: `HiddenEnum::B` and `_` not covered match None { None => {} Some(HiddenEnum::A) => {} } - //~^^^^ non-exhaustive patterns: `Some(HiddenEnum::B)` and `Some(_)` not covered + //~^^^^ ERROR non-exhaustive patterns: `Some(HiddenEnum::B)` and `Some(_)` not covered match InCrate::A { InCrate::A => {} InCrate::B => {} } - //~^^^^ non-exhaustive patterns: `InCrate::C` not covered + //~^^^^ ERROR non-exhaustive patterns: `InCrate::C` not covered } diff --git a/tests/ui/pattern/usefulness/non-exhaustive-defined-here.rs b/tests/ui/pattern/usefulness/non-exhaustive-defined-here.rs index d0a8a10f2f37..4a7b2c956fc3 100644 --- a/tests/ui/pattern/usefulness/non-exhaustive-defined-here.rs +++ b/tests/ui/pattern/usefulness/non-exhaustive-defined-here.rs @@ -24,12 +24,12 @@ enum E { //~| NOTE not covered //~| NOTE not covered C - //~^ not covered - //~| not covered - //~| not covered - //~| not covered - //~| not covered - //~| not covered + //~^ NOTE not covered + //~| NOTE not covered + //~| NOTE not covered + //~| NOTE not covered + //~| NOTE not covered + //~| NOTE not covered } fn by_val(e: E) { @@ -42,7 +42,7 @@ fn by_val(e: E) { let E::A = e; //~^ ERROR refutable pattern in local binding - //~| patterns `E::B` and `E::C` not covered + //~| NOTE patterns `E::B` and `E::C` not covered //~| NOTE `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with //~| NOTE for more information, visit https://doc.rust-lang.org/book/ch19-02-refutability.html //~| NOTE the matched value is of type `E` @@ -51,14 +51,14 @@ fn by_val(e: E) { fn by_ref_once(e: &E) { match e { //~^ ERROR non-exhaustive patterns - //~| patterns `&E::B` and `&E::C` not covered + //~| NOTE patterns `&E::B` and `&E::C` not covered //~| NOTE the matched value is of type `&E` E::A => {} } let E::A = e; //~^ ERROR refutable pattern in local binding - //~| patterns `&E::B` and `&E::C` not covered + //~| NOTE patterns `&E::B` and `&E::C` not covered //~| NOTE `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with //~| NOTE for more information, visit https://doc.rust-lang.org/book/ch19-02-refutability.html //~| NOTE the matched value is of type `&E` @@ -67,14 +67,14 @@ fn by_ref_once(e: &E) { fn by_ref_thrice(e: & &mut &E) { match e { //~^ ERROR non-exhaustive patterns - //~| patterns `&&mut &E::B` and `&&mut &E::C` not covered + //~| NOTE patterns `&&mut &E::B` and `&&mut &E::C` not covered //~| NOTE the matched value is of type `&&mut &E` E::A => {} } let E::A = e; //~^ ERROR refutable pattern in local binding - //~| patterns `&&mut &E::B` and `&&mut &E::C` not covered + //~| NOTE patterns `&&mut &E::B` and `&&mut &E::C` not covered //~| NOTE `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with //~| NOTE for more information, visit https://doc.rust-lang.org/book/ch19-02-refutability.html //~| NOTE the matched value is of type `&&mut &E` @@ -93,7 +93,7 @@ enum Opt { fn ref_pat(e: Opt) { match e { //~^ ERROR non-exhaustive patterns - //~| pattern `Opt::None` not covered + //~| NOTE pattern `Opt::None` not covered //~| NOTE the matched value is of type `Opt` Opt::Some(ref _x) => {} } diff --git a/tests/ui/pattern/usefulness/stable-gated-fields.rs b/tests/ui/pattern/usefulness/stable-gated-fields.rs index 61b202b77f61..7be2722daac7 100644 --- a/tests/ui/pattern/usefulness/stable-gated-fields.rs +++ b/tests/ui/pattern/usefulness/stable-gated-fields.rs @@ -6,10 +6,10 @@ use unstable::UnstableStruct; fn main() { let UnstableStruct { stable } = UnstableStruct::default(); - //~^ pattern does not mention field `stable2` and inaccessible fields + //~^ ERROR pattern does not mention field `stable2` and inaccessible fields let UnstableStruct { stable, stable2 } = UnstableStruct::default(); - //~^ pattern requires `..` due to inaccessible fields + //~^ ERROR pattern requires `..` due to inaccessible fields // OK: stable field is matched let UnstableStruct { stable, stable2, .. } = UnstableStruct::default(); diff --git a/tests/ui/pattern/usefulness/stable-gated-patterns.rs b/tests/ui/pattern/usefulness/stable-gated-patterns.rs index 5ceffbf09236..d58483441549 100644 --- a/tests/ui/pattern/usefulness/stable-gated-patterns.rs +++ b/tests/ui/pattern/usefulness/stable-gated-patterns.rs @@ -8,11 +8,11 @@ fn main() { match UnstableEnum::Stable { UnstableEnum::Stable => {} } - //~^^^ non-exhaustive patterns: `UnstableEnum::Stable2` and `_` not covered + //~^^^ ERROR non-exhaustive patterns: `UnstableEnum::Stable2` and `_` not covered match UnstableEnum::Stable { UnstableEnum::Stable => {} UnstableEnum::Stable2 => {} } - //~^^^^ non-exhaustive patterns: `_` not covered + //~^^^^ ERROR non-exhaustive patterns: `_` not covered } diff --git a/tests/ui/pattern/usefulness/unstable-gated-fields.rs b/tests/ui/pattern/usefulness/unstable-gated-fields.rs index e6a4494867a0..08b46283f659 100644 --- a/tests/ui/pattern/usefulness/unstable-gated-fields.rs +++ b/tests/ui/pattern/usefulness/unstable-gated-fields.rs @@ -8,10 +8,10 @@ use unstable::UnstableStruct; fn main() { let UnstableStruct { stable, stable2, } = UnstableStruct::default(); - //~^ pattern does not mention field `unstable` + //~^ ERROR pattern does not mention field `unstable` let UnstableStruct { stable, unstable, } = UnstableStruct::default(); - //~^ pattern does not mention field `stable2` + //~^ ERROR pattern does not mention field `stable2` // OK: stable field is matched let UnstableStruct { stable, stable2, unstable } = UnstableStruct::default(); diff --git a/tests/ui/pattern/usefulness/unstable-gated-patterns.rs b/tests/ui/pattern/usefulness/unstable-gated-patterns.rs index e6db495a1494..3acc0738bbc8 100644 --- a/tests/ui/pattern/usefulness/unstable-gated-patterns.rs +++ b/tests/ui/pattern/usefulness/unstable-gated-patterns.rs @@ -11,7 +11,7 @@ fn main() { UnstableEnum::Stable => {} UnstableEnum::Stable2 => {} } - //~^^^^ non-exhaustive patterns: `UnstableEnum::Unstable` not covered + //~^^^^ ERROR non-exhaustive patterns: `UnstableEnum::Unstable` not covered // Ok: all variants are explicitly matched match UnstableEnum::Stable { diff --git a/tests/ui/pin-macro/cant_access_internals.rs b/tests/ui/pin-macro/cant_access_internals.rs deleted file mode 100644 index 36a47d0fdf93..000000000000 --- a/tests/ui/pin-macro/cant_access_internals.rs +++ /dev/null @@ -1,12 +0,0 @@ -//@ edition:2018 - -use core::{ - marker::PhantomPinned, - mem, - pin::{pin, Pin}, -}; - -fn main() { - let mut phantom_pinned = pin!(PhantomPinned); - mem::take(phantom_pinned.__pointer); //~ ERROR use of unstable library feature `unsafe_pin_internals` -} diff --git a/tests/ui/pin-macro/cant_access_internals.stderr b/tests/ui/pin-macro/cant_access_internals.stderr deleted file mode 100644 index 8ad897bbbb95..000000000000 --- a/tests/ui/pin-macro/cant_access_internals.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0658]: use of unstable library feature `unsafe_pin_internals` - --> $DIR/cant_access_internals.rs:11:15 - | -LL | mem::take(phantom_pinned.__pointer); - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: add `#![feature(unsafe_pin_internals)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/pin-macro/lifetime_errors_on_promotion_misusage.rs b/tests/ui/pin-macro/lifetime_errors_on_promotion_misusage.rs index 8a0244e8145a..e505fe435207 100644 --- a/tests/ui/pin-macro/lifetime_errors_on_promotion_misusage.rs +++ b/tests/ui/pin-macro/lifetime_errors_on_promotion_misusage.rs @@ -9,14 +9,14 @@ use core::{ fn function_call_stops_borrow_extension() { let phantom_pinned = identity(pin!(PhantomPinned)); - //~^ ERROR temporary value dropped while borrowed + //~^ ERROR does not live long enough stuff(phantom_pinned) } fn promotion_only_works_for_the_innermost_block() { let phantom_pinned = { let phantom_pinned = pin!(PhantomPinned); - //~^ ERROR temporary value dropped while borrowed + //~^ ERROR does not live long enough phantom_pinned }; stuff(phantom_pinned) diff --git a/tests/ui/pin-macro/lifetime_errors_on_promotion_misusage.stderr b/tests/ui/pin-macro/lifetime_errors_on_promotion_misusage.stderr index 9df7f0ffd0c3..43fb82be7c2f 100644 --- a/tests/ui/pin-macro/lifetime_errors_on_promotion_misusage.stderr +++ b/tests/ui/pin-macro/lifetime_errors_on_promotion_misusage.stderr @@ -1,35 +1,29 @@ -error[E0716]: temporary value dropped while borrowed +error[E0597]: value does not live long enough --> $DIR/lifetime_errors_on_promotion_misusage.rs:11:35 | LL | let phantom_pinned = identity(pin!(PhantomPinned)); - | ^^^^^^^^^^^^^^^^^^^ - temporary value is freed at the end of this statement + | ^^^^^^^^^^^^^^^^^^^ - value dropped here while still borrowed | | - | creates a temporary value which is freed while still in use + | borrowed value does not live long enough LL | LL | stuff(phantom_pinned) | -------------- borrow later used here | = note: this error originates in the macro `pin` (in Nightly builds, run with -Z macro-backtrace for more info) -help: consider using a `let` binding to create a longer lived value - | -LL ~ let binding = pin!(PhantomPinned); -LL ~ let phantom_pinned = identity(binding); - | -error[E0716]: temporary value dropped while borrowed +error[E0597]: value does not live long enough --> $DIR/lifetime_errors_on_promotion_misusage.rs:18:30 | LL | let phantom_pinned = { | -------------- borrow later stored here LL | let phantom_pinned = pin!(PhantomPinned); - | ^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use + | ^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough ... LL | }; - | - temporary value is freed at the end of this statement + | - value dropped here while still borrowed | - = note: consider using a `let` binding to create a longer lived value = note: this error originates in the macro `pin` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0716`. +For more information about this error, try `rustc --explain E0597`. diff --git a/tests/ui/pin-macro/pin_move.stderr b/tests/ui/pin-macro/pin_move.stderr index c9b8ad9b2021..3f4660209885 100644 --- a/tests/ui/pin-macro/pin_move.stderr +++ b/tests/ui/pin-macro/pin_move.stderr @@ -31,6 +31,11 @@ LL | struct NotCopy(T); LL | let mut pointee = NotCopy(PhantomPinned); LL | pin!(*&mut pointee); | ------------- you could clone this value +help: consider removing the dereference here + | +LL - pin!(*&mut pointee); +LL + pin!(&mut pointee); + | error: aborting due to 2 previous errors diff --git a/tests/ui/precondition-checks/read.rs b/tests/ui/precondition-checks/read.rs index ab9921a0ceeb..d5ab7773987f 100644 --- a/tests/ui/precondition-checks/read.rs +++ b/tests/ui/precondition-checks/read.rs @@ -2,7 +2,7 @@ //@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes //@ error-pattern: unsafe precondition(s) violated: ptr::read requires //@ revisions: null misaligned -//@ ignore-test +//@ ignore-test (unimplemented) use std::ptr; diff --git a/tests/ui/precondition-checks/write.rs b/tests/ui/precondition-checks/write.rs index f76e776fcf35..5d6b9586fad7 100644 --- a/tests/ui/precondition-checks/write.rs +++ b/tests/ui/precondition-checks/write.rs @@ -2,7 +2,7 @@ //@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes //@ error-pattern: unsafe precondition(s) violated: ptr::write requires //@ revisions: null misaligned -//@ ignore-test +//@ ignore-test (unimplemented) use std::ptr; diff --git a/tests/ui/precondition-checks/write_bytes.rs b/tests/ui/precondition-checks/write_bytes.rs index 3f64be9d1ee1..be4f5a089f03 100644 --- a/tests/ui/precondition-checks/write_bytes.rs +++ b/tests/ui/precondition-checks/write_bytes.rs @@ -2,7 +2,7 @@ //@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes //@ error-pattern: unsafe precondition(s) violated: ptr::write requires //@ revisions: null misaligned -//@ ignore-test +//@ ignore-test (unimplemented) use std::ptr; diff --git a/tests/ui/print-calling-conventions.stdout b/tests/ui/print-calling-conventions.stdout index 539b2d5dee40..feee8cc3aa9c 100644 --- a/tests/ui/print-calling-conventions.stdout +++ b/tests/ui/print-calling-conventions.stdout @@ -19,7 +19,6 @@ riscv-interrupt-m riscv-interrupt-s rust-call rust-cold -rust-intrinsic stdcall stdcall-unwind system diff --git a/tests/ui/print-request/print-lints-help.rs b/tests/ui/print-request/print-lints-help.rs index 6dd88a701c31..9a706a296956 100644 --- a/tests/ui/print-request/print-lints-help.rs +++ b/tests/ui/print-request/print-lints-help.rs @@ -2,7 +2,8 @@ //! `--print=lints` (which is not a valid print request). //@ compile-flags: --print lints -//@ error-pattern: help: use `-Whelp` to print a list of lints -//@ error-pattern: help: for more information, see the rustc book //~? ERROR unknown print request: `lints` +//~? HELP use `-Whelp` to print a list of lints +//~? HELP for more information, see the rustc book +//~? HELP valid print requests are diff --git a/tests/ui/privacy/privacy3.rs b/tests/ui/privacy/privacy3.rs index 2bb3c1b3c61d..ec213285b405 100644 --- a/tests/ui/privacy/privacy3.rs +++ b/tests/ui/privacy/privacy3.rs @@ -22,7 +22,7 @@ fn test1() { //~^ ERROR requires `sized` lang_item use bar::gpriv; //~^ ERROR unresolved import `bar::gpriv` [E0432] - //~| no `gpriv` in `bar` + //~| NOTE no `gpriv` in `bar` // This should pass because the compiler will insert a fake name binding // for `gpriv` diff --git a/tests/ui/proc-macro/attribute-after-derive.rs b/tests/ui/proc-macro/attribute-after-derive.rs index f2e2eb12a195..382ef1f6ddfd 100644 --- a/tests/ui/proc-macro/attribute-after-derive.rs +++ b/tests/ui/proc-macro/attribute-after-derive.rs @@ -14,14 +14,14 @@ extern crate test_macros; #[print_attr] #[derive(Print)] struct AttributeDerive { - #[cfg(FALSE)] + #[cfg(false)] field: u8, } #[derive(Print)] #[print_attr] struct DeriveAttribute { - #[cfg(FALSE)] + #[cfg(false)] field: u8, } diff --git a/tests/ui/proc-macro/attribute-after-derive.stdout b/tests/ui/proc-macro/attribute-after-derive.stdout index 6d9531df8caf..bc0fc6dc1af1 100644 --- a/tests/ui/proc-macro/attribute-after-derive.stdout +++ b/tests/ui/proc-macro/attribute-after-derive.stdout @@ -1,5 +1,5 @@ -PRINT-ATTR INPUT (DISPLAY): #[derive(Print)] struct AttributeDerive { #[cfg(FALSE)] field: u8, } -PRINT-ATTR DEEP-RE-COLLECTED (DISPLAY): #[derive(Print)] struct AttributeDerive { #[cfg(FALSE)] field : u8, } +PRINT-ATTR INPUT (DISPLAY): #[derive(Print)] struct AttributeDerive { #[cfg(false)] field: u8, } +PRINT-ATTR DEEP-RE-COLLECTED (DISPLAY): #[derive(Print)] struct AttributeDerive { #[cfg(false)] field : u8, } PRINT-ATTR INPUT (DEBUG): TokenStream [ Punct { ch: '#', @@ -53,7 +53,7 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ delimiter: Parenthesis, stream: TokenStream [ Ident { - ident: "FALSE", + ident: "false", span: $DIR/attribute-after-derive.rs:17:11: 17:16 (#0), }, ], @@ -131,8 +131,8 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [ span: $DIR/attribute-after-derive.rs:23:24: 26:2 (#0), }, ] -PRINT-ATTR INPUT (DISPLAY): struct DeriveAttribute { #[cfg(FALSE)] field: u8, } -PRINT-ATTR DEEP-RE-COLLECTED (DISPLAY): struct DeriveAttribute { #[cfg(FALSE)] field : u8, } +PRINT-ATTR INPUT (DISPLAY): struct DeriveAttribute { #[cfg(false)] field: u8, } +PRINT-ATTR DEEP-RE-COLLECTED (DISPLAY): struct DeriveAttribute { #[cfg(false)] field : u8, } PRINT-ATTR INPUT (DEBUG): TokenStream [ Ident { ident: "struct", @@ -161,7 +161,7 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ delimiter: Parenthesis, stream: TokenStream [ Ident { - ident: "FALSE", + ident: "false", span: $DIR/attribute-after-derive.rs:24:11: 24:16 (#0), }, ], diff --git a/tests/ui/proc-macro/auxiliary/expand-expr.rs b/tests/ui/proc-macro/auxiliary/expand-expr.rs index 78c9fa75d9ff..14efc3c6b9f1 100644 --- a/tests/ui/proc-macro/auxiliary/expand-expr.rs +++ b/tests/ui/proc-macro/auxiliary/expand-expr.rs @@ -3,9 +3,10 @@ extern crate proc_macro; -use proc_macro::*; use std::str::FromStr; +use proc_macro::*; + // Flatten the TokenStream, removing any toplevel `Delimiter::None`s for // comparison. fn flatten(ts: TokenStream) -> Vec { @@ -136,9 +137,8 @@ pub fn check_expand_expr_file(ts: TokenStream) -> TokenStream { .to_string(); assert_eq!(input_t, parse_t); - // Check that the literal matches `Span::call_site().source_file().path()` - let expect_t = - Literal::string(&Span::call_site().source_file().path().to_string_lossy()).to_string(); + // Check that the literal matches `Span::call_site().file()` + let expect_t = Literal::string(&Span::call_site().file()).to_string(); assert_eq!(input_t, expect_t); TokenStream::new() diff --git a/tests/ui/proc-macro/auxiliary/macro-only-syntax.rs b/tests/ui/proc-macro/auxiliary/macro-only-syntax.rs index 4971de284b76..11e1910288ee 100644 --- a/tests/ui/proc-macro/auxiliary/macro-only-syntax.rs +++ b/tests/ui/proc-macro/auxiliary/macro-only-syntax.rs @@ -79,7 +79,7 @@ fn check_useful_span(token: TokenTree, expected_filename: &str) { let span = token.span(); assert!(span.column() < span.end().column()); - let source_path = span.source_file().path(); + let source_path = span.local_file().unwrap(); let filename = source_path.components().last().unwrap(); assert_eq!(filename, Component::Normal(expected_filename.as_ref())); } diff --git a/tests/ui/proc-macro/auxiliary/span-api-tests.rs b/tests/ui/proc-macro/auxiliary/span-api-tests.rs index 99db66ed6a94..036f2e3ac3f5 100644 --- a/tests/ui/proc-macro/auxiliary/span-api-tests.rs +++ b/tests/ui/proc-macro/auxiliary/span-api-tests.rs @@ -11,20 +11,9 @@ pub fn reemit(input: TokenStream) -> TokenStream { } #[proc_macro] -pub fn assert_fake_source_file(input: TokenStream) -> TokenStream { +pub fn assert_local_file(input: TokenStream) -> TokenStream { for tk in input { - let source_file = tk.span().source_file(); - assert!(!source_file.is_real(), "Source file is real: {:?}", source_file); - } - - "".parse().unwrap() -} - -#[proc_macro] -pub fn assert_source_file(input: TokenStream) -> TokenStream { - for tk in input { - let source_file = tk.span().source_file(); - assert!(source_file.is_real(), "Source file is not real: {:?}", source_file); + assert!(tk.span().local_file().is_some(), "No local file for span: {:?}", tk.span()); } "".parse().unwrap() diff --git a/tests/ui/proc-macro/cfg-attr-trace.rs b/tests/ui/proc-macro/cfg-attr-trace.rs index 140dd10a7e04..412c65bed1d8 100644 --- a/tests/ui/proc-macro/cfg-attr-trace.rs +++ b/tests/ui/proc-macro/cfg-attr-trace.rs @@ -3,7 +3,6 @@ //@ check-pass //@ proc-macro: test-macros.rs -#![feature(cfg_boolean_literals)] #![feature(cfg_eval)] #[macro_use] diff --git a/tests/ui/proc-macro/cfg-attr-trace.stdout b/tests/ui/proc-macro/cfg-attr-trace.stdout index 52f9ff4e05c5..33bcfe5d69b7 100644 --- a/tests/ui/proc-macro/cfg-attr-trace.stdout +++ b/tests/ui/proc-macro/cfg-attr-trace.stdout @@ -4,75 +4,75 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ Punct { ch: '#', spacing: Alone, - span: #0 bytes(305..306), + span: #0 bytes(271..272), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "test_macros", - span: #0 bytes(322..333), + span: #0 bytes(288..299), }, Punct { ch: ':', spacing: Joint, - span: #0 bytes(333..334), + span: #0 bytes(299..300), }, Punct { ch: ':', spacing: Alone, - span: #0 bytes(334..335), + span: #0 bytes(300..301), }, Ident { ident: "print_attr", - span: #0 bytes(335..345), + span: #0 bytes(301..311), }, ], - span: #0 bytes(306..347), + span: #0 bytes(272..313), }, Ident { ident: "struct", - span: #0 bytes(348..354), + span: #0 bytes(314..320), }, Ident { ident: "S", - span: #0 bytes(355..356), + span: #0 bytes(321..322), }, Punct { ch: ';', spacing: Alone, - span: #0 bytes(356..357), + span: #0 bytes(322..323), }, ] PRINT-ATTR INPUT (DISPLAY): struct S; PRINT-ATTR INPUT (DEBUG): TokenStream [ Ident { ident: "struct", - span: #0 bytes(348..354), + span: #0 bytes(314..320), }, Ident { ident: "S", - span: #0 bytes(355..356), + span: #0 bytes(321..322), }, Punct { ch: ';', spacing: Alone, - span: #0 bytes(356..357), + span: #0 bytes(322..323), }, ] PRINT-ATTR INPUT (DISPLAY): struct Z; PRINT-ATTR INPUT (DEBUG): TokenStream [ Ident { ident: "struct", - span: #0 bytes(411..417), + span: #0 bytes(377..383), }, Ident { ident: "Z", - span: #0 bytes(418..419), + span: #0 bytes(384..385), }, Punct { ch: ';', spacing: Alone, - span: #0 bytes(419..420), + span: #0 bytes(385..386), }, ] diff --git a/tests/ui/proc-macro/cfg-eval-fail.rs b/tests/ui/proc-macro/cfg-eval-fail.rs index a259aa2e6ec0..a94dcd283781 100644 --- a/tests/ui/proc-macro/cfg-eval-fail.rs +++ b/tests/ui/proc-macro/cfg-eval-fail.rs @@ -2,6 +2,6 @@ #![feature(stmt_expr_attributes)] fn main() { - let _ = #[cfg_eval] #[cfg(FALSE)] 0; + let _ = #[cfg_eval] #[cfg(false)] 0; //~^ ERROR removing an expression is not supported in this position } diff --git a/tests/ui/proc-macro/cfg-eval-fail.stderr b/tests/ui/proc-macro/cfg-eval-fail.stderr index 945ad46bf33c..7f21e4646b1c 100644 --- a/tests/ui/proc-macro/cfg-eval-fail.stderr +++ b/tests/ui/proc-macro/cfg-eval-fail.stderr @@ -1,7 +1,7 @@ error: removing an expression is not supported in this position --> $DIR/cfg-eval-fail.rs:5:25 | -LL | let _ = #[cfg_eval] #[cfg(FALSE)] 0; +LL | let _ = #[cfg_eval] #[cfg(false)] 0; | ^^^^^^^^^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/proc-macro/cfg-eval-inner.rs b/tests/ui/proc-macro/cfg-eval-inner.rs index 7493f3ea5236..dc4efd6ba15f 100644 --- a/tests/ui/proc-macro/cfg-eval-inner.rs +++ b/tests/ui/proc-macro/cfg-eval-inner.rs @@ -32,7 +32,7 @@ impl Foo<[u8; { #![cfg_attr(not(FALSE), rustc_dummy(evaluated_attr))] fn bar() { - #[cfg(FALSE)] let a = 1; + #[cfg(false)] let a = 1; } } diff --git a/tests/ui/proc-macro/cfg-eval.rs b/tests/ui/proc-macro/cfg-eval.rs index 1d9b4f23ea5c..ddf370805960 100644 --- a/tests/ui/proc-macro/cfg-eval.rs +++ b/tests/ui/proc-macro/cfg-eval.rs @@ -15,7 +15,7 @@ extern crate test_macros; #[cfg_eval] #[print_attr] struct S1 { - #[cfg(FALSE)] + #[cfg(false)] field_false: u8, #[cfg(all(/*true*/))] #[cfg_attr(FALSE, unknown_attr)] @@ -24,7 +24,7 @@ struct S1 { } #[cfg_eval] -#[cfg(FALSE)] +#[cfg(false)] struct S2 {} fn main() { @@ -33,5 +33,5 @@ fn main() { // expression. `#[cfg]` is not supported inside parenthesized expressions, so this will // produce an error when attribute collection runs. let _ = #[cfg_eval] #[print_attr] #[cfg_attr(not(FALSE), rustc_dummy)] - (#[cfg(FALSE)] 0, #[cfg(all(/*true*/))] 1,); + (#[cfg(false)] 0, #[cfg(all(/*true*/))] 1,); } diff --git a/tests/ui/proc-macro/derive-cfg-nested-tokens.rs b/tests/ui/proc-macro/derive-cfg-nested-tokens.rs index 7d4e8d8373d6..ec6aba0d1ea3 100644 --- a/tests/ui/proc-macro/derive-cfg-nested-tokens.rs +++ b/tests/ui/proc-macro/derive-cfg-nested-tokens.rs @@ -15,7 +15,7 @@ struct S { // - on eagerly configured `S` (from `impl Copy`), only 11 should be printed // - on non-configured `S` (from `struct S`), both 10 and 11 should be printed field: [u8; #[print_attr] { - #[cfg(FALSE)] { 10 } + #[cfg(false)] { 10 } #[cfg(not(FALSE))] { 11 } }], } diff --git a/tests/ui/proc-macro/derive-cfg-nested-tokens.stdout b/tests/ui/proc-macro/derive-cfg-nested-tokens.stdout index 05bf21ee8f9b..9dbddc95902d 100644 --- a/tests/ui/proc-macro/derive-cfg-nested-tokens.stdout +++ b/tests/ui/proc-macro/derive-cfg-nested-tokens.stdout @@ -54,7 +54,7 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ span: #0 bytes(452..523), }, ] -PRINT-ATTR INPUT (DISPLAY): { #[cfg(FALSE)] { 10 } #[cfg(not(FALSE))] { 11 } } +PRINT-ATTR INPUT (DISPLAY): { #[cfg(false)] { 10 } #[cfg(not(FALSE))] { 11 } } PRINT-ATTR INPUT (DEBUG): TokenStream [ Group { delimiter: Brace, @@ -75,7 +75,7 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ delimiter: Parenthesis, stream: TokenStream [ Ident { - ident: "FALSE", + ident: "false", span: #0 bytes(468..473), }, ], diff --git a/tests/ui/proc-macro/expand-to-derive.rs b/tests/ui/proc-macro/expand-to-derive.rs index 0e38e471980b..05c8e3262431 100644 --- a/tests/ui/proc-macro/expand-to-derive.rs +++ b/tests/ui/proc-macro/expand-to-derive.rs @@ -14,7 +14,7 @@ macro_rules! expand_to_derive { ($item:item) => { #[derive(Print)] struct Foo { - #[cfg(FALSE)] removed: bool, + #[cfg(false)] removed: bool, field: [bool; { $item 0 @@ -26,7 +26,7 @@ macro_rules! expand_to_derive { expand_to_derive! { #[cfg_attr(not(FALSE), rustc_dummy)] struct Inner { - #[cfg(FALSE)] removed_inner_field: bool, + #[cfg(false)] removed_inner_field: bool, other_inner_field: u8, } } diff --git a/tests/ui/proc-macro/inner-attrs.rs b/tests/ui/proc-macro/inner-attrs.rs index 34c37ddfac35..ca4b2029a338 100644 --- a/tests/ui/proc-macro/inner-attrs.rs +++ b/tests/ui/proc-macro/inner-attrs.rs @@ -1,6 +1,5 @@ // gate-test-custom_inner_attributes -//@ compile-flags: -Z span-debug --error-format human -//@ error-pattern:expected non-macro inner attribute +//@ compile-flags: -Z span-debug //@ proc-macro: test-macros.rs //@ edition:2018 @@ -63,23 +62,27 @@ fn bar() { for _ in &[true] { #![print_attr] + //~^ ERROR expected non-macro inner attribute, found attribute macro `print_attr` } let _ = { #![print_attr] + //~^ ERROR expected non-macro inner attribute, found attribute macro `print_attr` }; let _ = async { #![print_attr] + //~^ ERROR expected non-macro inner attribute, found attribute macro `print_attr` }; { #![print_attr] + //~^ ERROR expected non-macro inner attribute, found attribute macro `print_attr` }; } -extern { +extern { //~ WARN `extern` declarations without an explicit ABI are deprecated fn weird_extern() { #![print_target_and_args_consume(tenth)] } diff --git a/tests/ui/proc-macro/inner-attrs.stderr b/tests/ui/proc-macro/inner-attrs.stderr index 8b5fec1b4c37..54cccae8da08 100644 --- a/tests/ui/proc-macro/inner-attrs.stderr +++ b/tests/ui/proc-macro/inner-attrs.stderr @@ -1,5 +1,5 @@ error: expected non-macro inner attribute, found attribute macro `print_attr` - --> $DIR/inner-attrs.rs:65:12 + --> $DIR/inner-attrs.rs:64:12 | LL | #![print_attr] | ^^^^^^^^^^ not a non-macro inner attribute @@ -11,19 +11,19 @@ LL | #![print_attr] | ^^^^^^^^^^ not a non-macro inner attribute error: expected non-macro inner attribute, found attribute macro `print_attr` - --> $DIR/inner-attrs.rs:73:12 + --> $DIR/inner-attrs.rs:74:12 | LL | #![print_attr] | ^^^^^^^^^^ not a non-macro inner attribute error: expected non-macro inner attribute, found attribute macro `print_attr` - --> $DIR/inner-attrs.rs:77:12 + --> $DIR/inner-attrs.rs:79:12 | LL | #![print_attr] | ^^^^^^^^^^ not a non-macro inner attribute -warning: extern declarations without an explicit ABI are deprecated - --> $DIR/inner-attrs.rs:82:1 +warning: `extern` declarations without an explicit ABI are deprecated + --> $DIR/inner-attrs.rs:85:1 | LL | extern { | ^^^^^^ help: explicitly specify the "C" ABI: `extern "C"` diff --git a/tests/ui/proc-macro/inner-attrs.stdout b/tests/ui/proc-macro/inner-attrs.stdout index ed47ee2cf5ac..4496f7b90c4e 100644 --- a/tests/ui/proc-macro/inner-attrs.stdout +++ b/tests/ui/proc-macro/inner-attrs.stdout @@ -2,7 +2,7 @@ PRINT-ATTR_ARGS INPUT (DISPLAY): first PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [ Ident { ident: "first", - span: $DIR/inner-attrs.rs:18:25: 18:30 (#0), + span: $DIR/inner-attrs.rs:17:25: 17:30 (#0), }, ] PRINT-ATTR INPUT (DISPLAY): #[print_target_and_args(second)] fn foo() @@ -13,44 +13,74 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ Punct { ch: '#', spacing: Alone, - span: $DIR/inner-attrs.rs:19:1: 19:2 (#0), + span: $DIR/inner-attrs.rs:18:1: 18:2 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "print_target_and_args", - span: $DIR/inner-attrs.rs:19:3: 19:24 (#0), + span: $DIR/inner-attrs.rs:18:3: 18:24 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "second", - span: $DIR/inner-attrs.rs:19:25: 19:31 (#0), + span: $DIR/inner-attrs.rs:18:25: 18:31 (#0), }, ], - span: $DIR/inner-attrs.rs:19:24: 19:32 (#0), + span: $DIR/inner-attrs.rs:18:24: 18:32 (#0), }, ], - span: $DIR/inner-attrs.rs:19:2: 19:33 (#0), + span: $DIR/inner-attrs.rs:18:2: 18:33 (#0), }, Ident { ident: "fn", - span: $DIR/inner-attrs.rs:20:1: 20:3 (#0), + span: $DIR/inner-attrs.rs:19:1: 19:3 (#0), }, Ident { ident: "foo", - span: $DIR/inner-attrs.rs:20:4: 20:7 (#0), + span: $DIR/inner-attrs.rs:19:4: 19:7 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [], - span: $DIR/inner-attrs.rs:20:7: 20:9 (#0), + span: $DIR/inner-attrs.rs:19:7: 19:9 (#0), }, Group { delimiter: Brace, stream: TokenStream [ + Punct { + ch: '#', + spacing: Joint, + span: $DIR/inner-attrs.rs:20:5: 20:6 (#0), + }, + Punct { + ch: '!', + spacing: Alone, + span: $DIR/inner-attrs.rs:20:6: 20:7 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "print_target_and_args", + span: $DIR/inner-attrs.rs:20:8: 20:29 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "third", + span: $DIR/inner-attrs.rs:20:30: 20:35 (#0), + }, + ], + span: $DIR/inner-attrs.rs:20:29: 20:36 (#0), + }, + ], + span: $DIR/inner-attrs.rs:20:7: 20:37 (#0), + }, Punct { ch: '#', spacing: Joint, @@ -68,58 +98,28 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ ident: "print_target_and_args", span: $DIR/inner-attrs.rs:21:8: 21:29 (#0), }, - Group { - delimiter: Parenthesis, - stream: TokenStream [ - Ident { - ident: "third", - span: $DIR/inner-attrs.rs:21:30: 21:35 (#0), - }, - ], - span: $DIR/inner-attrs.rs:21:29: 21:36 (#0), - }, - ], - span: $DIR/inner-attrs.rs:21:7: 21:37 (#0), - }, - Punct { - ch: '#', - spacing: Joint, - span: $DIR/inner-attrs.rs:22:5: 22:6 (#0), - }, - Punct { - ch: '!', - spacing: Alone, - span: $DIR/inner-attrs.rs:22:6: 22:7 (#0), - }, - Group { - delimiter: Bracket, - stream: TokenStream [ - Ident { - ident: "print_target_and_args", - span: $DIR/inner-attrs.rs:22:8: 22:29 (#0), - }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "fourth", - span: $DIR/inner-attrs.rs:22:30: 22:36 (#0), + span: $DIR/inner-attrs.rs:21:30: 21:36 (#0), }, ], - span: $DIR/inner-attrs.rs:22:29: 22:37 (#0), + span: $DIR/inner-attrs.rs:21:29: 21:37 (#0), }, ], - span: $DIR/inner-attrs.rs:22:7: 22:38 (#0), + span: $DIR/inner-attrs.rs:21:7: 21:38 (#0), }, ], - span: $DIR/inner-attrs.rs:20:10: 23:2 (#0), + span: $DIR/inner-attrs.rs:19:10: 22:2 (#0), }, ] PRINT-ATTR_ARGS INPUT (DISPLAY): second PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [ Ident { ident: "second", - span: $DIR/inner-attrs.rs:19:25: 19:31 (#0), + span: $DIR/inner-attrs.rs:18:25: 18:31 (#0), }, ] PRINT-ATTR INPUT (DISPLAY): fn foo() @@ -129,16 +129,106 @@ PRINT-ATTR DEEP-RE-COLLECTED (DISPLAY): fn foo() PRINT-ATTR INPUT (DEBUG): TokenStream [ Ident { ident: "fn", - span: $DIR/inner-attrs.rs:20:1: 20:3 (#0), + span: $DIR/inner-attrs.rs:19:1: 19:3 (#0), }, Ident { ident: "foo", - span: $DIR/inner-attrs.rs:20:4: 20:7 (#0), + span: $DIR/inner-attrs.rs:19:4: 19:7 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [], - span: $DIR/inner-attrs.rs:20:7: 20:9 (#0), + span: $DIR/inner-attrs.rs:19:7: 19:9 (#0), + }, + Group { + delimiter: Brace, + stream: TokenStream [ + Punct { + ch: '#', + spacing: Joint, + span: $DIR/inner-attrs.rs:20:5: 20:6 (#0), + }, + Punct { + ch: '!', + spacing: Alone, + span: $DIR/inner-attrs.rs:20:6: 20:7 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "print_target_and_args", + span: $DIR/inner-attrs.rs:20:8: 20:29 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "third", + span: $DIR/inner-attrs.rs:20:30: 20:35 (#0), + }, + ], + span: $DIR/inner-attrs.rs:20:29: 20:36 (#0), + }, + ], + span: $DIR/inner-attrs.rs:20:7: 20:37 (#0), + }, + Punct { + ch: '#', + spacing: Joint, + span: $DIR/inner-attrs.rs:21:5: 21:6 (#0), + }, + Punct { + ch: '!', + spacing: Alone, + span: $DIR/inner-attrs.rs:21:6: 21:7 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "print_target_and_args", + span: $DIR/inner-attrs.rs:21:8: 21:29 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "fourth", + span: $DIR/inner-attrs.rs:21:30: 21:36 (#0), + }, + ], + span: $DIR/inner-attrs.rs:21:29: 21:37 (#0), + }, + ], + span: $DIR/inner-attrs.rs:21:7: 21:38 (#0), + }, + ], + span: $DIR/inner-attrs.rs:19:10: 22:2 (#0), + }, +] +PRINT-ATTR_ARGS INPUT (DISPLAY): third +PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [ + Ident { + ident: "third", + span: $DIR/inner-attrs.rs:20:30: 20:35 (#0), + }, +] +PRINT-ATTR INPUT (DISPLAY): fn foo() { #![print_target_and_args(fourth)] } +PRINT-ATTR DEEP-RE-COLLECTED (DISPLAY): fn foo() { #! [print_target_and_args(fourth)] } +PRINT-ATTR INPUT (DEBUG): TokenStream [ + Ident { + ident: "fn", + span: $DIR/inner-attrs.rs:19:1: 19:3 (#0), + }, + Ident { + ident: "foo", + span: $DIR/inner-attrs.rs:19:4: 19:7 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [], + span: $DIR/inner-attrs.rs:19:7: 19:9 (#0), }, Group { delimiter: Brace, @@ -160,146 +250,56 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ ident: "print_target_and_args", span: $DIR/inner-attrs.rs:21:8: 21:29 (#0), }, - Group { - delimiter: Parenthesis, - stream: TokenStream [ - Ident { - ident: "third", - span: $DIR/inner-attrs.rs:21:30: 21:35 (#0), - }, - ], - span: $DIR/inner-attrs.rs:21:29: 21:36 (#0), - }, - ], - span: $DIR/inner-attrs.rs:21:7: 21:37 (#0), - }, - Punct { - ch: '#', - spacing: Joint, - span: $DIR/inner-attrs.rs:22:5: 22:6 (#0), - }, - Punct { - ch: '!', - spacing: Alone, - span: $DIR/inner-attrs.rs:22:6: 22:7 (#0), - }, - Group { - delimiter: Bracket, - stream: TokenStream [ - Ident { - ident: "print_target_and_args", - span: $DIR/inner-attrs.rs:22:8: 22:29 (#0), - }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "fourth", - span: $DIR/inner-attrs.rs:22:30: 22:36 (#0), + span: $DIR/inner-attrs.rs:21:30: 21:36 (#0), }, ], - span: $DIR/inner-attrs.rs:22:29: 22:37 (#0), + span: $DIR/inner-attrs.rs:21:29: 21:37 (#0), }, ], - span: $DIR/inner-attrs.rs:22:7: 22:38 (#0), + span: $DIR/inner-attrs.rs:21:7: 21:38 (#0), }, ], - span: $DIR/inner-attrs.rs:20:10: 23:2 (#0), - }, -] -PRINT-ATTR_ARGS INPUT (DISPLAY): third -PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [ - Ident { - ident: "third", - span: $DIR/inner-attrs.rs:21:30: 21:35 (#0), - }, -] -PRINT-ATTR INPUT (DISPLAY): fn foo() { #![print_target_and_args(fourth)] } -PRINT-ATTR DEEP-RE-COLLECTED (DISPLAY): fn foo() { #! [print_target_and_args(fourth)] } -PRINT-ATTR INPUT (DEBUG): TokenStream [ - Ident { - ident: "fn", - span: $DIR/inner-attrs.rs:20:1: 20:3 (#0), - }, - Ident { - ident: "foo", - span: $DIR/inner-attrs.rs:20:4: 20:7 (#0), - }, - Group { - delimiter: Parenthesis, - stream: TokenStream [], - span: $DIR/inner-attrs.rs:20:7: 20:9 (#0), - }, - Group { - delimiter: Brace, - stream: TokenStream [ - Punct { - ch: '#', - spacing: Joint, - span: $DIR/inner-attrs.rs:22:5: 22:6 (#0), - }, - Punct { - ch: '!', - spacing: Alone, - span: $DIR/inner-attrs.rs:22:6: 22:7 (#0), - }, - Group { - delimiter: Bracket, - stream: TokenStream [ - Ident { - ident: "print_target_and_args", - span: $DIR/inner-attrs.rs:22:8: 22:29 (#0), - }, - Group { - delimiter: Parenthesis, - stream: TokenStream [ - Ident { - ident: "fourth", - span: $DIR/inner-attrs.rs:22:30: 22:36 (#0), - }, - ], - span: $DIR/inner-attrs.rs:22:29: 22:37 (#0), - }, - ], - span: $DIR/inner-attrs.rs:22:7: 22:38 (#0), - }, - ], - span: $DIR/inner-attrs.rs:20:10: 23:2 (#0), + span: $DIR/inner-attrs.rs:19:10: 22:2 (#0), }, ] PRINT-ATTR_ARGS INPUT (DISPLAY): fourth PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [ Ident { ident: "fourth", - span: $DIR/inner-attrs.rs:22:30: 22:36 (#0), + span: $DIR/inner-attrs.rs:21:30: 21:36 (#0), }, ] PRINT-ATTR INPUT (DISPLAY): fn foo() {} PRINT-ATTR INPUT (DEBUG): TokenStream [ Ident { ident: "fn", - span: $DIR/inner-attrs.rs:20:1: 20:3 (#0), + span: $DIR/inner-attrs.rs:19:1: 19:3 (#0), }, Ident { ident: "foo", - span: $DIR/inner-attrs.rs:20:4: 20:7 (#0), + span: $DIR/inner-attrs.rs:19:4: 19:7 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [], - span: $DIR/inner-attrs.rs:20:7: 20:9 (#0), + span: $DIR/inner-attrs.rs:19:7: 19:9 (#0), }, Group { delimiter: Brace, stream: TokenStream [], - span: $DIR/inner-attrs.rs:20:10: 23:2 (#0), + span: $DIR/inner-attrs.rs:19:10: 22:2 (#0), }, ] PRINT-ATTR_ARGS INPUT (DISPLAY): mod_first PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [ Ident { ident: "mod_first", - span: $DIR/inner-attrs.rs:25:25: 25:34 (#0), + span: $DIR/inner-attrs.rs:24:25: 24:34 (#0), }, ] PRINT-ATTR INPUT (DISPLAY): #[print_target_and_args(mod_second)] mod inline_mod @@ -313,39 +313,69 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ Punct { ch: '#', spacing: Alone, - span: $DIR/inner-attrs.rs:26:1: 26:2 (#0), + span: $DIR/inner-attrs.rs:25:1: 25:2 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "print_target_and_args", - span: $DIR/inner-attrs.rs:26:3: 26:24 (#0), + span: $DIR/inner-attrs.rs:25:3: 25:24 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "mod_second", - span: $DIR/inner-attrs.rs:26:25: 26:35 (#0), + span: $DIR/inner-attrs.rs:25:25: 25:35 (#0), }, ], - span: $DIR/inner-attrs.rs:26:24: 26:36 (#0), + span: $DIR/inner-attrs.rs:25:24: 25:36 (#0), }, ], - span: $DIR/inner-attrs.rs:26:2: 26:37 (#0), + span: $DIR/inner-attrs.rs:25:2: 25:37 (#0), }, Ident { ident: "mod", - span: $DIR/inner-attrs.rs:27:1: 27:4 (#0), + span: $DIR/inner-attrs.rs:26:1: 26:4 (#0), }, Ident { ident: "inline_mod", - span: $DIR/inner-attrs.rs:27:5: 27:15 (#0), + span: $DIR/inner-attrs.rs:26:5: 26:15 (#0), }, Group { delimiter: Brace, stream: TokenStream [ + Punct { + ch: '#', + spacing: Joint, + span: $DIR/inner-attrs.rs:27:5: 27:6 (#0), + }, + Punct { + ch: '!', + spacing: Alone, + span: $DIR/inner-attrs.rs:27:6: 27:7 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "print_target_and_args", + span: $DIR/inner-attrs.rs:27:8: 27:29 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "mod_third", + span: $DIR/inner-attrs.rs:27:30: 27:39 (#0), + }, + ], + span: $DIR/inner-attrs.rs:27:29: 27:40 (#0), + }, + ], + span: $DIR/inner-attrs.rs:27:7: 27:41 (#0), + }, Punct { ch: '#', spacing: Joint, @@ -363,58 +393,28 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ ident: "print_target_and_args", span: $DIR/inner-attrs.rs:28:8: 28:29 (#0), }, - Group { - delimiter: Parenthesis, - stream: TokenStream [ - Ident { - ident: "mod_third", - span: $DIR/inner-attrs.rs:28:30: 28:39 (#0), - }, - ], - span: $DIR/inner-attrs.rs:28:29: 28:40 (#0), - }, - ], - span: $DIR/inner-attrs.rs:28:7: 28:41 (#0), - }, - Punct { - ch: '#', - spacing: Joint, - span: $DIR/inner-attrs.rs:29:5: 29:6 (#0), - }, - Punct { - ch: '!', - spacing: Alone, - span: $DIR/inner-attrs.rs:29:6: 29:7 (#0), - }, - Group { - delimiter: Bracket, - stream: TokenStream [ - Ident { - ident: "print_target_and_args", - span: $DIR/inner-attrs.rs:29:8: 29:29 (#0), - }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "mod_fourth", - span: $DIR/inner-attrs.rs:29:30: 29:40 (#0), + span: $DIR/inner-attrs.rs:28:30: 28:40 (#0), }, ], - span: $DIR/inner-attrs.rs:29:29: 29:41 (#0), + span: $DIR/inner-attrs.rs:28:29: 28:41 (#0), }, ], - span: $DIR/inner-attrs.rs:29:7: 29:42 (#0), + span: $DIR/inner-attrs.rs:28:7: 28:42 (#0), }, ], - span: $DIR/inner-attrs.rs:27:16: 30:2 (#0), + span: $DIR/inner-attrs.rs:26:16: 29:2 (#0), }, ] PRINT-ATTR_ARGS INPUT (DISPLAY): mod_second PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [ Ident { ident: "mod_second", - span: $DIR/inner-attrs.rs:26:25: 26:35 (#0), + span: $DIR/inner-attrs.rs:25:25: 25:35 (#0), }, ] PRINT-ATTR INPUT (DISPLAY): mod inline_mod @@ -427,11 +427,96 @@ PRINT-ATTR DEEP-RE-COLLECTED (DISPLAY): mod inline_mod PRINT-ATTR INPUT (DEBUG): TokenStream [ Ident { ident: "mod", - span: $DIR/inner-attrs.rs:27:1: 27:4 (#0), + span: $DIR/inner-attrs.rs:26:1: 26:4 (#0), }, Ident { ident: "inline_mod", - span: $DIR/inner-attrs.rs:27:5: 27:15 (#0), + span: $DIR/inner-attrs.rs:26:5: 26:15 (#0), + }, + Group { + delimiter: Brace, + stream: TokenStream [ + Punct { + ch: '#', + spacing: Joint, + span: $DIR/inner-attrs.rs:27:5: 27:6 (#0), + }, + Punct { + ch: '!', + spacing: Alone, + span: $DIR/inner-attrs.rs:27:6: 27:7 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "print_target_and_args", + span: $DIR/inner-attrs.rs:27:8: 27:29 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "mod_third", + span: $DIR/inner-attrs.rs:27:30: 27:39 (#0), + }, + ], + span: $DIR/inner-attrs.rs:27:29: 27:40 (#0), + }, + ], + span: $DIR/inner-attrs.rs:27:7: 27:41 (#0), + }, + Punct { + ch: '#', + spacing: Joint, + span: $DIR/inner-attrs.rs:28:5: 28:6 (#0), + }, + Punct { + ch: '!', + spacing: Alone, + span: $DIR/inner-attrs.rs:28:6: 28:7 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "print_target_and_args", + span: $DIR/inner-attrs.rs:28:8: 28:29 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "mod_fourth", + span: $DIR/inner-attrs.rs:28:30: 28:40 (#0), + }, + ], + span: $DIR/inner-attrs.rs:28:29: 28:41 (#0), + }, + ], + span: $DIR/inner-attrs.rs:28:7: 28:42 (#0), + }, + ], + span: $DIR/inner-attrs.rs:26:16: 29:2 (#0), + }, +] +PRINT-ATTR_ARGS INPUT (DISPLAY): mod_third +PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [ + Ident { + ident: "mod_third", + span: $DIR/inner-attrs.rs:27:30: 27:39 (#0), + }, +] +PRINT-ATTR INPUT (DISPLAY): mod inline_mod { #![print_target_and_args(mod_fourth)] } +PRINT-ATTR DEEP-RE-COLLECTED (DISPLAY): mod inline_mod { #! [print_target_and_args(mod_fourth)] } +PRINT-ATTR INPUT (DEBUG): TokenStream [ + Ident { + ident: "mod", + span: $DIR/inner-attrs.rs:26:1: 26:4 (#0), + }, + Ident { + ident: "inline_mod", + span: $DIR/inner-attrs.rs:26:5: 26:15 (#0), }, Group { delimiter: Brace, @@ -453,129 +538,44 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ ident: "print_target_and_args", span: $DIR/inner-attrs.rs:28:8: 28:29 (#0), }, - Group { - delimiter: Parenthesis, - stream: TokenStream [ - Ident { - ident: "mod_third", - span: $DIR/inner-attrs.rs:28:30: 28:39 (#0), - }, - ], - span: $DIR/inner-attrs.rs:28:29: 28:40 (#0), - }, - ], - span: $DIR/inner-attrs.rs:28:7: 28:41 (#0), - }, - Punct { - ch: '#', - spacing: Joint, - span: $DIR/inner-attrs.rs:29:5: 29:6 (#0), - }, - Punct { - ch: '!', - spacing: Alone, - span: $DIR/inner-attrs.rs:29:6: 29:7 (#0), - }, - Group { - delimiter: Bracket, - stream: TokenStream [ - Ident { - ident: "print_target_and_args", - span: $DIR/inner-attrs.rs:29:8: 29:29 (#0), - }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "mod_fourth", - span: $DIR/inner-attrs.rs:29:30: 29:40 (#0), + span: $DIR/inner-attrs.rs:28:30: 28:40 (#0), }, ], - span: $DIR/inner-attrs.rs:29:29: 29:41 (#0), + span: $DIR/inner-attrs.rs:28:29: 28:41 (#0), }, ], - span: $DIR/inner-attrs.rs:29:7: 29:42 (#0), + span: $DIR/inner-attrs.rs:28:7: 28:42 (#0), }, ], - span: $DIR/inner-attrs.rs:27:16: 30:2 (#0), - }, -] -PRINT-ATTR_ARGS INPUT (DISPLAY): mod_third -PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [ - Ident { - ident: "mod_third", - span: $DIR/inner-attrs.rs:28:30: 28:39 (#0), - }, -] -PRINT-ATTR INPUT (DISPLAY): mod inline_mod { #![print_target_and_args(mod_fourth)] } -PRINT-ATTR DEEP-RE-COLLECTED (DISPLAY): mod inline_mod { #! [print_target_and_args(mod_fourth)] } -PRINT-ATTR INPUT (DEBUG): TokenStream [ - Ident { - ident: "mod", - span: $DIR/inner-attrs.rs:27:1: 27:4 (#0), - }, - Ident { - ident: "inline_mod", - span: $DIR/inner-attrs.rs:27:5: 27:15 (#0), - }, - Group { - delimiter: Brace, - stream: TokenStream [ - Punct { - ch: '#', - spacing: Joint, - span: $DIR/inner-attrs.rs:29:5: 29:6 (#0), - }, - Punct { - ch: '!', - spacing: Alone, - span: $DIR/inner-attrs.rs:29:6: 29:7 (#0), - }, - Group { - delimiter: Bracket, - stream: TokenStream [ - Ident { - ident: "print_target_and_args", - span: $DIR/inner-attrs.rs:29:8: 29:29 (#0), - }, - Group { - delimiter: Parenthesis, - stream: TokenStream [ - Ident { - ident: "mod_fourth", - span: $DIR/inner-attrs.rs:29:30: 29:40 (#0), - }, - ], - span: $DIR/inner-attrs.rs:29:29: 29:41 (#0), - }, - ], - span: $DIR/inner-attrs.rs:29:7: 29:42 (#0), - }, - ], - span: $DIR/inner-attrs.rs:27:16: 30:2 (#0), + span: $DIR/inner-attrs.rs:26:16: 29:2 (#0), }, ] PRINT-ATTR_ARGS INPUT (DISPLAY): mod_fourth PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [ Ident { ident: "mod_fourth", - span: $DIR/inner-attrs.rs:29:30: 29:40 (#0), + span: $DIR/inner-attrs.rs:28:30: 28:40 (#0), }, ] PRINT-ATTR INPUT (DISPLAY): mod inline_mod {} PRINT-ATTR INPUT (DEBUG): TokenStream [ Ident { ident: "mod", - span: $DIR/inner-attrs.rs:27:1: 27:4 (#0), + span: $DIR/inner-attrs.rs:26:1: 26:4 (#0), }, Ident { ident: "inline_mod", - span: $DIR/inner-attrs.rs:27:5: 27:15 (#0), + span: $DIR/inner-attrs.rs:26:5: 26:15 (#0), }, Group { delimiter: Brace, stream: TokenStream [], - span: $DIR/inner-attrs.rs:27:16: 30:2 (#0), + span: $DIR/inner-attrs.rs:26:16: 29:2 (#0), }, ] PRINT-DERIVE INPUT (DISPLAY): struct MyDerivePrint @@ -585,63 +585,63 @@ PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): struct MyDerivePrint PRINT-DERIVE INPUT (DEBUG): TokenStream [ Ident { ident: "struct", - span: $DIR/inner-attrs.rs:37:1: 37:7 (#0), + span: $DIR/inner-attrs.rs:36:1: 36:7 (#0), }, Ident { ident: "MyDerivePrint", - span: $DIR/inner-attrs.rs:37:8: 37:21 (#0), + span: $DIR/inner-attrs.rs:36:8: 36:21 (#0), }, Group { delimiter: Brace, stream: TokenStream [ Ident { ident: "field", - span: $DIR/inner-attrs.rs:38:5: 38:10 (#0), + span: $DIR/inner-attrs.rs:37:5: 37:10 (#0), }, Punct { ch: ':', spacing: Alone, - span: $DIR/inner-attrs.rs:38:10: 38:11 (#0), + span: $DIR/inner-attrs.rs:37:10: 37:11 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "u8", - span: $DIR/inner-attrs.rs:38:13: 38:15 (#0), + span: $DIR/inner-attrs.rs:37:13: 37:15 (#0), }, Punct { ch: ';', spacing: Alone, - span: $DIR/inner-attrs.rs:38:15: 38:16 (#0), + span: $DIR/inner-attrs.rs:37:15: 37:16 (#0), }, Group { delimiter: Brace, stream: TokenStream [ Ident { ident: "match", - span: $DIR/inner-attrs.rs:39:9: 39:14 (#0), + span: $DIR/inner-attrs.rs:38:9: 38:14 (#0), }, Ident { ident: "true", - span: $DIR/inner-attrs.rs:39:15: 39:19 (#0), + span: $DIR/inner-attrs.rs:38:15: 38:19 (#0), }, Group { delimiter: Brace, stream: TokenStream [ Ident { ident: "_", - span: $DIR/inner-attrs.rs:40:13: 40:14 (#0), + span: $DIR/inner-attrs.rs:39:13: 39:14 (#0), }, Punct { ch: '=', spacing: Joint, - span: $DIR/inner-attrs.rs:40:15: 40:16 (#0), + span: $DIR/inner-attrs.rs:39:15: 39:16 (#0), }, Punct { ch: '>', spacing: Alone, - span: $DIR/inner-attrs.rs:40:16: 40:17 (#0), + span: $DIR/inner-attrs.rs:39:16: 39:17 (#0), }, Group { delimiter: Brace, @@ -649,69 +649,69 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [ Punct { ch: '#', spacing: Joint, - span: $DIR/inner-attrs.rs:41:17: 41:18 (#0), + span: $DIR/inner-attrs.rs:40:17: 40:18 (#0), }, Punct { ch: '!', spacing: Alone, - span: $DIR/inner-attrs.rs:41:18: 41:19 (#0), + span: $DIR/inner-attrs.rs:40:18: 40:19 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "rustc_dummy", - span: $DIR/inner-attrs.rs:41:41: 41:52 (#0), + span: $DIR/inner-attrs.rs:40:41: 40:52 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "third", - span: $DIR/inner-attrs.rs:41:53: 41:58 (#0), + span: $DIR/inner-attrs.rs:40:53: 40:58 (#0), }, ], - span: $DIR/inner-attrs.rs:41:52: 41:59 (#0), + span: $DIR/inner-attrs.rs:40:52: 40:59 (#0), }, ], - span: $DIR/inner-attrs.rs:41:19: 41:61 (#0), + span: $DIR/inner-attrs.rs:40:19: 40:61 (#0), }, Ident { ident: "true", - span: $DIR/inner-attrs.rs:42:17: 42:21 (#0), + span: $DIR/inner-attrs.rs:41:17: 41:21 (#0), }, ], - span: $DIR/inner-attrs.rs:40:18: 43:14 (#0), + span: $DIR/inner-attrs.rs:39:18: 42:14 (#0), }, ], - span: $DIR/inner-attrs.rs:39:20: 44:10 (#0), + span: $DIR/inner-attrs.rs:38:20: 43:10 (#0), }, Punct { ch: ';', spacing: Alone, - span: $DIR/inner-attrs.rs:44:10: 44:11 (#0), + span: $DIR/inner-attrs.rs:43:10: 43:11 (#0), }, Literal { kind: Integer, symbol: "0", suffix: None, - span: $DIR/inner-attrs.rs:45:9: 45:10 (#0), + span: $DIR/inner-attrs.rs:44:9: 44:10 (#0), }, ], - span: $DIR/inner-attrs.rs:38:17: 46:6 (#0), + span: $DIR/inner-attrs.rs:37:17: 45:6 (#0), }, ], - span: $DIR/inner-attrs.rs:38:12: 46:7 (#0), + span: $DIR/inner-attrs.rs:37:12: 45:7 (#0), }, ], - span: $DIR/inner-attrs.rs:37:22: 47:2 (#0), + span: $DIR/inner-attrs.rs:36:22: 46:2 (#0), }, ] PRINT-ATTR_ARGS INPUT (DISPLAY): tuple_attrs PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [ Ident { ident: "tuple_attrs", - span: $DIR/inner-attrs.rs:50:29: 50:40 (#0), + span: $DIR/inner-attrs.rs:49:29: 49:40 (#0), }, ] PRINT-ATTR INPUT (DISPLAY): (3, 4, { #![cfg_attr(not(FALSE), rustc_dummy(innermost))] 5 }); @@ -724,23 +724,23 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ kind: Integer, symbol: "3", suffix: None, - span: $DIR/inner-attrs.rs:51:9: 51:10 (#0), + span: $DIR/inner-attrs.rs:50:9: 50:10 (#0), }, Punct { ch: ',', spacing: Alone, - span: $DIR/inner-attrs.rs:51:10: 51:11 (#0), + span: $DIR/inner-attrs.rs:50:10: 50:11 (#0), }, Literal { kind: Integer, symbol: "4", suffix: None, - span: $DIR/inner-attrs.rs:51:12: 51:13 (#0), + span: $DIR/inner-attrs.rs:50:12: 50:13 (#0), }, Punct { ch: ',', spacing: Alone, - span: $DIR/inner-attrs.rs:51:13: 51:14 (#0), + span: $DIR/inner-attrs.rs:50:13: 50:14 (#0), }, Group { delimiter: Brace, @@ -748,85 +748,85 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ Punct { ch: '#', spacing: Joint, + span: $DIR/inner-attrs.rs:51:13: 51:14 (#0), + }, + Punct { + ch: '!', + spacing: Alone, + span: $DIR/inner-attrs.rs:51:14: 51:15 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "cfg_attr", + span: $DIR/inner-attrs.rs:51:16: 51:24 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "not", + span: $DIR/inner-attrs.rs:51:25: 51:28 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "FALSE", + span: $DIR/inner-attrs.rs:51:29: 51:34 (#0), + }, + ], + span: $DIR/inner-attrs.rs:51:28: 51:35 (#0), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/inner-attrs.rs:51:35: 51:36 (#0), + }, + Ident { + ident: "rustc_dummy", + span: $DIR/inner-attrs.rs:51:37: 51:48 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "innermost", + span: $DIR/inner-attrs.rs:51:49: 51:58 (#0), + }, + ], + span: $DIR/inner-attrs.rs:51:48: 51:59 (#0), + }, + ], + span: $DIR/inner-attrs.rs:51:24: 51:60 (#0), + }, + ], + span: $DIR/inner-attrs.rs:51:15: 51:61 (#0), + }, + Literal { + kind: Integer, + symbol: "5", + suffix: None, span: $DIR/inner-attrs.rs:52:13: 52:14 (#0), }, - Punct { - ch: '!', - spacing: Alone, - span: $DIR/inner-attrs.rs:52:14: 52:15 (#0), - }, - Group { - delimiter: Bracket, - stream: TokenStream [ - Ident { - ident: "cfg_attr", - span: $DIR/inner-attrs.rs:52:16: 52:24 (#0), - }, - Group { - delimiter: Parenthesis, - stream: TokenStream [ - Ident { - ident: "not", - span: $DIR/inner-attrs.rs:52:25: 52:28 (#0), - }, - Group { - delimiter: Parenthesis, - stream: TokenStream [ - Ident { - ident: "FALSE", - span: $DIR/inner-attrs.rs:52:29: 52:34 (#0), - }, - ], - span: $DIR/inner-attrs.rs:52:28: 52:35 (#0), - }, - Punct { - ch: ',', - spacing: Alone, - span: $DIR/inner-attrs.rs:52:35: 52:36 (#0), - }, - Ident { - ident: "rustc_dummy", - span: $DIR/inner-attrs.rs:52:37: 52:48 (#0), - }, - Group { - delimiter: Parenthesis, - stream: TokenStream [ - Ident { - ident: "innermost", - span: $DIR/inner-attrs.rs:52:49: 52:58 (#0), - }, - ], - span: $DIR/inner-attrs.rs:52:48: 52:59 (#0), - }, - ], - span: $DIR/inner-attrs.rs:52:24: 52:60 (#0), - }, - ], - span: $DIR/inner-attrs.rs:52:15: 52:61 (#0), - }, - Literal { - kind: Integer, - symbol: "5", - suffix: None, - span: $DIR/inner-attrs.rs:53:13: 53:14 (#0), - }, ], - span: $DIR/inner-attrs.rs:51:15: 54:10 (#0), + span: $DIR/inner-attrs.rs:50:15: 53:10 (#0), }, ], - span: $DIR/inner-attrs.rs:50:43: 55:6 (#0), + span: $DIR/inner-attrs.rs:49:43: 54:6 (#0), }, Punct { ch: ';', spacing: Alone, - span: $DIR/inner-attrs.rs:55:6: 55:7 (#0), + span: $DIR/inner-attrs.rs:54:6: 54:7 (#0), }, ] PRINT-ATTR_ARGS INPUT (DISPLAY): tuple_attrs PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [ Ident { ident: "tuple_attrs", - span: $DIR/inner-attrs.rs:57:29: 57:40 (#0), + span: $DIR/inner-attrs.rs:56:29: 56:40 (#0), }, ] PRINT-ATTR INPUT (DISPLAY): (3, 4, { #![cfg_attr(not(FALSE), rustc_dummy(innermost))] 5 }); @@ -839,23 +839,23 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ kind: Integer, symbol: "3", suffix: None, - span: $DIR/inner-attrs.rs:58:9: 58:10 (#0), + span: $DIR/inner-attrs.rs:57:9: 57:10 (#0), }, Punct { ch: ',', spacing: Alone, - span: $DIR/inner-attrs.rs:58:10: 58:11 (#0), + span: $DIR/inner-attrs.rs:57:10: 57:11 (#0), }, Literal { kind: Integer, symbol: "4", suffix: None, - span: $DIR/inner-attrs.rs:58:12: 58:13 (#0), + span: $DIR/inner-attrs.rs:57:12: 57:13 (#0), }, Punct { ch: ',', spacing: Alone, - span: $DIR/inner-attrs.rs:58:13: 58:14 (#0), + span: $DIR/inner-attrs.rs:57:13: 57:14 (#0), }, Group { delimiter: Brace, @@ -863,105 +863,105 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ Punct { ch: '#', spacing: Joint, - span: $DIR/inner-attrs.rs:59:13: 59:14 (#0), + span: $DIR/inner-attrs.rs:58:13: 58:14 (#0), }, Punct { ch: '!', spacing: Alone, - span: $DIR/inner-attrs.rs:59:14: 59:15 (#0), + span: $DIR/inner-attrs.rs:58:14: 58:15 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "cfg_attr", - span: $DIR/inner-attrs.rs:59:16: 59:24 (#0), + span: $DIR/inner-attrs.rs:58:16: 58:24 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "not", - span: $DIR/inner-attrs.rs:59:25: 59:28 (#0), + span: $DIR/inner-attrs.rs:58:25: 58:28 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "FALSE", - span: $DIR/inner-attrs.rs:59:29: 59:34 (#0), + span: $DIR/inner-attrs.rs:58:29: 58:34 (#0), }, ], - span: $DIR/inner-attrs.rs:59:28: 59:35 (#0), + span: $DIR/inner-attrs.rs:58:28: 58:35 (#0), }, Punct { ch: ',', spacing: Alone, - span: $DIR/inner-attrs.rs:59:35: 59:36 (#0), + span: $DIR/inner-attrs.rs:58:35: 58:36 (#0), }, Ident { ident: "rustc_dummy", - span: $DIR/inner-attrs.rs:59:37: 59:48 (#0), + span: $DIR/inner-attrs.rs:58:37: 58:48 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "innermost", - span: $DIR/inner-attrs.rs:59:49: 59:58 (#0), + span: $DIR/inner-attrs.rs:58:49: 58:58 (#0), }, ], - span: $DIR/inner-attrs.rs:59:48: 59:59 (#0), + span: $DIR/inner-attrs.rs:58:48: 58:59 (#0), }, ], - span: $DIR/inner-attrs.rs:59:24: 59:60 (#0), + span: $DIR/inner-attrs.rs:58:24: 58:60 (#0), }, ], - span: $DIR/inner-attrs.rs:59:15: 59:61 (#0), + span: $DIR/inner-attrs.rs:58:15: 58:61 (#0), }, Literal { kind: Integer, symbol: "5", suffix: None, - span: $DIR/inner-attrs.rs:60:13: 60:14 (#0), + span: $DIR/inner-attrs.rs:59:13: 59:14 (#0), }, ], - span: $DIR/inner-attrs.rs:58:15: 61:10 (#0), + span: $DIR/inner-attrs.rs:57:15: 60:10 (#0), }, ], - span: $DIR/inner-attrs.rs:57:43: 62:6 (#0), + span: $DIR/inner-attrs.rs:56:43: 61:6 (#0), }, Punct { ch: ';', spacing: Alone, - span: $DIR/inner-attrs.rs:62:6: 62:7 (#0), + span: $DIR/inner-attrs.rs:61:6: 61:7 (#0), }, ] PRINT-ATTR_ARGS INPUT (DISPLAY): tenth PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [ Ident { ident: "tenth", - span: $DIR/inner-attrs.rs:84:42: 84:47 (#0), + span: $DIR/inner-attrs.rs:87:42: 87:47 (#0), }, ] PRINT-ATTR INPUT (DISPLAY): fn weird_extern() {} PRINT-ATTR INPUT (DEBUG): TokenStream [ Ident { ident: "fn", - span: $DIR/inner-attrs.rs:83:5: 83:7 (#0), + span: $DIR/inner-attrs.rs:86:5: 86:7 (#0), }, Ident { ident: "weird_extern", - span: $DIR/inner-attrs.rs:83:8: 83:20 (#0), + span: $DIR/inner-attrs.rs:86:8: 86:20 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [], - span: $DIR/inner-attrs.rs:83:20: 83:22 (#0), + span: $DIR/inner-attrs.rs:86:20: 86:22 (#0), }, Group { delimiter: Brace, stream: TokenStream [], - span: $DIR/inner-attrs.rs:83:23: 85:6 (#0), + span: $DIR/inner-attrs.rs:86:23: 88:6 (#0), }, ] diff --git a/tests/ui/proc-macro/issue-50493.rs b/tests/ui/proc-macro/issue-50493.rs index e23f1f7c7d87..4a88eee21852 100644 --- a/tests/ui/proc-macro/issue-50493.rs +++ b/tests/ui/proc-macro/issue-50493.rs @@ -5,7 +5,7 @@ extern crate issue_50493; #[derive(Derive)] struct Restricted { - pub(in restricted) field: usize, //~ visibilities can only be restricted to ancestor modules + pub(in restricted) field: usize, //~ ERROR visibilities can only be restricted to ancestor modules } mod restricted {} diff --git a/tests/ui/proc-macro/issue-75930-derive-cfg.rs b/tests/ui/proc-macro/issue-75930-derive-cfg.rs index 376a8ea42783..f0851b31e9cb 100644 --- a/tests/ui/proc-macro/issue-75930-derive-cfg.rs +++ b/tests/ui/proc-macro/issue-75930-derive-cfg.rs @@ -31,7 +31,7 @@ extern crate test_macros; // // It is because of this code from below: // ``` -// struct Foo<#[cfg(FALSE)] A, B> +// struct Foo<#[cfg(false)] A, B> // ``` // When the token stream is formed during parsing, `<` is followed immediately // by `#`, which is punctuation, so it is marked `Joint`. But before being @@ -51,22 +51,22 @@ extern crate test_macros; #[print_attr] #[derive(Print)] #[print_helper(b)] -struct Foo<#[cfg(FALSE)] A, B> { - #[cfg(FALSE)] first: String, +struct Foo<#[cfg(false)] A, B> { + #[cfg(false)] first: String, #[cfg_attr(FALSE, deny(warnings))] second: bool, third: [u8; { - #[cfg(FALSE)] struct Bar; + #[cfg(false)] struct Bar; #[cfg(not(FALSE))] struct Inner; - #[cfg(FALSE)] let a = 25; + #[cfg(false)] let a = 25; match true { - #[cfg(FALSE)] true => {}, + #[cfg(false)] true => {}, #[cfg_attr(not(FALSE), allow(warnings))] false => {}, _ => {} }; #[print_helper(should_be_removed)] fn removed_fn() { - #![cfg(FALSE)] + #![cfg(false)] } #[print_helper(c)] #[cfg(not(FALSE))] fn kept_fn() { @@ -76,22 +76,22 @@ struct Foo<#[cfg(FALSE)] A, B> { enum TupleEnum { Foo( - #[cfg(FALSE)] u8, - #[cfg(FALSE)] bool, + #[cfg(false)] u8, + #[cfg(false)] bool, #[cfg(not(FALSE))] i32, - #[cfg(FALSE)] String, u8 + #[cfg(false)] String, u8 ) } struct TupleStruct( - #[cfg(FALSE)] String, + #[cfg(false)] String, #[cfg(not(FALSE))] i32, - #[cfg(FALSE)] bool, + #[cfg(false)] bool, u8 ); fn plain_removed_fn() { - #![cfg_attr(not(FALSE), cfg(FALSE))] + #![cfg_attr(not(FALSE), cfg(false))] } 0 diff --git a/tests/ui/proc-macro/issue-75930-derive-cfg.stdout b/tests/ui/proc-macro/issue-75930-derive-cfg.stdout index 4dcf2b717d8a..549621fdca31 100644 --- a/tests/ui/proc-macro/issue-75930-derive-cfg.stdout +++ b/tests/ui/proc-macro/issue-75930-derive-cfg.stdout @@ -1,73 +1,73 @@ PRINT-ATTR INPUT (DISPLAY): #[print_helper(a)] #[allow(dead_code)] #[derive(Print)] #[print_helper(b)] -struct Foo<#[cfg(FALSE)] A, B> +struct Foo<#[cfg(false)] A, B> { - #[cfg(FALSE)] first: String, #[cfg_attr(FALSE, deny(warnings))] second: + #[cfg(false)] first: String, #[cfg_attr(FALSE, deny(warnings))] second: bool, third: [u8; { - #[cfg(FALSE)] struct Bar; #[cfg(not(FALSE))] struct Inner; - #[cfg(FALSE)] let a = 25; match true + #[cfg(false)] struct Bar; #[cfg(not(FALSE))] struct Inner; + #[cfg(false)] let a = 25; match true { - #[cfg(FALSE)] true => {}, #[cfg_attr(not(FALSE), allow(warnings))] + #[cfg(false)] true => {}, #[cfg_attr(not(FALSE), allow(warnings))] false => {}, _ => {} }; #[print_helper(should_be_removed)] fn removed_fn() - { #![cfg(FALSE)] } #[print_helper(c)] #[cfg(not(FALSE))] fn kept_fn() + { #![cfg(false)] } #[print_helper(c)] #[cfg(not(FALSE))] fn kept_fn() { #![cfg(not(FALSE))] let my_val = true; } enum TupleEnum { - Foo(#[cfg(FALSE)] u8, #[cfg(FALSE)] bool, #[cfg(not(FALSE))] i32, - #[cfg(FALSE)] String, u8) + Foo(#[cfg(false)] u8, #[cfg(false)] bool, #[cfg(not(FALSE))] i32, + #[cfg(false)] String, u8) } struct - TupleStruct(#[cfg(FALSE)] String, #[cfg(not(FALSE))] i32, - #[cfg(FALSE)] bool, u8); fn plain_removed_fn() - { #![cfg_attr(not(FALSE), cfg(FALSE))] } 0 + TupleStruct(#[cfg(false)] String, #[cfg(not(FALSE))] i32, + #[cfg(false)] bool, u8); fn plain_removed_fn() + { #![cfg_attr(not(FALSE), cfg(false))] } 0 }], #[print_helper(d)] fourth: B } PRINT-ATTR RE-COLLECTED (DISPLAY): #[print_helper(a)] #[allow(dead_code)] #[derive(Print)] #[print_helper(b)] -struct Foo <#[cfg(FALSE)] A, B > +struct Foo <#[cfg(false)] A, B > { - #[cfg(FALSE)] first: String, #[cfg_attr(FALSE, deny(warnings))] second: + #[cfg(false)] first: String, #[cfg_attr(FALSE, deny(warnings))] second: bool, third: [u8; { - #[cfg(FALSE)] struct Bar; #[cfg(not(FALSE))] struct Inner; - #[cfg(FALSE)] let a = 25; match true + #[cfg(false)] struct Bar; #[cfg(not(FALSE))] struct Inner; + #[cfg(false)] let a = 25; match true { - #[cfg(FALSE)] true => {}, #[cfg_attr(not(FALSE), allow(warnings))] + #[cfg(false)] true => {}, #[cfg_attr(not(FALSE), allow(warnings))] false => {}, _ => {} }; #[print_helper(should_be_removed)] fn removed_fn() - { #![cfg(FALSE)] } #[print_helper(c)] #[cfg(not(FALSE))] fn kept_fn() + { #![cfg(false)] } #[print_helper(c)] #[cfg(not(FALSE))] fn kept_fn() { #![cfg(not(FALSE))] let my_val = true; } enum TupleEnum { - Foo(#[cfg(FALSE)] u8, #[cfg(FALSE)] bool, #[cfg(not(FALSE))] i32, - #[cfg(FALSE)] String, u8) + Foo(#[cfg(false)] u8, #[cfg(false)] bool, #[cfg(not(FALSE))] i32, + #[cfg(false)] String, u8) } struct - TupleStruct(#[cfg(FALSE)] String, #[cfg(not(FALSE))] i32, - #[cfg(FALSE)] bool, u8); fn plain_removed_fn() - { #![cfg_attr(not(FALSE), cfg(FALSE))] } 0 + TupleStruct(#[cfg(false)] String, #[cfg(not(FALSE))] i32, + #[cfg(false)] bool, u8); fn plain_removed_fn() + { #![cfg_attr(not(FALSE), cfg(false))] } 0 }], #[print_helper(d)] fourth: B } PRINT-ATTR DEEP-RE-COLLECTED (DISPLAY): #[print_helper(a)] #[allow(dead_code)] #[derive(Print)] #[print_helper(b)] -struct Foo <#[cfg(FALSE)] A, B > +struct Foo <#[cfg(false)] A, B > { - #[cfg(FALSE)] first : String, #[cfg_attr(FALSE, deny(warnings))] second : + #[cfg(false)] first : String, #[cfg_attr(FALSE, deny(warnings))] second : bool, third : [u8; { - #[cfg(FALSE)] struct Bar; #[cfg(not(FALSE))] struct Inner; - #[cfg(FALSE)] let a = 25; match true + #[cfg(false)] struct Bar; #[cfg(not(FALSE))] struct Inner; + #[cfg(false)] let a = 25; match true { - #[cfg(FALSE)] true => {}, #[cfg_attr(not(FALSE), allow(warnings))] + #[cfg(false)] true => {}, #[cfg_attr(not(FALSE), allow(warnings))] false => {}, _ => {} }; #[print_helper(should_be_removed)] fn removed_fn() - { #! [cfg(FALSE)] } #[print_helper(c)] #[cfg(not(FALSE))] fn kept_fn() + { #! [cfg(false)] } #[print_helper(c)] #[cfg(not(FALSE))] fn kept_fn() { #! [cfg(not(FALSE))] let my_val = true; } enum TupleEnum { - Foo(#[cfg(FALSE)] u8, #[cfg(FALSE)] bool, #[cfg(not(FALSE))] i32, - #[cfg(FALSE)] String, u8) + Foo(#[cfg(false)] u8, #[cfg(false)] bool, #[cfg(not(FALSE))] i32, + #[cfg(false)] String, u8) } struct - TupleStruct(#[cfg(FALSE)] String, #[cfg(not(FALSE))] i32, - #[cfg(FALSE)] bool, u8); fn plain_removed_fn() - { #! [cfg_attr(not(FALSE), cfg(FALSE))] } 0 + TupleStruct(#[cfg(false)] String, #[cfg(not(FALSE))] i32, + #[cfg(false)] bool, u8); fn plain_removed_fn() + { #! [cfg_attr(not(FALSE), cfg(false))] } 0 }], #[print_helper(d)] fourth : B } PRINT-ATTR INPUT (DEBUG): TokenStream [ @@ -200,7 +200,7 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ delimiter: Parenthesis, stream: TokenStream [ Ident { - ident: "FALSE", + ident: "false", span: $DIR/issue-75930-derive-cfg.rs:54:18: 54:23 (#0), }, ], @@ -246,7 +246,7 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ delimiter: Parenthesis, stream: TokenStream [ Ident { - ident: "FALSE", + ident: "false", span: $DIR/issue-75930-derive-cfg.rs:55:11: 55:16 (#0), }, ], @@ -375,7 +375,7 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ delimiter: Parenthesis, stream: TokenStream [ Ident { - ident: "FALSE", + ident: "false", span: $DIR/issue-75930-derive-cfg.rs:58:15: 58:20 (#0), }, ], @@ -461,7 +461,7 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ delimiter: Parenthesis, stream: TokenStream [ Ident { - ident: "FALSE", + ident: "false", span: $DIR/issue-75930-derive-cfg.rs:60:15: 60:20 (#0), }, ], @@ -521,7 +521,7 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ delimiter: Parenthesis, stream: TokenStream [ Ident { - ident: "FALSE", + ident: "false", span: $DIR/issue-75930-derive-cfg.rs:62:19: 62:24 (#0), }, ], @@ -721,7 +721,7 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ delimiter: Parenthesis, stream: TokenStream [ Ident { - ident: "FALSE", + ident: "false", span: $DIR/issue-75930-derive-cfg.rs:69:20: 69:25 (#0), }, ], @@ -908,7 +908,7 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ delimiter: Parenthesis, stream: TokenStream [ Ident { - ident: "FALSE", + ident: "false", span: $DIR/issue-75930-derive-cfg.rs:79:23: 79:28 (#0), }, ], @@ -942,7 +942,7 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ delimiter: Parenthesis, stream: TokenStream [ Ident { - ident: "FALSE", + ident: "false", span: $DIR/issue-75930-derive-cfg.rs:80:23: 80:28 (#0), }, ], @@ -1020,7 +1020,7 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ delimiter: Parenthesis, stream: TokenStream [ Ident { - ident: "FALSE", + ident: "false", span: $DIR/issue-75930-derive-cfg.rs:82:23: 82:28 (#0), }, ], @@ -1075,7 +1075,7 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ delimiter: Parenthesis, stream: TokenStream [ Ident { - ident: "FALSE", + ident: "false", span: $DIR/issue-75930-derive-cfg.rs:87:19: 87:24 (#0), }, ], @@ -1153,7 +1153,7 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ delimiter: Parenthesis, stream: TokenStream [ Ident { - ident: "FALSE", + ident: "false", span: $DIR/issue-75930-derive-cfg.rs:89:19: 89:24 (#0), }, ], @@ -1246,7 +1246,7 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ delimiter: Parenthesis, stream: TokenStream [ Ident { - ident: "FALSE", + ident: "false", span: $DIR/issue-75930-derive-cfg.rs:94:41: 94:46 (#0), }, ], diff --git a/tests/ui/proc-macro/issue-91800.rs b/tests/ui/proc-macro/issue-91800.rs index bc78bcacfd0f..8cecfad32b55 100644 --- a/tests/ui/proc-macro/issue-91800.rs +++ b/tests/ui/proc-macro/issue-91800.rs @@ -6,11 +6,14 @@ extern crate issue_91800_macro; #[derive(MyTrait)] //~^ ERROR macros that expand to items must be delimited with braces or followed by a semicolon //~| ERROR proc-macro derive produced unparsable tokens +//~| ERROR #[attribute_macro] //~^ ERROR macros that expand to items must be delimited with braces or followed by a semicolon +//~| ERROR struct MyStruct; fn_macro! {} //~^ ERROR macros that expand to items must be delimited with braces or followed by a semicolon +//~| ERROR fn main() {} diff --git a/tests/ui/proc-macro/issue-91800.stderr b/tests/ui/proc-macro/issue-91800.stderr index d831d62e919d..63ebc0a552e3 100644 --- a/tests/ui/proc-macro/issue-91800.stderr +++ b/tests/ui/proc-macro/issue-91800.stderr @@ -21,7 +21,7 @@ LL | #[derive(MyTrait)] = note: this error originates in the derive macro `MyTrait` (in Nightly builds, run with -Z macro-backtrace for more info) error: macros that expand to items must be delimited with braces or followed by a semicolon - --> $DIR/issue-91800.rs:9:1 + --> $DIR/issue-91800.rs:10:1 | LL | #[attribute_macro] | ^^^^^^^^^^^^^^^^^^ @@ -29,7 +29,7 @@ LL | #[attribute_macro] = note: this error originates in the attribute macro `attribute_macro` (in Nightly builds, run with -Z macro-backtrace for more info) error: - --> $DIR/issue-91800.rs:9:1 + --> $DIR/issue-91800.rs:10:1 | LL | #[attribute_macro] | ^^^^^^^^^^^^^^^^^^ @@ -37,7 +37,7 @@ LL | #[attribute_macro] = note: this error originates in the attribute macro `attribute_macro` (in Nightly builds, run with -Z macro-backtrace for more info) error: macros that expand to items must be delimited with braces or followed by a semicolon - --> $DIR/issue-91800.rs:13:1 + --> $DIR/issue-91800.rs:15:1 | LL | fn_macro! {} | ^^^^^^^^^^^^ @@ -45,7 +45,7 @@ LL | fn_macro! {} = note: this error originates in the macro `fn_macro` (in Nightly builds, run with -Z macro-backtrace for more info) error: - --> $DIR/issue-91800.rs:13:1 + --> $DIR/issue-91800.rs:15:1 | LL | fn_macro! {} | ^^^^^^^^^^^^ diff --git a/tests/ui/proc-macro/meta-macro-hygiene.stdout b/tests/ui/proc-macro/meta-macro-hygiene.stdout index 1ee7179e84c0..1734b9afe92e 100644 --- a/tests/ui/proc-macro/meta-macro-hygiene.stdout +++ b/tests/ui/proc-macro/meta-macro-hygiene.stdout @@ -60,11 +60,11 @@ SyntaxContexts: #0: parent: #0, outer_mark: (crate0::{{expn0}}, Opaque) #1: parent: #0, outer_mark: (crate0::{{expn1}}, Opaque) #2: parent: #0, outer_mark: (crate0::{{expn1}}, Transparent) -#3: parent: #0, outer_mark: (crate0::{{expn2}}, SemiTransparent) +#3: parent: #0, outer_mark: (crate0::{{expn2}}, SemiOpaque) #4: parent: #0, outer_mark: (crate0::{{expn3}}, Opaque) #5: parent: #3, outer_mark: (crate0::{{expn3}}, Transparent) -#6: parent: #0, outer_mark: (crate0::{{expn3}}, SemiTransparent) +#6: parent: #0, outer_mark: (crate0::{{expn3}}, SemiOpaque) #7: parent: #0, outer_mark: (crate0::{{expn4}}, Opaque) #8: parent: #4, outer_mark: (crate0::{{expn4}}, Transparent) -#9: parent: #4, outer_mark: (crate0::{{expn4}}, SemiTransparent) +#9: parent: #4, outer_mark: (crate0::{{expn4}}, SemiOpaque) */ diff --git a/tests/ui/proc-macro/module.rs b/tests/ui/proc-macro/module.rs index 210c05988bf2..5878f1b7ddd8 100644 --- a/tests/ui/proc-macro/module.rs +++ b/tests/ui/proc-macro/module.rs @@ -1 +1 @@ -//@ ignore-test (auxiliary, used by other tests) +//@ ignore-auxiliary (used by `./attributes-on-modules-fail.rs`) diff --git a/tests/ui/proc-macro/module_with_attrs.rs b/tests/ui/proc-macro/module_with_attrs.rs index 8a4ca92e44b6..7e4ec978736f 100644 --- a/tests/ui/proc-macro/module_with_attrs.rs +++ b/tests/ui/proc-macro/module_with_attrs.rs @@ -1,4 +1,4 @@ -//@ ignore-test (auxiliary, used by other tests) +//@ ignore-auxiliary (used by `../inner-attr-non-inline-mod.rs`) #![rustfmt::skip] #![print_attr] diff --git a/tests/ui/proc-macro/nested-derive-cfg.rs b/tests/ui/proc-macro/nested-derive-cfg.rs index bd8f231ac2c2..b3dcfb7c3966 100644 --- a/tests/ui/proc-macro/nested-derive-cfg.rs +++ b/tests/ui/proc-macro/nested-derive-cfg.rs @@ -10,10 +10,10 @@ extern crate test_macros; #[derive(Print)] struct Foo { - #[cfg(FALSE)] removed: bool, + #[cfg(false)] removed: bool, my_array: [bool; { struct Inner { - #[cfg(FALSE)] removed_inner_field: u8, + #[cfg(false)] removed_inner_field: u8, non_removed_inner_field: usize } 0 diff --git a/tests/ui/proc-macro/nonterminal-token-hygiene.rs b/tests/ui/proc-macro/nonterminal-token-hygiene.rs index e2aedb245d07..b7b0d1ea3dd7 100644 --- a/tests/ui/proc-macro/nonterminal-token-hygiene.rs +++ b/tests/ui/proc-macro/nonterminal-token-hygiene.rs @@ -8,6 +8,7 @@ //@ normalize-stdout: "expn\d{3,}" -> "expnNNN" //@ normalize-stdout: "extern crate compiler_builtins /\* \d+ \*/" -> "extern crate compiler_builtins /* NNN */" //@ proc-macro: test-macros.rs +//@ edition: 2015 #![feature(decl_macro)] #![no_std] // Don't load unnecessary hygiene information from std diff --git a/tests/ui/proc-macro/nonterminal-token-hygiene.stdout b/tests/ui/proc-macro/nonterminal-token-hygiene.stdout index 6fd6cb474693..42257312a872 100644 --- a/tests/ui/proc-macro/nonterminal-token-hygiene.stdout +++ b/tests/ui/proc-macro/nonterminal-token-hygiene.stdout @@ -5,19 +5,19 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ stream: TokenStream [ Ident { ident: "struct", - span: $DIR/nonterminal-token-hygiene.rs:32:5: 32:11 (#5), + span: $DIR/nonterminal-token-hygiene.rs:33:5: 33:11 (#5), }, Ident { ident: "S", - span: $DIR/nonterminal-token-hygiene.rs:32:12: 32:13 (#5), + span: $DIR/nonterminal-token-hygiene.rs:33:12: 33:13 (#5), }, Punct { ch: ';', spacing: Alone, - span: $DIR/nonterminal-token-hygiene.rs:32:13: 32:14 (#5), + span: $DIR/nonterminal-token-hygiene.rs:33:13: 33:14 (#5), }, ], - span: $DIR/nonterminal-token-hygiene.rs:22:27: 22:32 (#4), + span: $DIR/nonterminal-token-hygiene.rs:23:27: 23:32 (#4), }, ] #![feature /* 0#0 */(prelude_import)] @@ -32,6 +32,7 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ //@ normalize-stdout: "expn\d{3,}" -> "expnNNN" //@ normalize-stdout: "extern crate compiler_builtins /\* \d+ \*/" -> "extern crate compiler_builtins /* NNN */" //@ proc-macro: test-macros.rs +//@ edition: 2015 #![feature /* 0#0 */(decl_macro)] #![no_std /* 0#0 */] @@ -82,10 +83,10 @@ SyntaxContexts: #0: parent: #0, outer_mark: (crate0::{{expn0}}, Opaque) #1: parent: #0, outer_mark: (crate0::{{expn1}}, Opaque) #2: parent: #0, outer_mark: (crate0::{{expn1}}, Transparent) -#3: parent: #0, outer_mark: (crate0::{{expn2}}, SemiTransparent) +#3: parent: #0, outer_mark: (crate0::{{expn2}}, SemiOpaque) #4: parent: #3, outer_mark: (crate0::{{expn3}}, Opaque) #5: parent: #0, outer_mark: (crate0::{{expn3}}, Opaque) #6: parent: #0, outer_mark: (crate0::{{expn4}}, Opaque) #7: parent: #4, outer_mark: (crate0::{{expn4}}, Transparent) -#8: parent: #5, outer_mark: (crate0::{{expn4}}, SemiTransparent) +#8: parent: #5, outer_mark: (crate0::{{expn4}}, SemiOpaque) */ diff --git a/tests/ui/proc-macro/outer/inner.rs b/tests/ui/proc-macro/outer/inner.rs index 210c05988bf2..d0f2087321f4 100644 --- a/tests/ui/proc-macro/outer/inner.rs +++ b/tests/ui/proc-macro/outer/inner.rs @@ -1 +1 @@ -//@ ignore-test (auxiliary, used by other tests) +//@ ignore-auxiliary (used by `../attributes-on-modules-fail.rs`) diff --git a/tests/ui/proc-macro/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs b/tests/ui/proc-macro/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs index f89098f3a5ec..a27176a38e22 100644 --- a/tests/ui/proc-macro/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs +++ b/tests/ui/proc-macro/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs @@ -1,4 +1,4 @@ -//@ ignore-test (auxiliary, used by other tests) +//@ ignore-auxiliary (used by `../../../pretty-print-hack-show.rs`) #[derive(Print)] enum ProceduralMasqueradeDummyType { diff --git a/tests/ui/proc-macro/pretty-print-hack/rental-0.5.5/src/lib.rs b/tests/ui/proc-macro/pretty-print-hack/rental-0.5.5/src/lib.rs index f89098f3a5ec..a27176a38e22 100644 --- a/tests/ui/proc-macro/pretty-print-hack/rental-0.5.5/src/lib.rs +++ b/tests/ui/proc-macro/pretty-print-hack/rental-0.5.5/src/lib.rs @@ -1,4 +1,4 @@ -//@ ignore-test (auxiliary, used by other tests) +//@ ignore-auxiliary (used by `../../../pretty-print-hack-show.rs`) #[derive(Print)] enum ProceduralMasqueradeDummyType { diff --git a/tests/ui/proc-macro/pretty-print-hack/rental-0.5.6/src/lib.rs b/tests/ui/proc-macro/pretty-print-hack/rental-0.5.6/src/lib.rs index f89098f3a5ec..765ee4be656e 100644 --- a/tests/ui/proc-macro/pretty-print-hack/rental-0.5.6/src/lib.rs +++ b/tests/ui/proc-macro/pretty-print-hack/rental-0.5.6/src/lib.rs @@ -1,4 +1,4 @@ -//@ ignore-test (auxiliary, used by other tests) +//@ ignore-auxiliary (used by `../../../pretty-print-hack/hide.rs`) #[derive(Print)] enum ProceduralMasqueradeDummyType { diff --git a/tests/ui/proc-macro/pub-at-crate-root.rs b/tests/ui/proc-macro/pub-at-crate-root.rs index 32e4999a71bc..b8de66967b10 100644 --- a/tests/ui/proc-macro/pub-at-crate-root.rs +++ b/tests/ui/proc-macro/pub-at-crate-root.rs @@ -5,7 +5,7 @@ extern crate proc_macro; -pub mod a { //~ `proc-macro` crate types currently cannot export any items +pub mod a { //~ ERROR `proc-macro` crate types currently cannot export any items use proc_macro::TokenStream; #[proc_macro_derive(B)] diff --git a/tests/ui/proc-macro/quote/debug.rs b/tests/ui/proc-macro/quote/debug.rs index ce113079e567..ce1ef81bedaf 100644 --- a/tests/ui/proc-macro/quote/debug.rs +++ b/tests/ui/proc-macro/quote/debug.rs @@ -3,6 +3,7 @@ //@ no-prefer-dynamic //@ compile-flags: -Z unpretty=expanded //@ needs-unwind compiling proc macros with panic=abort causes a warning +//@ edition: 2015 // // This file is not actually used as a proc-macro - instead, // it's just used to show the output of the `quote!` macro diff --git a/tests/ui/proc-macro/quote/debug.stdout b/tests/ui/proc-macro/quote/debug.stdout index 3eaad9eb9699..6ebb3a379511 100644 --- a/tests/ui/proc-macro/quote/debug.stdout +++ b/tests/ui/proc-macro/quote/debug.stdout @@ -5,6 +5,7 @@ //@ no-prefer-dynamic //@ compile-flags: -Z unpretty=expanded //@ needs-unwind compiling proc macros with panic=abort causes a warning +//@ edition: 2015 // // This file is not actually used as a proc-macro - instead, // it's just used to show the output of the `quote!` macro diff --git a/tests/ui/proc-macro/span-api-tests.rs b/tests/ui/proc-macro/span-api-tests.rs index ac42a7ea611a..792859ed05b1 100644 --- a/tests/ui/proc-macro/span-api-tests.rs +++ b/tests/ui/proc-macro/span-api-tests.rs @@ -8,26 +8,24 @@ extern crate span_test_macros; extern crate span_api_tests; -// FIXME(69775): Investigate `assert_fake_source_file`. - -use span_api_tests::{reemit, assert_source_file, macro_stringify}; +use span_api_tests::{reemit, assert_local_file, macro_stringify}; macro_rules! say_hello { ($macname:ident) => ( $macname! { "Hello, world!" }) } -assert_source_file! { "Hello, world!" } +assert_local_file! { "Hello, world!" } -say_hello! { assert_source_file } +say_hello! { assert_local_file } reemit_legacy! { - assert_source_file! { "Hello, world!" } + assert_local_file! { "Hello, world!" } } -say_hello_extern! { assert_source_file } +say_hello_extern! { assert_local_file } reemit! { - assert_source_file! { "Hello, world!" } + assert_local_file! { "Hello, world!" } } fn main() { diff --git a/tests/ui/process/win-command-curdir-no-verbatim.rs b/tests/ui/process/win-command-curdir-no-verbatim.rs new file mode 100644 index 000000000000..99943e1c8abc --- /dev/null +++ b/tests/ui/process/win-command-curdir-no-verbatim.rs @@ -0,0 +1,36 @@ +// Test that windows verbatim paths in `Command::current_dir` are converted to +// non-verbatim paths before passing to the subprocess. + +//@ run-pass +//@ only-windows +//@ needs-subprocess + +use std::env; +use std::process::Command; + +fn main() { + if env::args().skip(1).any(|s| s == "--child") { + child(); + } else { + parent(); + } +} + +fn parent() { + let exe = env::current_exe().unwrap(); + let dir = env::current_dir().unwrap(); + let status = Command::new(&exe) + .arg("--child") + .current_dir(dir.canonicalize().unwrap()) + .spawn() + .unwrap() + .wait() + .unwrap(); + assert_eq!(status.code(), Some(0)); +} + +fn child() { + let current_dir = env::current_dir().unwrap(); + let current_dir = current_dir.as_os_str().as_encoded_bytes(); + assert!(!current_dir.starts_with(br"\\?\")); +} diff --git a/tests/ui/pub/pub-restricted.rs b/tests/ui/pub/pub-restricted.rs index bcd21082f75c..2aa24121335c 100644 --- a/tests/ui/pub/pub-restricted.rs +++ b/tests/ui/pub/pub-restricted.rs @@ -1,8 +1,8 @@ mod a {} -pub (a) fn afn() {} //~ incorrect visibility restriction -pub (b) fn bfn() {} //~ incorrect visibility restriction -pub (crate::a) fn cfn() {} //~ incorrect visibility restriction +pub (a) fn afn() {} //~ ERROR incorrect visibility restriction +pub (b) fn bfn() {} //~ ERROR incorrect visibility restriction +pub (crate::a) fn cfn() {} //~ ERROR incorrect visibility restriction pub fn privfn() {} mod x { @@ -19,7 +19,7 @@ mod y { pub (super) s: usize, valid_private: usize, pub (in y) valid_in_x: usize, - pub (a) invalid: usize, //~ incorrect visibility restriction + pub (a) invalid: usize, //~ ERROR incorrect visibility restriction pub (in x) non_parent_invalid: usize, //~ ERROR visibilities can only be restricted } } @@ -28,4 +28,4 @@ fn main() {} // test multichar names mod xyz {} -pub (xyz) fn xyz() {} //~ incorrect visibility restriction +pub (xyz) fn xyz() {} //~ ERROR incorrect visibility restriction diff --git a/tests/ui/reachable/unreachable-by-call-arguments-issue-139627.rs b/tests/ui/reachable/unreachable-by-call-arguments-issue-139627.rs new file mode 100644 index 000000000000..b3310ac1c754 --- /dev/null +++ b/tests/ui/reachable/unreachable-by-call-arguments-issue-139627.rs @@ -0,0 +1,16 @@ +//@ check-pass +#![deny(unreachable_code)] +#![deny(unused)] + +pub enum Void {} + +pub struct S(T); + +pub fn foo(void: Void, void1: Void) { + let s = S(void); + drop(s); + let s1 = S { 0: void1 }; + drop(s1); +} + +fn main() {} diff --git a/tests/ui/regions/region-invariant-static-error-reporting.rs b/tests/ui/regions/region-invariant-static-error-reporting.rs index e58eea3f61ae..9792c101fa89 100644 --- a/tests/ui/regions/region-invariant-static-error-reporting.rs +++ b/tests/ui/regions/region-invariant-static-error-reporting.rs @@ -3,7 +3,7 @@ // over time, but this test used to exhibit some pretty bogus messages // that were not remotely helpful. -//@ error-pattern:requires that `'a` must outlive `'static` +//@ dont-require-annotations: NOTE struct Invariant<'a>(Option<&'a mut &'a mut ()>); @@ -14,6 +14,7 @@ fn unify<'a>(x: Option>, f: fn(Invariant<'a>)) { x.unwrap() } else { mk_static() //~ ERROR lifetime may not live long enough + //~| NOTE assignment requires that `'a` must outlive `'static` }; f(bad); } diff --git a/tests/ui/repr/attr-usage-repr.rs b/tests/ui/repr/attr-usage-repr.rs index d8515a12e055..cbf99f16e036 100644 --- a/tests/ui/repr/attr-usage-repr.rs +++ b/tests/ui/repr/attr-usage-repr.rs @@ -45,7 +45,7 @@ enum EInt { B, } -#[repr()] //~ attribute should be applied to a struct, enum, function, associated function, or union [E0517] +#[repr()] //~ ERROR attribute should be applied to a struct, enum, function, associated function, or union [E0517] type SirThisIsAType = i32; #[repr()] diff --git a/tests/ui/resolve/auxiliary/empty.rs b/tests/ui/resolve/auxiliary/empty.rs new file mode 100644 index 000000000000..bd9ec079d80d --- /dev/null +++ b/tests/ui/resolve/auxiliary/empty.rs @@ -0,0 +1 @@ +// Intentionally empty. diff --git a/tests/ui/resolve/crate-called-as-function.rs b/tests/ui/resolve/crate-called-as-function.rs index e8f52c0c029a..30922d923f48 100644 --- a/tests/ui/resolve/crate-called-as-function.rs +++ b/tests/ui/resolve/crate-called-as-function.rs @@ -1,3 +1,3 @@ fn main() { - ::foo() //~ cannot find external crate `foo` in the crate root + ::foo() //~ ERROR cannot find external crate `foo` in the crate root } diff --git a/tests/ui/resolve/dont-compute-arg-names-for-non-fn.rs b/tests/ui/resolve/dont-compute-arg-names-for-non-fn.rs index 20bbbff8fd20..4053ccdfbf14 100644 --- a/tests/ui/resolve/dont-compute-arg-names-for-non-fn.rs +++ b/tests/ui/resolve/dont-compute-arg-names-for-non-fn.rs @@ -3,7 +3,7 @@ extern crate foreign_trait_with_assoc; use foreign_trait_with_assoc::Foo; -// Make sure we don't try to call `fn_arg_names` on a non-fn item. +// Make sure we don't try to call `fn_arg_idents` on a non-fn item. impl Foo for Bar {} //~^ ERROR cannot find type `Bar` in this scope diff --git a/tests/ui/resolve/issue-118295.rs b/tests/ui/resolve/issue-118295.rs index 37a49baee80c..d8c6310300a3 100644 --- a/tests/ui/resolve/issue-118295.rs +++ b/tests/ui/resolve/issue-118295.rs @@ -1,11 +1,11 @@ macro_rules! {} //~^ ERROR cannot find macro `macro_rules` in this scope //~| NOTE maybe you have forgotten to define a name for this `macro_rules!` -//~| put a macro name here +//~| NOTE put a macro name here macro_rules!{} //~^ ERROR cannot find macro `macro_rules` in this scope //~| NOTE maybe you have forgotten to define a name for this `macro_rules!` -//~| put a macro name here +//~| NOTE put a macro name here fn main() {} diff --git a/tests/ui/resolve/prim-crate-partial-res.rs b/tests/ui/resolve/prim-crate-partial-res.rs new file mode 100644 index 000000000000..955f4fa2aee7 --- /dev/null +++ b/tests/ui/resolve/prim-crate-partial-res.rs @@ -0,0 +1,8 @@ +//@ aux-build: empty.rs + +extern crate empty as usize; + +fn foo() -> usize<()> { 0 } +//~^ ERROR type arguments are not allowed on builtin type `usize` + +fn main() {} diff --git a/tests/ui/resolve/prim-crate-partial-res.stderr b/tests/ui/resolve/prim-crate-partial-res.stderr new file mode 100644 index 000000000000..d10d37c9f1b0 --- /dev/null +++ b/tests/ui/resolve/prim-crate-partial-res.stderr @@ -0,0 +1,17 @@ +error[E0109]: type arguments are not allowed on builtin type `usize` + --> $DIR/prim-crate-partial-res.rs:5:19 + | +LL | fn foo() -> usize<()> { 0 } + | ----- ^^ type argument not allowed + | | + | not allowed on builtin type `usize` + | +help: primitive type `usize` doesn't have generic parameters + | +LL - fn foo() -> usize<()> { 0 } +LL + fn foo() -> usize { 0 } + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0109`. diff --git a/tests/ui/resolve/tool-import.rs b/tests/ui/resolve/tool-import.rs index bde375a2c490..951505b92a0b 100644 --- a/tests/ui/resolve/tool-import.rs +++ b/tests/ui/resolve/tool-import.rs @@ -1,7 +1,7 @@ //@ edition: 2018 use clippy::time::Instant; -//~^ `clippy` is a tool module +//~^ ERROR `clippy` is a tool module fn main() { Instant::now(); diff --git a/tests/ui/resolve/typo-suggestion-for-variable-with-name-similar-to-struct-field.rs b/tests/ui/resolve/typo-suggestion-for-variable-with-name-similar-to-struct-field.rs index ecd3f5881190..7216b0294dce 100644 --- a/tests/ui/resolve/typo-suggestion-for-variable-with-name-similar-to-struct-field.rs +++ b/tests/ui/resolve/typo-suggestion-for-variable-with-name-similar-to-struct-field.rs @@ -4,15 +4,15 @@ struct A { impl A { fn new(cofig: String) -> Self { - Self { config } //~ Error cannot find value `config` in this scope + Self { config } //~ ERROR cannot find value `config` in this scope } fn do_something(cofig: String) { - println!("{config}"); //~ Error cannot find value `config` in this scope + println!("{config}"); //~ ERROR cannot find value `config` in this scope } fn self_is_available(self, cofig: String) { - println!("{config}"); //~ Error cannot find value `config` in this scope + println!("{config}"); //~ ERROR cannot find value `config` in this scope } } diff --git a/tests/ui/rfcs/rfc-1937-termination-trait/issue-103052-2.stderr b/tests/ui/rfcs/rfc-1937-termination-trait/issue-103052-2.stderr index f1f53e300abf..400969c279e6 100644 --- a/tests/ui/rfcs/rfc-1937-termination-trait/issue-103052-2.stderr +++ b/tests/ui/rfcs/rfc-1937-termination-trait/issue-103052-2.stderr @@ -4,11 +4,11 @@ error[E0277]: the trait bound `Something: Termination` is not satisfied LL | fn main() -> Something { | ^^^^^^^^^ the trait `Termination` is not implemented for `Something` | -note: required by a bound in `Main::{synthetic#0}` +note: required by a bound in `Main::{anon_assoc#0}` --> $DIR/issue-103052-2.rs:3:27 | LL | fn main() -> impl std::process::Termination; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Main::{synthetic#0}` + | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Main::{anon_assoc#0}` error: aborting due to 1 previous error diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/omitted-patterns.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/omitted-patterns.rs index 5809e56fb7b4..ba800e315b15 100644 --- a/tests/ui/rfcs/rfc-2008-non-exhaustive/omitted-patterns.rs +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/omitted-patterns.rs @@ -63,14 +63,14 @@ fn main() { } match non_enum { - //~^ some variants are not matched explicitly + //~^ ERROR some variants are not matched explicitly NonExhaustiveEnum::Unit => {} NonExhaustiveEnum::Tuple(_) => {} _ => {} } match non_enum { - //~^ some variants are not matched explicitly + //~^ ERROR some variants are not matched explicitly NonExhaustiveEnum::Unit | NonExhaustiveEnum::Struct { .. } => {} _ => {} } @@ -91,7 +91,7 @@ fn main() { _ => {} } match (non_enum, true) { - //~^ some variants are not matched explicitly + //~^ ERROR some variants are not matched explicitly (NonExhaustiveEnum::Unit, true) => {} (NonExhaustiveEnum::Tuple(_), false) => {} _ => {} @@ -104,14 +104,14 @@ fn main() { _ => {} } match (true, non_enum) { - //~^ some variants are not matched explicitly + //~^ ERROR some variants are not matched explicitly (true, NonExhaustiveEnum::Unit) => {} (false, NonExhaustiveEnum::Tuple(_)) => {} _ => {} } match Some(non_enum) { - //~^ some variants are not matched explicitly + //~^ ERROR some variants are not matched explicitly Some(NonExhaustiveEnum::Unit) => {} Some(NonExhaustiveEnum::Tuple(_)) => {} _ => {} @@ -127,7 +127,7 @@ fn main() { } match NestedNonExhaustive::B { - //~^ some variants are not matched explicitly + //~^ ERROR some variants are not matched explicitly NestedNonExhaustive::A(NonExhaustiveEnum::Unit) => {} NestedNonExhaustive::A(_) => {} NestedNonExhaustive::B => {} @@ -138,17 +138,17 @@ fn main() { VariantNonExhaustive::Baz(_, _) => {} VariantNonExhaustive::Bar { x, .. } => {} } - //~^^ some fields are not explicitly listed + //~^^ ERROR some fields are not explicitly listed let FunctionalRecord { first_field, second_field, .. } = FunctionalRecord::default(); - //~^ some fields are not explicitly listed + //~^ ERROR some fields are not explicitly listed // Ok: this is local let Foo { a, b, .. } = Foo::default(); let NestedStruct { bar: NormalStruct { first_field, .. }, .. } = NestedStruct::default(); - //~^ some fields are not explicitly listed - //~^^ some fields are not explicitly listed + //~^ ERROR some fields are not explicitly listed + //~^^ ERROR some fields are not explicitly listed // Ok: this tests https://github.com/rust-lang/rust/issues/89382 let MixedVisFields { a, b, .. } = MixedVisFields::default(); @@ -182,7 +182,7 @@ fn main() { if let NonExhaustiveEnum::Tuple(_) = non_enum {} match UnstableEnum::Stable { - //~^ some variants are not matched explicitly + //~^ ERROR some variants are not matched explicitly UnstableEnum::Stable => {} UnstableEnum::Stable2 => {} _ => {} @@ -204,19 +204,19 @@ fn main() { } match OnlyUnstableEnum::Unstable { - //~^ some variants are not matched explicitly + //~^ ERROR some variants are not matched explicitly OnlyUnstableEnum::Unstable => {} _ => {} } let OnlyUnstableStruct { unstable, .. } = OnlyUnstableStruct::new(); - //~^ some fields are not explicitly listed + //~^ ERROR some fields are not explicitly listed // OK: both unstable fields are matched with feature on let OnlyUnstableStruct { unstable, unstable2, .. } = OnlyUnstableStruct::new(); let UnstableStruct { stable, stable2, .. } = UnstableStruct::default(); - //~^ some fields are not explicitly listed + //~^ ERROR some fields are not explicitly listed // OK: both unstable and stable fields are matched with feature on let UnstableStruct { stable, stable2, unstable, .. } = UnstableStruct::default(); @@ -226,11 +226,11 @@ fn main() { // Ok: missing patterns will be blocked by the pattern being refutable let local_refutable @ NonExhaustiveEnum::Unit = NonExhaustiveEnum::Unit; - //~^ refutable pattern in local binding + //~^ ERROR refutable pattern in local binding // Check that matching on a reference results in a correct diagnostic match &non_enum { - //~^ some variants are not matched explicitly + //~^ ERROR some variants are not matched explicitly //~| pattern `&NonExhaustiveEnum::Struct { .. }` not covered NonExhaustiveEnum::Unit => {} NonExhaustiveEnum::Tuple(_) => {} @@ -238,21 +238,21 @@ fn main() { } match (true, &non_enum) { - //~^ some variants are not matched explicitly + //~^ ERROR some variants are not matched explicitly //~| patterns `(_, &NonExhaustiveEnum::Tuple(_))` and `(_, &NonExhaustiveEnum::Struct { .. })` not covered (true, NonExhaustiveEnum::Unit) => {} _ => {} } match (&non_enum, true) { - //~^ some variants are not matched explicitly + //~^ ERROR some variants are not matched explicitly //~| patterns `(&NonExhaustiveEnum::Tuple(_), _)` and `(&NonExhaustiveEnum::Struct { .. }, _)` not covered (NonExhaustiveEnum::Unit, true) => {} _ => {} } match Some(&non_enum) { - //~^ some variants are not matched explicitly + //~^ ERROR some variants are not matched explicitly //~| pattern `Some(&NonExhaustiveEnum::Struct { .. })` not covered Some(NonExhaustiveEnum::Unit | NonExhaustiveEnum::Tuple(_)) => {} _ => {} diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/stable-omitted-patterns.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/stable-omitted-patterns.rs index 6d3072f3ddd7..6e064251b721 100644 --- a/tests/ui/rfcs/rfc-2008-non-exhaustive/stable-omitted-patterns.rs +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/stable-omitted-patterns.rs @@ -19,7 +19,7 @@ fn main() { #[deny(non_exhaustive_omitted_patterns)] match UnstableEnum::Stable { - //~^ some variants are not matched explicitly + //~^ ERROR some variants are not matched explicitly UnstableEnum::Stable => {} _ => {} } @@ -37,7 +37,7 @@ fn main() { #[warn(non_exhaustive_omitted_patterns)] let UnstableStruct { stable, .. } = UnstableStruct::default(); - //~^ some fields are not explicitly listed + //~^ WARN some fields are not explicitly listed // OK: stable field is matched #[warn(non_exhaustive_omitted_patterns)] diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/regions-enum-not-wf.rs b/tests/ui/rfcs/rfc-2093-infer-outlives/regions-enum-not-wf.rs index 8b491ee4e303..038f53034ab0 100644 --- a/tests/ui/rfcs/rfc-2093-infer-outlives/regions-enum-not-wf.rs +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/regions-enum-not-wf.rs @@ -33,7 +33,7 @@ enum RefIndirect<'a, T> { enum RefDouble<'a, 'b, T> { RefDoubleVariant1(&'a RequireOutlives<'b, T>), - //~^ the parameter type `T` may not live long enough [E0309] + //~^ ERROR the parameter type `T` may not live long enough [E0309] } fn main() {} diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.rs b/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.rs index 110c03d0e549..983fe87451f2 100644 --- a/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.rs +++ b/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.rs @@ -64,7 +64,7 @@ fn _macros() { //~^ ERROR expected expression, found `let` statement //~| ERROR expected expression, found `let` statement match () { - #[cfg(FALSE)] + #[cfg(false)] () if let 0 = 1 => {} //~^ ERROR `if let` guards are experimental _ => {} diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/parens.rs b/tests/ui/rfcs/rfc-2294-if-let-guard/parens.rs index f12824db9c00..0e71a9d24c97 100644 --- a/tests/ui/rfcs/rfc-2294-if-let-guard/parens.rs +++ b/tests/ui/rfcs/rfc-2294-if-let-guard/parens.rs @@ -3,7 +3,7 @@ #![feature(if_let_guard)] #![feature(let_chains)] -#[cfg(FALSE)] +#[cfg(false)] fn un_cfged() { match () { () if let 0 = 1 => {} diff --git a/tests/ui/rfcs/rfc-2457-non-ascii-idents/extern_block_nonascii_forbidden.rs b/tests/ui/rfcs/rfc-2457-non-ascii-idents/extern_block_nonascii_forbidden.rs index ad6825404306..1d064ec54031 100644 --- a/tests/ui/rfcs/rfc-2457-non-ascii-idents/extern_block_nonascii_forbidden.rs +++ b/tests/ui/rfcs/rfc-2457-non-ascii-idents/extern_block_nonascii_forbidden.rs @@ -1,9 +1,9 @@ #![feature(extern_types)] extern "C" { - type 一; //~ items in `extern` blocks cannot use non-ascii identifiers - fn 二(); //~ items in `extern` blocks cannot use non-ascii identifiers - static 三: usize; //~ items in `extern` blocks cannot use non-ascii identifiers + type 一; //~ ERROR items in `extern` blocks cannot use non-ascii identifiers + fn 二(); //~ ERROR items in `extern` blocks cannot use non-ascii identifiers + static 三: usize; //~ ERROR items in `extern` blocks cannot use non-ascii identifiers } fn main() {} diff --git a/tests/ui/rfcs/rfc-2457-non-ascii-idents/mod_file_nonascii_forbidden.rs b/tests/ui/rfcs/rfc-2457-non-ascii-idents/mod_file_nonascii_forbidden.rs index e949e2319c1c..90a7347f6a10 100644 --- a/tests/ui/rfcs/rfc-2457-non-ascii-idents/mod_file_nonascii_forbidden.rs +++ b/tests/ui/rfcs/rfc-2457-non-ascii-idents/mod_file_nonascii_forbidden.rs @@ -1,4 +1,4 @@ -mod řųśť; //~ trying to load file for -//~^ file not found for +mod řųśť; //~ ERROR trying to load file for +//~^ ERROR file not found for fn main() {} diff --git a/tests/ui/rfcs/rfc-2457-non-ascii-idents/no_mangle_nonascii_forbidden.rs b/tests/ui/rfcs/rfc-2457-non-ascii-idents/no_mangle_nonascii_forbidden.rs index f4c126a6e025..dc36c7539e92 100644 --- a/tests/ui/rfcs/rfc-2457-non-ascii-idents/no_mangle_nonascii_forbidden.rs +++ b/tests/ui/rfcs/rfc-2457-non-ascii-idents/no_mangle_nonascii_forbidden.rs @@ -1,11 +1,11 @@ #[no_mangle] -pub fn řųśť() {} //~ `#[no_mangle]` requires ASCII identifier +pub fn řųśť() {} //~ ERROR `#[no_mangle]` requires ASCII identifier pub struct Foo; impl Foo { #[no_mangle] - pub fn řųśť() {} //~ `#[no_mangle]` requires ASCII identifier + pub fn řųśť() {} //~ ERROR `#[no_mangle]` requires ASCII identifier } trait Bar { @@ -14,7 +14,7 @@ trait Bar { impl Bar for Foo { #[no_mangle] - fn řųśť() {} //~ `#[no_mangle]` requires ASCII identifier + fn řųśť() {} //~ ERROR `#[no_mangle]` requires ASCII identifier } fn main() {} diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/ast-pretty-check.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/ast-pretty-check.rs index 8d7826463336..16165c4a42cc 100644 --- a/tests/ui/rfcs/rfc-2497-if-let-chains/ast-pretty-check.rs +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/ast-pretty-check.rs @@ -1,5 +1,6 @@ //@ check-pass //@ compile-flags: -Z unpretty=expanded +//@ edition: 2015 fn main() { if let 0 = 1 {} diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/ast-pretty-check.stdout b/tests/ui/rfcs/rfc-2497-if-let-chains/ast-pretty-check.stdout index 1c103f03c354..e2e45ae94ea6 100644 --- a/tests/ui/rfcs/rfc-2497-if-let-chains/ast-pretty-check.stdout +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/ast-pretty-check.stdout @@ -6,5 +6,6 @@ use ::std::prelude::rust_2015::*; extern crate std; //@ check-pass //@ compile-flags: -Z unpretty=expanded +//@ edition: 2015 fn main() { if let 0 = 1 {} } diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.rs index 99f99c2be72d..0b0abe6ec175 100644 --- a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.rs +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.rs @@ -340,12 +340,12 @@ fn outside_if_and_while_expr() { //~| ERROR expected expression, found `let` statement { - #[cfg(FALSE)] + #[cfg(false)] let x = true && let y = 1; //~^ ERROR expected expression, found `let` statement } - #[cfg(FALSE)] + #[cfg(false)] { [1, 2, 3][let _ = ()] //~^ ERROR expected expression, found `let` statement @@ -436,11 +436,11 @@ fn with_parenthesis() { //[no_feature]~^ ERROR `let` expressions in this position are unstable } - #[cfg(FALSE)] + #[cfg(false)] let x = (true && let y = 1); //~^ ERROR expected expression, found `let` statement - #[cfg(FALSE)] + #[cfg(false)] { ([1, 2, 3][let _ = ()]) //~^ ERROR expected expression, found `let` statement diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.rs index 2087fc42cf10..dad02b7f1063 100644 --- a/tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.rs +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.rs @@ -51,7 +51,7 @@ fn _macros() { while $e {} } } - #[cfg(FALSE)] (let 0 = 1); + #[cfg(false)] (let 0 = 1); //~^ ERROR expected expression, found `let` statement use_expr!(let 0 = 1); //~^ ERROR no rules expected keyword `let` diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.stderr b/tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.stderr index 7c874ae78a8a..b9dac472dca1 100644 --- a/tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.stderr +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.stderr @@ -1,7 +1,7 @@ error: expected expression, found `let` statement --> $DIR/feature-gate.rs:54:20 | -LL | #[cfg(FALSE)] (let 0 = 1); +LL | #[cfg(false)] (let 0 = 1); | ^^^ | = note: only supported directly in conditions of `if` and `while` expressions diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/invalid-let-in-a-valid-let-context.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/invalid-let-in-a-valid-let-context.rs index dce1c19ff339..ae525aed4148 100644 --- a/tests/ui/rfcs/rfc-2497-if-let-chains/invalid-let-in-a-valid-let-context.rs +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/invalid-let-in-a-valid-let-context.rs @@ -3,12 +3,12 @@ fn main() { let _opt = Some(1i32); - #[cfg(FALSE)] + #[cfg(false)] { let _ = &&let Some(x) = Some(42); //~^ ERROR expected expression, found `let` statement } - #[cfg(FALSE)] + #[cfg(false)] { if let Some(elem) = _opt && [1, 2, 3][let _ = &&let Some(x) = Some(42)] = 1 { //~^ ERROR expected expression, found `let` statement @@ -18,7 +18,7 @@ fn main() { } } - #[cfg(FALSE)] + #[cfg(false)] { if let Some(elem) = _opt && { [1, 2, 3][let _ = ()]; @@ -28,7 +28,7 @@ fn main() { } } - #[cfg(FALSE)] + #[cfg(false)] { if let Some(elem) = _opt && [1, 2, 3][let _ = ()] = 1 { //~^ ERROR expected expression, found `let` statement @@ -36,7 +36,7 @@ fn main() { true } } - #[cfg(FALSE)] + #[cfg(false)] { if let a = 1 && { let x = let y = 1; diff --git a/tests/ui/rfcs/rfc-2528-type-changing-struct-update/issue-92010-trait-bound-not-satisfied.rs b/tests/ui/rfcs/rfc-2528-type-changing-struct-update/issue-92010-trait-bound-not-satisfied.rs index f1a54ee5867c..3de88fcaecb6 100644 --- a/tests/ui/rfcs/rfc-2528-type-changing-struct-update/issue-92010-trait-bound-not-satisfied.rs +++ b/tests/ui/rfcs/rfc-2528-type-changing-struct-update/issue-92010-trait-bound-not-satisfied.rs @@ -6,7 +6,7 @@ struct P { impl P { fn y(&self, y: f64) -> Self { P{y, .. self.clone() } } - //~^ mismatched types [E0308] + //~^ ERROR mismatched types [E0308] } fn main() {} diff --git a/tests/ui/rfcs/rfc-2565-param-attrs/attr-without-param.rs b/tests/ui/rfcs/rfc-2565-param-attrs/attr-without-param.rs index eeb2191bab46..c0f17570673c 100644 --- a/tests/ui/rfcs/rfc-2565-param-attrs/attr-without-param.rs +++ b/tests/ui/rfcs/rfc-2565-param-attrs/attr-without-param.rs @@ -1,14 +1,14 @@ -#[cfg(FALSE)] +#[cfg(false)] impl S { fn f(#[attr]) {} //~ ERROR expected parameter name, found `)` } -#[cfg(FALSE)] +#[cfg(false)] impl T for S { fn f(#[attr]) {} //~ ERROR expected parameter name, found `)` } -#[cfg(FALSE)] +#[cfg(false)] trait T { fn f(#[attr]); //~ ERROR expected argument name, found `)` } diff --git a/tests/ui/rfcs/rfc-3467-unsafe-pinned/unsafe-pinned-hides-niche.rs b/tests/ui/rfcs/rfc-3467-unsafe-pinned/unsafe-pinned-hides-niche.rs new file mode 100644 index 000000000000..a1ff9a1f69fd --- /dev/null +++ b/tests/ui/rfcs/rfc-3467-unsafe-pinned/unsafe-pinned-hides-niche.rs @@ -0,0 +1,29 @@ +//@ check-pass +// this test ensures that UnsafePinned hides the niche of its inner type, just like UnsafeCell does + +#![crate_type = "lib"] +#![feature(unsafe_pinned)] + +use std::num::NonZero; +use std::pin::UnsafePinned; + +macro_rules! assert_size_is { + ($ty:ty = $size:expr) => { + const _: () = assert!(size_of::<$ty>() == $size); + }; +} + +assert_size_is!(UnsafePinned<()> = 0); +assert_size_is!(UnsafePinned = 1); + +assert_size_is!( UnsafePinned< u32> = 4); +assert_size_is!( UnsafePinned< NonZero> = 4); +assert_size_is!( UnsafePinned>> = 4); +assert_size_is!(Option> = 8); +assert_size_is!(Option>> = 8); +assert_size_is!(Option>>> = 8); + +assert_size_is!( UnsafePinned< &()> = size_of::()); +assert_size_is!( UnsafePinned> = size_of::()); +assert_size_is!(Option> = size_of::() * 2); +assert_size_is!(Option>> = size_of::() * 2); diff --git a/tests/ui/runtime/backtrace-debuginfo-aux.rs b/tests/ui/runtime/backtrace-debuginfo-aux.rs index 24180ed21966..4493fa51f950 100644 --- a/tests/ui/runtime/backtrace-debuginfo-aux.rs +++ b/tests/ui/runtime/backtrace-debuginfo-aux.rs @@ -1,5 +1,4 @@ -//@ run-pass -//@ ignore-test: not a test, used by backtrace-debuginfo.rs to test file!() +//@ ignore-auxiliary (used by `./backtrace-debuginfo.rs` to test `file!()`) #[inline(never)] pub fn callback(f: F) where F: FnOnce((&'static str, u32)) { diff --git a/tests/ui/rust-2018/edition-lint-nested-paths.fixed b/tests/ui/rust-2018/edition-lint-nested-paths.fixed index 742732ebc494..93ccb2fe6af2 100644 --- a/tests/ui/rust-2018/edition-lint-nested-paths.fixed +++ b/tests/ui/rust-2018/edition-lint-nested-paths.fixed @@ -4,9 +4,9 @@ use crate::foo::{a, b}; //~^ ERROR absolute paths must start with -//~| this is accepted in the current edition +//~| WARN this is accepted in the current edition //~| ERROR absolute paths must start with -//~| this is accepted in the current edition +//~| WARN this is accepted in the current edition mod foo { pub(crate) fn a() {} @@ -21,9 +21,9 @@ fn main() { { use crate::foo::{self as x, c}; //~^ ERROR absolute paths must start with - //~| this is accepted in the current edition + //~| WARN this is accepted in the current edition //~| ERROR absolute paths must start with - //~| this is accepted in the current edition + //~| WARN this is accepted in the current edition x::a(); c(); } diff --git a/tests/ui/rust-2018/edition-lint-nested-paths.rs b/tests/ui/rust-2018/edition-lint-nested-paths.rs index 861ca521bb7b..1c1d21dbab91 100644 --- a/tests/ui/rust-2018/edition-lint-nested-paths.rs +++ b/tests/ui/rust-2018/edition-lint-nested-paths.rs @@ -4,9 +4,9 @@ use foo::{a, b}; //~^ ERROR absolute paths must start with -//~| this is accepted in the current edition +//~| WARN this is accepted in the current edition //~| ERROR absolute paths must start with -//~| this is accepted in the current edition +//~| WARN this is accepted in the current edition mod foo { pub(crate) fn a() {} @@ -21,9 +21,9 @@ fn main() { { use foo::{self as x, c}; //~^ ERROR absolute paths must start with - //~| this is accepted in the current edition + //~| WARN this is accepted in the current edition //~| ERROR absolute paths must start with - //~| this is accepted in the current edition + //~| WARN this is accepted in the current edition x::a(); c(); } diff --git a/tests/ui/rust-2021/future-prelude-collision-generic-trait.fixed b/tests/ui/rust-2021/future-prelude-collision-generic-trait.fixed index ea104011873c..129fdaeaeb23 100644 --- a/tests/ui/rust-2021/future-prelude-collision-generic-trait.fixed +++ b/tests/ui/rust-2021/future-prelude-collision-generic-trait.fixed @@ -23,7 +23,7 @@ where fn try_into(&self) -> Result<&U, i32> { >::try_from(self) //~^ WARNING trait-associated function `try_from` will become ambiguous in Rust 2021 - //~| this is accepted in the current edition (Rust 2018) + //~| WARN this is accepted in the current edition (Rust 2018) } } diff --git a/tests/ui/rust-2021/future-prelude-collision-generic-trait.rs b/tests/ui/rust-2021/future-prelude-collision-generic-trait.rs index ce7dd2fdac76..4e4d5d0d667c 100644 --- a/tests/ui/rust-2021/future-prelude-collision-generic-trait.rs +++ b/tests/ui/rust-2021/future-prelude-collision-generic-trait.rs @@ -23,7 +23,7 @@ where fn try_into(&self) -> Result<&U, i32> { U::try_from(self) //~^ WARNING trait-associated function `try_from` will become ambiguous in Rust 2021 - //~| this is accepted in the current edition (Rust 2018) + //~| WARN this is accepted in the current edition (Rust 2018) } } diff --git a/tests/ui/rust-2021/future-prelude-collision-generic.fixed b/tests/ui/rust-2021/future-prelude-collision-generic.fixed index 3546b1aef6ca..bb852832456a 100644 --- a/tests/ui/rust-2021/future-prelude-collision-generic.fixed +++ b/tests/ui/rust-2021/future-prelude-collision-generic.fixed @@ -27,11 +27,11 @@ impl std::iter::FromIterator for Generic<'static, i32> { fn main() { as MyFromIter>::from_iter(1); //~^ WARNING trait-associated function `from_iter` will become ambiguous in Rust 2021 - //~| this is accepted in the current edition (Rust 2018) + //~| WARN this is accepted in the current edition (Rust 2018) as MyFromIter>::from_iter(1); //~^ WARNING trait-associated function `from_iter` will become ambiguous in Rust 2021 - //~| this is accepted in the current edition (Rust 2018) + //~| WARN this is accepted in the current edition (Rust 2018) as MyFromIter>::from_iter(1); //~^ WARNING trait-associated function `from_iter` will become ambiguous in Rust 2021 - //~| this is accepted in the current edition (Rust 2018) + //~| WARN this is accepted in the current edition (Rust 2018) } diff --git a/tests/ui/rust-2021/future-prelude-collision-generic.rs b/tests/ui/rust-2021/future-prelude-collision-generic.rs index 1ae5e8fce23c..bcaced88763c 100644 --- a/tests/ui/rust-2021/future-prelude-collision-generic.rs +++ b/tests/ui/rust-2021/future-prelude-collision-generic.rs @@ -27,11 +27,11 @@ impl std::iter::FromIterator for Generic<'static, i32> { fn main() { Generic::from_iter(1); //~^ WARNING trait-associated function `from_iter` will become ambiguous in Rust 2021 - //~| this is accepted in the current edition (Rust 2018) + //~| WARN this is accepted in the current edition (Rust 2018) Generic::<'static, i32>::from_iter(1); //~^ WARNING trait-associated function `from_iter` will become ambiguous in Rust 2021 - //~| this is accepted in the current edition (Rust 2018) + //~| WARN this is accepted in the current edition (Rust 2018) Generic::<'_, _>::from_iter(1); //~^ WARNING trait-associated function `from_iter` will become ambiguous in Rust 2021 - //~| this is accepted in the current edition (Rust 2018) + //~| WARN this is accepted in the current edition (Rust 2018) } diff --git a/tests/ui/rust-2024/reserved-guarded-strings.rs b/tests/ui/rust-2024/reserved-guarded-strings.rs index ae68d34cb86e..ae4bd670fcad 100644 --- a/tests/ui/rust-2024/reserved-guarded-strings.rs +++ b/tests/ui/rust-2024/reserved-guarded-strings.rs @@ -46,13 +46,13 @@ fn main() { //~^ ERROR prefix `blah` is unknown //~| ERROR invalid string literal - demo2!(## "foo"); //~ reserved multi-hash token is forbidden - demo3!("foo"###); //~ reserved multi-hash token is forbidden - demo3!(### "foo"); //~ reserved multi-hash token is forbidden - demo3!(## "foo"#); //~ reserved multi-hash token is forbidden + demo2!(## "foo"); //~ ERROR reserved multi-hash token is forbidden + demo3!("foo"###); //~ ERROR reserved multi-hash token is forbidden + demo3!(### "foo"); //~ ERROR reserved multi-hash token is forbidden + demo3!(## "foo"#); //~ ERROR reserved multi-hash token is forbidden demo5!(### "foo"###); - //~^ reserved multi-hash token is forbidden - //~| reserved multi-hash token is forbidden + //~^ ERROR reserved multi-hash token is forbidden + //~| ERROR reserved multi-hash token is forbidden demo1!(#""); //~ ERROR invalid string literal demo1!(#""#); //~ ERROR invalid string literal diff --git a/tests/ui/sanitizer/cfi/assoc-ty-lifetime-issue-123053.rs b/tests/ui/sanitizer/cfi/assoc-ty-lifetime-issue-123053.rs index dd604b6bf7dc..f4f383e008a0 100644 --- a/tests/ui/sanitizer/cfi/assoc-ty-lifetime-issue-123053.rs +++ b/tests/ui/sanitizer/cfi/assoc-ty-lifetime-issue-123053.rs @@ -2,7 +2,8 @@ // trait object type to fail, causing an ICE. // //@ needs-sanitizer-cfi -//@ compile-flags: -Ccodegen-units=1 -Clto -Ctarget-feature=-crt-static -Zsanitizer=cfi --edition=2021 +//@ compile-flags: -Ccodegen-units=1 -Clto -Ctarget-feature=-crt-static -Zsanitizer=cfi +//@ edition: 2021 //@ no-prefer-dynamic //@ only-x86_64-unknown-linux-gnu //@ build-pass diff --git a/tests/ui/sanitizer/cfi/coroutine.rs b/tests/ui/sanitizer/cfi/coroutine.rs index 3ad896afd00b..39a754f10363 100644 --- a/tests/ui/sanitizer/cfi/coroutine.rs +++ b/tests/ui/sanitizer/cfi/coroutine.rs @@ -26,7 +26,7 @@ use std::async_iter::AsyncIterator; #[test] fn general_coroutine() { - let mut coro = #[coroutine] |x: i32| { + let coro = #[coroutine] |x: i32| { yield x; "done" }; diff --git a/tests/ui/sanitizer/issue-111184-cfi-coroutine-witness.rs b/tests/ui/sanitizer/issue-111184-cfi-coroutine-witness.rs index e5b1e0322575..7d0c73c2841e 100644 --- a/tests/ui/sanitizer/issue-111184-cfi-coroutine-witness.rs +++ b/tests/ui/sanitizer/issue-111184-cfi-coroutine-witness.rs @@ -2,7 +2,8 @@ // encode_ty and caused the compiler to ICE. // //@ needs-sanitizer-cfi -//@ compile-flags: -Ccodegen-units=1 -Clto -Ctarget-feature=-crt-static -Zsanitizer=cfi --edition=2021 +//@ compile-flags: -Ccodegen-units=1 -Clto -Ctarget-feature=-crt-static -Zsanitizer=cfi +//@ edition: 2021 //@ no-prefer-dynamic //@ only-x86_64-unknown-linux-gnu //@ build-pass diff --git a/tests/ui/self/arbitrary_self_type_infinite_recursion.rs b/tests/ui/self/arbitrary_self_type_infinite_recursion.rs index 6fbf35c0b867..79ca7079c421 100644 --- a/tests/ui/self/arbitrary_self_type_infinite_recursion.rs +++ b/tests/ui/self/arbitrary_self_type_infinite_recursion.rs @@ -10,15 +10,15 @@ struct Content; impl Content { fn method(self: MySmartPtr) { // note self type - //~^ reached the recursion limit - //~| reached the recursion limit - //~| invalid `self` parameter type + //~^ ERROR reached the recursion limit + //~| ERROR reached the recursion limit + //~| ERROR invalid `self` parameter type } } fn main() { let p = MySmartPtr(Content); p.method(); - //~^ reached the recursion limit - //~| no method named `method` + //~^ ERROR reached the recursion limit + //~| ERROR no method named `method` } diff --git a/tests/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.rs b/tests/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.rs index b5a8992542bf..2fb7aed970e5 100644 --- a/tests/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.rs +++ b/tests/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.rs @@ -6,16 +6,16 @@ struct Foo; impl Foo { async fn a(self: Pin<&Foo>, f: &Foo) -> &Foo { f } - //~^ lifetime may not live long enough + //~^ ERROR lifetime may not live long enough async fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) } - //~^ lifetime may not live long enough + //~^ ERROR lifetime may not live long enough } type Alias = Pin; impl Foo { async fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> &() { arg } - //~^ lifetime may not live long enough + //~^ ERROR lifetime may not live long enough } fn main() {} diff --git a/tests/ui/simd/empty-simd-vector-in-operand.rs b/tests/ui/simd/empty-simd-vector-in-operand.rs index 2a2a6c0737db..813222c8a2ed 100644 --- a/tests/ui/simd/empty-simd-vector-in-operand.rs +++ b/tests/ui/simd/empty-simd-vector-in-operand.rs @@ -10,6 +10,6 @@ struct A(); fn main() { unsafe { std::arch::asm!("{}", in(xmm_reg) A()); - //~^ use of empty SIMD vector `A` + //~^ ERROR use of empty SIMD vector `A` } } diff --git a/tests/ui/simd/intrinsic/generic-elements-pass.rs b/tests/ui/simd/intrinsic/generic-elements-pass.rs index 4dc2e4d5a80a..e4d47cdb3818 100644 --- a/tests/ui/simd/intrinsic/generic-elements-pass.rs +++ b/tests/ui/simd/intrinsic/generic-elements-pass.rs @@ -1,8 +1,10 @@ //@ run-pass -#![feature(repr_simd, core_intrinsics)] +#![feature(repr_simd, intrinsics, core_intrinsics)] -use std::intrinsics::simd::{simd_extract, simd_insert, simd_shuffle}; +use std::intrinsics::simd::{ + simd_extract, simd_extract_dyn, simd_insert, simd_insert_dyn, simd_shuffle, +}; #[repr(simd)] #[derive(Copy, Clone, Debug, PartialEq)] @@ -70,6 +72,41 @@ fn main() { all_eq!(simd_extract(x8, 6), 86); all_eq!(simd_extract(x8, 7), 87); } + unsafe { + all_eq!(simd_insert_dyn(x2, 0, 100), i32x2([100, 21])); + all_eq!(simd_insert_dyn(x2, 1, 100), i32x2([20, 100])); + + all_eq!(simd_insert_dyn(x4, 0, 100), i32x4([100, 41, 42, 43])); + all_eq!(simd_insert_dyn(x4, 1, 100), i32x4([40, 100, 42, 43])); + all_eq!(simd_insert_dyn(x4, 2, 100), i32x4([40, 41, 100, 43])); + all_eq!(simd_insert_dyn(x4, 3, 100), i32x4([40, 41, 42, 100])); + + all_eq!(simd_insert_dyn(x8, 0, 100), i32x8([100, 81, 82, 83, 84, 85, 86, 87])); + all_eq!(simd_insert_dyn(x8, 1, 100), i32x8([80, 100, 82, 83, 84, 85, 86, 87])); + all_eq!(simd_insert_dyn(x8, 2, 100), i32x8([80, 81, 100, 83, 84, 85, 86, 87])); + all_eq!(simd_insert_dyn(x8, 3, 100), i32x8([80, 81, 82, 100, 84, 85, 86, 87])); + all_eq!(simd_insert_dyn(x8, 4, 100), i32x8([80, 81, 82, 83, 100, 85, 86, 87])); + all_eq!(simd_insert_dyn(x8, 5, 100), i32x8([80, 81, 82, 83, 84, 100, 86, 87])); + all_eq!(simd_insert_dyn(x8, 6, 100), i32x8([80, 81, 82, 83, 84, 85, 100, 87])); + all_eq!(simd_insert_dyn(x8, 7, 100), i32x8([80, 81, 82, 83, 84, 85, 86, 100])); + + all_eq!(simd_extract_dyn(x2, 0), 20); + all_eq!(simd_extract_dyn(x2, 1), 21); + + all_eq!(simd_extract_dyn(x4, 0), 40); + all_eq!(simd_extract_dyn(x4, 1), 41); + all_eq!(simd_extract_dyn(x4, 2), 42); + all_eq!(simd_extract_dyn(x4, 3), 43); + + all_eq!(simd_extract_dyn(x8, 0), 80); + all_eq!(simd_extract_dyn(x8, 1), 81); + all_eq!(simd_extract_dyn(x8, 2), 82); + all_eq!(simd_extract_dyn(x8, 3), 83); + all_eq!(simd_extract_dyn(x8, 4), 84); + all_eq!(simd_extract_dyn(x8, 5), 85); + all_eq!(simd_extract_dyn(x8, 6), 86); + all_eq!(simd_extract_dyn(x8, 7), 87); + } let y2 = i32x2([120, 121]); let y4 = i32x4([140, 141, 142, 143]); diff --git a/tests/ui/simd/monomorphize-shuffle-index.rs b/tests/ui/simd/monomorphize-shuffle-index.rs index 3a074dfd432c..a56f2ea14520 100644 --- a/tests/ui/simd/monomorphize-shuffle-index.rs +++ b/tests/ui/simd/monomorphize-shuffle-index.rs @@ -34,7 +34,7 @@ trait Shuffle { return simd_shuffle(a, b, Self::I); #[cfg(generic)] return simd_shuffle_const_generic::<_, _, { &Self::I.0 }>(a, b); - //[generic]~^ overly complex generic constant + //[generic]~^ ERROR overly complex generic constant #[cfg(generic_with_fn)] return simd_shuffle_const_generic::<_, _, { Self::J }>(a, b); } diff --git a/tests/ui/specialization/issue-63716-parse-async.rs b/tests/ui/specialization/issue-63716-parse-async.rs index 3314b4e20f90..00c0b291a1ad 100644 --- a/tests/ui/specialization/issue-63716-parse-async.rs +++ b/tests/ui/specialization/issue-63716-parse-async.rs @@ -8,7 +8,7 @@ fn main() {} -#[cfg(FALSE)] +#[cfg(false)] impl Foo for Bar { default async fn baz() {} } diff --git a/tests/ui/stability-attribute/generics-default-stability.rs b/tests/ui/stability-attribute/generics-default-stability.rs index e1b3971f70c0..400e22a8e6cc 100644 --- a/tests/ui/stability-attribute/generics-default-stability.rs +++ b/tests/ui/stability-attribute/generics-default-stability.rs @@ -69,30 +69,30 @@ fn main() { let _ = STRUCT4; let _: Struct4 = Struct4 { field: 1 }; - //~^ use of deprecated struct `unstable_generic_param::Struct4`: test [deprecated] - //~^^ use of deprecated struct `unstable_generic_param::Struct4`: test [deprecated] - //~^^^ use of deprecated field `unstable_generic_param::Struct4::field`: test [deprecated] + //~^ WARN use of deprecated struct `unstable_generic_param::Struct4`: test [deprecated] + //~^^ WARN use of deprecated struct `unstable_generic_param::Struct4`: test [deprecated] + //~^^^ WARN use of deprecated field `unstable_generic_param::Struct4::field`: test [deprecated] let _ = STRUCT4; - let _: Struct4 = STRUCT4; //~ use of deprecated struct `unstable_generic_param::Struct4`: test [deprecated] - let _: Struct4 = STRUCT4; //~ use of deprecated struct `unstable_generic_param::Struct4`: test [deprecated] + let _: Struct4 = STRUCT4; //~ WARN use of deprecated struct `unstable_generic_param::Struct4`: test [deprecated] + let _: Struct4 = STRUCT4; //~ WARN use of deprecated struct `unstable_generic_param::Struct4`: test [deprecated] let _: Struct4 = Struct4 { field: 0 }; - //~^ use of deprecated struct `unstable_generic_param::Struct4`: test [deprecated] - //~^^ use of deprecated struct `unstable_generic_param::Struct4`: test [deprecated] - //~^^^ use of deprecated field `unstable_generic_param::Struct4::field`: test [deprecated] + //~^ WARN use of deprecated struct `unstable_generic_param::Struct4`: test [deprecated] + //~^^ WARN use of deprecated struct `unstable_generic_param::Struct4`: test [deprecated] + //~^^^ WARN use of deprecated field `unstable_generic_param::Struct4::field`: test [deprecated] let _ = STRUCT5; let _: Struct5 = Struct5 { field: 1 }; //~ ERROR use of unstable library feature `unstable_default` - //~^ use of deprecated struct `unstable_generic_param::Struct5`: test [deprecated] - //~^^ use of deprecated struct `unstable_generic_param::Struct5`: test [deprecated] - //~^^^ use of deprecated field `unstable_generic_param::Struct5::field`: test [deprecated] + //~^ WARN use of deprecated struct `unstable_generic_param::Struct5`: test [deprecated] + //~^^ WARN use of deprecated struct `unstable_generic_param::Struct5`: test [deprecated] + //~^^^ WARN use of deprecated field `unstable_generic_param::Struct5::field`: test [deprecated] let _ = STRUCT5; - let _: Struct5 = STRUCT5; //~ use of deprecated struct `unstable_generic_param::Struct5`: test [deprecated] + let _: Struct5 = STRUCT5; //~ WARN use of deprecated struct `unstable_generic_param::Struct5`: test [deprecated] let _: Struct5 = STRUCT5; //~ ERROR use of unstable library feature `unstable_default` - //~^ use of deprecated struct `unstable_generic_param::Struct5`: test [deprecated] + //~^ WARN use of deprecated struct `unstable_generic_param::Struct5`: test [deprecated] let _: Struct5 = Struct5 { field: 0 }; //~ ERROR use of unstable library feature `unstable_default` - //~^ use of deprecated struct `unstable_generic_param::Struct5`: test [deprecated] - //~^^ use of deprecated struct `unstable_generic_param::Struct5`: test [deprecated] - //~^^^ use of deprecated field `unstable_generic_param::Struct5::field`: test [deprecated] + //~^ WARN use of deprecated struct `unstable_generic_param::Struct5`: test [deprecated] + //~^^ WARN use of deprecated struct `unstable_generic_param::Struct5`: test [deprecated] + //~^^^ WARN use of deprecated field `unstable_generic_param::Struct5::field`: test [deprecated] let _: Struct6 = Struct6 { field: 1 }; // ok let _: Struct6 = Struct6 { field: 0 }; // ok @@ -145,26 +145,26 @@ fn main() { let _ = ALIAS4; let _: Alias4 = Alias4::Some(1); - //~^ use of deprecated type alias `unstable_generic_param::Alias4`: test [deprecated] - //~^^ use of deprecated type alias `unstable_generic_param::Alias4`: test [deprecated] + //~^ WARN use of deprecated type alias `unstable_generic_param::Alias4`: test [deprecated] + //~^^ WARN use of deprecated type alias `unstable_generic_param::Alias4`: test [deprecated] let _ = ALIAS4; - let _: Alias4 = ALIAS4; //~ use of deprecated type alias `unstable_generic_param::Alias4`: test [deprecated] - let _: Alias4 = ALIAS4; //~ use of deprecated type alias `unstable_generic_param::Alias4`: test [deprecated] + let _: Alias4 = ALIAS4; //~ WARN use of deprecated type alias `unstable_generic_param::Alias4`: test [deprecated] + let _: Alias4 = ALIAS4; //~ WARN use of deprecated type alias `unstable_generic_param::Alias4`: test [deprecated] let _: Alias4 = Alias4::Some(0); - //~^ use of deprecated type alias `unstable_generic_param::Alias4`: test [deprecated] - //~^^ use of deprecated type alias `unstable_generic_param::Alias4`: test [deprecated] + //~^ WARN use of deprecated type alias `unstable_generic_param::Alias4`: test [deprecated] + //~^^ WARN use of deprecated type alias `unstable_generic_param::Alias4`: test [deprecated] let _ = ALIAS5; let _: Alias5 = Alias5::Some(1); //~ ERROR use of unstable library feature `unstable_default` - //~^ use of deprecated type alias `unstable_generic_param::Alias5`: test [deprecated] - //~^^ use of deprecated type alias `unstable_generic_param::Alias5`: test [deprecated] + //~^ WARN use of deprecated type alias `unstable_generic_param::Alias5`: test [deprecated] + //~^^ WARN use of deprecated type alias `unstable_generic_param::Alias5`: test [deprecated] let _ = ALIAS5; - let _: Alias5 = ALIAS5; //~ use of deprecated type alias `unstable_generic_param::Alias5`: test [deprecated] + let _: Alias5 = ALIAS5; //~ WARN use of deprecated type alias `unstable_generic_param::Alias5`: test [deprecated] let _: Alias5 = ALIAS5; //~ ERROR use of unstable library feature `unstable_default` - //~^ use of deprecated type alias `unstable_generic_param::Alias5`: test [deprecated] + //~^ WARN use of deprecated type alias `unstable_generic_param::Alias5`: test [deprecated] let _: Alias5 = Alias5::Some(0); //~ ERROR use of unstable library feature `unstable_default` - //~^ use of deprecated type alias `unstable_generic_param::Alias5`: test [deprecated] - //~^^ use of deprecated type alias `unstable_generic_param::Alias5`: test [deprecated] + //~^ WARN use of deprecated type alias `unstable_generic_param::Alias5`: test [deprecated] + //~^^ WARN use of deprecated type alias `unstable_generic_param::Alias5`: test [deprecated] let _: Alias6 = Alias6::Some(1); // ok let _: Alias6 = Alias6::Some(0); // ok @@ -217,26 +217,26 @@ fn main() { let _ = ENUM4; let _: Enum4 = Enum4::Some(1); - //~^ use of deprecated tuple variant `unstable_generic_param::Enum4::Some`: test [deprecated] - //~^^ use of deprecated enum `unstable_generic_param::Enum4`: test [deprecated] + //~^ WARN use of deprecated tuple variant `unstable_generic_param::Enum4::Some`: test [deprecated] + //~^^ WARN use of deprecated enum `unstable_generic_param::Enum4`: test [deprecated] let _ = ENUM4; - let _: Enum4 = ENUM4; //~ use of deprecated enum `unstable_generic_param::Enum4`: test [deprecated] - let _: Enum4 = ENUM4; //~ use of deprecated enum `unstable_generic_param::Enum4`: test [deprecated] + let _: Enum4 = ENUM4; //~ WARN use of deprecated enum `unstable_generic_param::Enum4`: test [deprecated] + let _: Enum4 = ENUM4; //~ WARN use of deprecated enum `unstable_generic_param::Enum4`: test [deprecated] let _: Enum4 = Enum4::Some(0); - //~^ use of deprecated tuple variant `unstable_generic_param::Enum4::Some`: test [deprecated] - //~^^ use of deprecated enum `unstable_generic_param::Enum4`: test [deprecated] + //~^ WARN use of deprecated tuple variant `unstable_generic_param::Enum4::Some`: test [deprecated] + //~^^ WARN use of deprecated enum `unstable_generic_param::Enum4`: test [deprecated] let _ = ENUM5; let _: Enum5 = Enum5::Some(1); //~ ERROR use of unstable library feature `unstable_default` - //~^ use of deprecated tuple variant `unstable_generic_param::Enum5::Some`: test [deprecated] - //~^^ use of deprecated enum `unstable_generic_param::Enum5`: test [deprecated] + //~^ WARN use of deprecated tuple variant `unstable_generic_param::Enum5::Some`: test [deprecated] + //~^^ WARN use of deprecated enum `unstable_generic_param::Enum5`: test [deprecated] let _ = ENUM5; - let _: Enum5 = ENUM5; //~ use of deprecated enum `unstable_generic_param::Enum5`: test [deprecated] + let _: Enum5 = ENUM5; //~ WARN use of deprecated enum `unstable_generic_param::Enum5`: test [deprecated] let _: Enum5 = ENUM5; //~ ERROR use of unstable library feature `unstable_default` - //~^ use of deprecated enum `unstable_generic_param::Enum5`: test [deprecated] + //~^ WARN use of deprecated enum `unstable_generic_param::Enum5`: test [deprecated] let _: Enum5 = Enum5::Some(0); //~ ERROR use of unstable library feature `unstable_default` - //~^ use of deprecated tuple variant `unstable_generic_param::Enum5::Some`: test [deprecated] - //~^^ use of deprecated enum `unstable_generic_param::Enum5`: test [deprecated] + //~^ WARN use of deprecated tuple variant `unstable_generic_param::Enum5::Some`: test [deprecated] + //~^^ WARN use of deprecated enum `unstable_generic_param::Enum5`: test [deprecated] let _: Enum6 = Enum6::Some(1); // ok let _: Enum6 = Enum6::Some(0); // ok diff --git a/tests/ui/static/bad-const-type.rs b/tests/ui/static/bad-const-type.rs index 24fd67ecbaac..d4e6352d7c1c 100644 --- a/tests/ui/static/bad-const-type.rs +++ b/tests/ui/static/bad-const-type.rs @@ -1,4 +1,4 @@ static i: String = 10; //~^ ERROR mismatched types -//~| expected `String`, found integer +//~| NOTE expected `String`, found integer fn main() { println!("{}", i); } diff --git a/tests/ui/stats/input-stats.stderr b/tests/ui/stats/input-stats.stderr index 24e389486478..b369af62f876 100644 --- a/tests/ui/stats/input-stats.stderr +++ b/tests/ui/stats/input-stats.stderr @@ -5,25 +5,25 @@ ast-stats-1 Crate 40 ( 0.6%) 1 40 ast-stats-1 GenericArgs 40 ( 0.6%) 1 40 ast-stats-1 - AngleBracketed 40 ( 0.6%) 1 ast-stats-1 ExprField 48 ( 0.7%) 1 48 -ast-stats-1 Attribute 64 ( 1.0%) 2 32 +ast-stats-1 Attribute 64 ( 0.9%) 2 32 ast-stats-1 - DocComment 32 ( 0.5%) 1 ast-stats-1 - Normal 32 ( 0.5%) 1 ast-stats-1 WherePredicate 72 ( 1.1%) 1 72 ast-stats-1 - BoundPredicate 72 ( 1.1%) 1 ast-stats-1 ForeignItem 80 ( 1.2%) 1 80 ast-stats-1 - Fn 80 ( 1.2%) 1 -ast-stats-1 Local 80 ( 1.2%) 1 80 ast-stats-1 Arm 96 ( 1.4%) 2 48 +ast-stats-1 Local 96 ( 1.4%) 1 96 ast-stats-1 FnDecl 120 ( 1.8%) 5 24 ast-stats-1 Param 160 ( 2.4%) 4 40 ast-stats-1 Stmt 160 ( 2.4%) 5 32 ast-stats-1 - Let 32 ( 0.5%) 1 ast-stats-1 - MacCall 32 ( 0.5%) 1 ast-stats-1 - Expr 96 ( 1.4%) 3 -ast-stats-1 Block 192 ( 2.9%) 6 32 +ast-stats-1 Block 192 ( 2.8%) 6 32 ast-stats-1 FieldDef 208 ( 3.1%) 2 104 ast-stats-1 Variant 208 ( 3.1%) 2 104 -ast-stats-1 AssocItem 320 ( 4.8%) 4 80 +ast-stats-1 AssocItem 320 ( 4.7%) 4 80 ast-stats-1 - Fn 160 ( 2.4%) 2 ast-stats-1 - Type 160 ( 2.4%) 2 ast-stats-1 GenericBound 352 ( 5.2%) 4 88 @@ -33,7 +33,7 @@ ast-stats-1 Pat 504 ( 7.5%) 7 72 ast-stats-1 - Struct 72 ( 1.1%) 1 ast-stats-1 - Wild 72 ( 1.1%) 1 ast-stats-1 - Ident 360 ( 5.3%) 5 -ast-stats-1 Expr 576 ( 8.6%) 8 72 +ast-stats-1 Expr 576 ( 8.5%) 8 72 ast-stats-1 - Match 72 ( 1.1%) 1 ast-stats-1 - Path 72 ( 1.1%) 1 ast-stats-1 - Struct 72 ( 1.1%) 1 @@ -41,8 +41,8 @@ ast-stats-1 - Lit 144 ( 2.1%) 2 ast-stats-1 - Block 216 ( 3.2%) 3 ast-stats-1 PathSegment 744 (11.0%) 31 24 ast-stats-1 Ty 896 (13.3%) 14 64 -ast-stats-1 - Ptr 64 ( 1.0%) 1 -ast-stats-1 - Ref 64 ( 1.0%) 1 +ast-stats-1 - Ptr 64 ( 0.9%) 1 +ast-stats-1 - Ref 64 ( 0.9%) 1 ast-stats-1 - ImplicitSelf 128 ( 1.9%) 2 ast-stats-1 - Path 640 ( 9.5%) 10 ast-stats-1 Item 1_296 (19.2%) 9 144 @@ -53,7 +53,7 @@ ast-stats-1 - Trait 144 ( 2.1%) 1 ast-stats-1 - Fn 288 ( 4.3%) 2 ast-stats-1 - Use 432 ( 6.4%) 3 ast-stats-1 ---------------------------------------------------------------- -ast-stats-1 Total 6_736 116 +ast-stats-1 Total 6_752 116 ast-stats-1 ast-stats-2 POST EXPANSION AST STATS ast-stats-2 Name Accumulated Size Count Item Size @@ -66,8 +66,8 @@ ast-stats-2 WherePredicate 72 ( 1.0%) 1 72 ast-stats-2 - BoundPredicate 72 ( 1.0%) 1 ast-stats-2 ForeignItem 80 ( 1.1%) 1 80 ast-stats-2 - Fn 80 ( 1.1%) 1 -ast-stats-2 Local 80 ( 1.1%) 1 80 ast-stats-2 Arm 96 ( 1.3%) 2 48 +ast-stats-2 Local 96 ( 1.3%) 1 96 ast-stats-2 FnDecl 120 ( 1.6%) 5 24 ast-stats-2 InlineAsm 120 ( 1.6%) 1 120 ast-stats-2 Attribute 128 ( 1.7%) 4 32 @@ -84,14 +84,14 @@ ast-stats-2 Variant 208 ( 2.8%) 2 104 ast-stats-2 AssocItem 320 ( 4.3%) 4 80 ast-stats-2 - Fn 160 ( 2.2%) 2 ast-stats-2 - Type 160 ( 2.2%) 2 -ast-stats-2 GenericBound 352 ( 4.8%) 4 88 -ast-stats-2 - Trait 352 ( 4.8%) 4 +ast-stats-2 GenericBound 352 ( 4.7%) 4 88 +ast-stats-2 - Trait 352 ( 4.7%) 4 ast-stats-2 GenericParam 480 ( 6.5%) 5 96 ast-stats-2 Pat 504 ( 6.8%) 7 72 ast-stats-2 - Struct 72 ( 1.0%) 1 ast-stats-2 - Wild 72 ( 1.0%) 1 ast-stats-2 - Ident 360 ( 4.9%) 5 -ast-stats-2 Expr 648 ( 8.8%) 9 72 +ast-stats-2 Expr 648 ( 8.7%) 9 72 ast-stats-2 - InlineAsm 72 ( 1.0%) 1 ast-stats-2 - Match 72 ( 1.0%) 1 ast-stats-2 - Path 72 ( 1.0%) 1 @@ -113,7 +113,7 @@ ast-stats-2 - Trait 144 ( 1.9%) 1 ast-stats-2 - Fn 288 ( 3.9%) 2 ast-stats-2 - Use 576 ( 7.8%) 4 ast-stats-2 ---------------------------------------------------------------- -ast-stats-2 Total 7_400 127 +ast-stats-2 Total 7_416 127 ast-stats-2 hir-stats HIR STATS hir-stats Name Accumulated Size Count Item Size @@ -126,11 +126,11 @@ hir-stats TraitItemRef 56 ( 0.6%) 2 28 hir-stats GenericArg 64 ( 0.7%) 4 16 hir-stats - Type 16 ( 0.2%) 1 hir-stats - Lifetime 48 ( 0.5%) 3 -hir-stats Local 64 ( 0.7%) 1 64 hir-stats Param 64 ( 0.7%) 2 32 hir-stats Body 72 ( 0.8%) 3 24 hir-stats ImplItemRef 72 ( 0.8%) 2 36 hir-stats InlineAsm 72 ( 0.8%) 1 72 +hir-stats Local 72 ( 0.8%) 1 72 hir-stats WherePredicate 72 ( 0.8%) 3 24 hir-stats - BoundPredicate 72 ( 0.8%) 3 hir-stats Arm 80 ( 0.9%) 2 40 @@ -143,8 +143,8 @@ hir-stats Attribute 128 ( 1.4%) 4 32 hir-stats FieldDef 128 ( 1.4%) 2 64 hir-stats GenericArgs 144 ( 1.6%) 3 48 hir-stats Variant 144 ( 1.6%) 2 72 -hir-stats GenericBound 256 ( 2.9%) 4 64 -hir-stats - Trait 256 ( 2.9%) 4 +hir-stats GenericBound 256 ( 2.8%) 4 64 +hir-stats - Trait 256 ( 2.8%) 4 hir-stats Block 288 ( 3.2%) 6 48 hir-stats Pat 360 ( 4.0%) 5 72 hir-stats - Struct 72 ( 0.8%) 1 @@ -156,7 +156,7 @@ hir-stats Ty 720 ( 8.0%) 15 48 hir-stats - Ptr 48 ( 0.5%) 1 hir-stats - Ref 48 ( 0.5%) 1 hir-stats - Path 624 ( 6.9%) 13 -hir-stats Expr 768 ( 8.6%) 12 64 +hir-stats Expr 768 ( 8.5%) 12 64 hir-stats - InlineAsm 64 ( 0.7%) 1 hir-stats - Match 64 ( 0.7%) 1 hir-stats - Path 64 ( 0.7%) 1 @@ -174,5 +174,5 @@ hir-stats - Use 352 ( 3.9%) 4 hir-stats Path 1_240 (13.8%) 31 40 hir-stats PathSegment 1_920 (21.4%) 40 48 hir-stats ---------------------------------------------------------------- -hir-stats Total 8_980 180 +hir-stats Total 8_988 180 hir-stats diff --git a/tests/ui/structs/default-field-values/failures.rs b/tests/ui/structs/default-field-values/failures.rs index 1e94eecb4f87..4461302e841d 100644 --- a/tests/ui/structs/default-field-values/failures.rs +++ b/tests/ui/structs/default-field-values/failures.rs @@ -1,4 +1,4 @@ -#![feature(default_field_values)] + #![feature(default_field_values)] #[derive(Debug)] pub struct S; @@ -50,7 +50,8 @@ enum E { fn main () { let _ = Foo { .. }; // ok let _ = Foo::default(); // ok - let _ = Bar { .. }; //~ ERROR mandatory field + let _ = Bar { .. }; //~ ERROR missing field + let _ = Bar { baz: 0, .. }; //~ ERROR missing field let _ = Bar::default(); // silenced let _ = Bar { bar: S, .. }; // ok let _ = Qux::<4> { .. }; diff --git a/tests/ui/structs/default-field-values/failures.stderr b/tests/ui/structs/default-field-values/failures.stderr index 58f7baee4b28..21c9bfb44b43 100644 --- a/tests/ui/structs/default-field-values/failures.stderr +++ b/tests/ui/structs/default-field-values/failures.stderr @@ -27,14 +27,20 @@ LL + #[derive(Default)] LL | pub struct S; | -error: missing mandatory field `bar` - --> $DIR/failures.rs:53:21 +error: missing field `bar` in initializer + --> $DIR/failures.rs:53:19 | LL | let _ = Bar { .. }; - | ^ + | ^ fields that do not have a defaulted value must be provided explicitly + +error: missing field `bar` in initializer + --> $DIR/failures.rs:54:27 + | +LL | let _ = Bar { baz: 0, .. }; + | ^ fields that do not have a defaulted value must be provided explicitly error[E0308]: mismatched types - --> $DIR/failures.rs:57:17 + --> $DIR/failures.rs:58:17 | LL | let _ = Rak(..); | --- ^^ expected `i32`, found `RangeFull` @@ -47,19 +53,19 @@ note: tuple struct defined here LL | pub struct Rak(i32 = 42); | ^^^ help: you might have meant to use `..` to skip providing a value for expected fields, but this is only supported on non-tuple struct literals; it is instead interpreted as a `std::ops::RangeFull` literal - --> $DIR/failures.rs:57:17 + --> $DIR/failures.rs:58:17 | LL | let _ = Rak(..); | ^^ error[E0061]: this struct takes 1 argument but 2 arguments were supplied - --> $DIR/failures.rs:59:13 + --> $DIR/failures.rs:60:13 | LL | let _ = Rak(0, ..); | ^^^ -- unexpected argument #2 of type `RangeFull` | help: you might have meant to use `..` to skip providing a value for expected fields, but this is only supported on non-tuple struct literals; it is instead interpreted as a `std::ops::RangeFull` literal - --> $DIR/failures.rs:59:20 + --> $DIR/failures.rs:60:20 | LL | let _ = Rak(0, ..); | ^^ @@ -75,13 +81,13 @@ LL + let _ = Rak(0); | error[E0061]: this struct takes 1 argument but 2 arguments were supplied - --> $DIR/failures.rs:61:13 + --> $DIR/failures.rs:62:13 | LL | let _ = Rak(.., 0); | ^^^ -- unexpected argument #1 of type `RangeFull` | help: you might have meant to use `..` to skip providing a value for expected fields, but this is only supported on non-tuple struct literals; it is instead interpreted as a `std::ops::RangeFull` literal - --> $DIR/failures.rs:61:17 + --> $DIR/failures.rs:62:17 | LL | let _ = Rak(.., 0); | ^^ @@ -96,7 +102,7 @@ LL - let _ = Rak(.., 0); LL + let _ = Rak(0); | -error: aborting due to 7 previous errors +error: aborting due to 8 previous errors Some errors have detailed explanations: E0061, E0277, E0308. For more information about an error, try `rustc --explain E0061`. diff --git a/tests/ui/structs/struct-missing-comma.fixed b/tests/ui/structs/struct-missing-comma.fixed index 800128f503bd..cd02f61f1a46 100644 --- a/tests/ui/structs/struct-missing-comma.fixed +++ b/tests/ui/structs/struct-missing-comma.fixed @@ -2,7 +2,7 @@ //@ run-rustfix pub struct S { - pub foo: u32, //~ expected `,`, or `}`, found keyword `pub` + pub foo: u32, //~ ERROR expected `,`, or `}`, found keyword `pub` // ~^ HELP try adding a comma: ',' pub bar: u32 } diff --git a/tests/ui/structs/struct-missing-comma.rs b/tests/ui/structs/struct-missing-comma.rs index b9d8c9eb3034..84944519fba9 100644 --- a/tests/ui/structs/struct-missing-comma.rs +++ b/tests/ui/structs/struct-missing-comma.rs @@ -2,7 +2,7 @@ //@ run-rustfix pub struct S { - pub foo: u32 //~ expected `,`, or `}`, found keyword `pub` + pub foo: u32 //~ ERROR expected `,`, or `}`, found keyword `pub` // ~^ HELP try adding a comma: ',' pub bar: u32 } diff --git a/tests/ui/structs/suggest-replacing-field-when-specifying-same-type.rs b/tests/ui/structs/suggest-replacing-field-when-specifying-same-type.rs index dd2fe79731ea..ab5815e23a61 100644 --- a/tests/ui/structs/suggest-replacing-field-when-specifying-same-type.rs +++ b/tests/ui/structs/suggest-replacing-field-when-specifying-same-type.rs @@ -22,7 +22,7 @@ fn main() { //~| ERROR pattern does not mention field `b` [E0027] Foo::Baz { bb: "" } => (), //~^ ERROR variant `Foo::Baz` does not have a field named `bb` [E0026] - //~| pattern does not mention field `a` [E0027] + //~| ERROR pattern does not mention field `a` [E0027] _ => (), } } diff --git a/tests/ui/suggestions/argument-list-from-path-sep-error-129273.stderr b/tests/ui/suggestions/argument-list-from-path-sep-error-129273.stderr index 92947e3b177f..713b071a625a 100644 --- a/tests/ui/suggestions/argument-list-from-path-sep-error-129273.stderr +++ b/tests/ui/suggestions/argument-list-from-path-sep-error-129273.stderr @@ -4,7 +4,6 @@ error: path separator must be a double colon LL | fn fmt(&self, f: &mut fmt:Formatter) -> fmt::Result { | ^ | - = note: if you meant to annotate an expression with a type, the type ascription syntax has been removed, see issue #101728 help: use a double colon instead | LL | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { diff --git a/tests/ui/suggestions/const-no-type.rs b/tests/ui/suggestions/const-no-type.rs index c6fdcdadbeaf..b72ace95213c 100644 --- a/tests/ui/suggestions/const-no-type.rs +++ b/tests/ui/suggestions/const-no-type.rs @@ -10,19 +10,19 @@ fn main() {} // These will not reach typeck: -#[cfg(FALSE)] +#[cfg(false)] const C2 = 42; //~^ ERROR missing type for `const` item //~| HELP provide a type for the item //~| SUGGESTION : -#[cfg(FALSE)] +#[cfg(false)] static S2 = "abc"; //~^ ERROR missing type for `static` item //~| HELP provide a type for the item //~| SUGGESTION : -#[cfg(FALSE)] +#[cfg(false)] static mut SM2 = "abc"; //~^ ERROR missing type for `static mut` item //~| HELP provide a type for the item diff --git a/tests/ui/suggestions/derive-trait-for-method-call.rs b/tests/ui/suggestions/derive-trait-for-method-call.rs index b5ce0078c9bc..beac24148428 100644 --- a/tests/ui/suggestions/derive-trait-for-method-call.rs +++ b/tests/ui/suggestions/derive-trait-for-method-call.rs @@ -26,19 +26,19 @@ impl Foo { fn test1() { let x = Foo(Enum::First, CloneEnum::First); let y = x.test(); - //~^the method `test` exists for struct `Foo`, but its trait bounds were not satisfied [E0599] + //~^ ERROR the method `test` exists for struct `Foo`, but its trait bounds were not satisfied [E0599] } fn test2() { let x = Foo(Struct{}, CloneStruct{}); let y = x.test(); - //~^the method `test` exists for struct `Foo`, but its trait bounds were not satisfied [E0599] + //~^ ERROR the method `test` exists for struct `Foo`, but its trait bounds were not satisfied [E0599] } fn test3() { let x = Foo(Vec::::new(), Instant::now()); let y = x.test(); - //~^the method `test` exists for struct `Foo, Instant>`, but its trait bounds were not satisfied [E0599] + //~^ ERROR the method `test` exists for struct `Foo, Instant>`, but its trait bounds were not satisfied [E0599] } fn main() {} diff --git a/tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021-without-dyn.stderr b/tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021-without-dyn.stderr index 7b0fd9799919..e189012d15c9 100644 --- a/tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021-without-dyn.stderr +++ b/tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021-without-dyn.stderr @@ -26,6 +26,20 @@ help: `A` is dyn-incompatible, use `impl A` to return an opaque type, as long as LL | fn f(a: A) -> impl A; | ++++ +error: associated item referring to unboxed trait object for its own trait + --> $DIR/dyn-incompatible-trait-should-use-self-2021-without-dyn.rs:4:13 + | +LL | trait A: Sized { + | - in this trait +LL | fn f(a: A) -> A; + | ^ ^ + | +help: you might have meant to use `Self` to refer to the implementing type + | +LL - fn f(a: A) -> A; +LL + fn f(a: Self) -> Self; + | + error[E0782]: expected a type, found a trait --> $DIR/dyn-incompatible-trait-should-use-self-2021-without-dyn.rs:10:13 | @@ -54,6 +68,20 @@ help: `B` is dyn-incompatible, use `impl B` to return an opaque type, as long as LL | fn f(b: B) -> impl B; | ++++ +error: associated item referring to unboxed trait object for its own trait + --> $DIR/dyn-incompatible-trait-should-use-self-2021-without-dyn.rs:10:13 + | +LL | trait B { + | - in this trait +LL | fn f(b: B) -> B; + | ^ ^ + | +help: you might have meant to use `Self` to refer to the implementing type + | +LL - fn f(b: B) -> B; +LL + fn f(b: Self) -> Self; + | + error[E0782]: expected a type, found a trait --> $DIR/dyn-incompatible-trait-should-use-self-2021-without-dyn.rs:16:20 | @@ -82,34 +110,6 @@ help: `C` is dyn-incompatible, use `impl C` to return an opaque type, as long as LL | fn f(&self, c: C) -> impl C; | ++++ -error: associated item referring to unboxed trait object for its own trait - --> $DIR/dyn-incompatible-trait-should-use-self-2021-without-dyn.rs:4:13 - | -LL | trait A: Sized { - | - in this trait -LL | fn f(a: A) -> A; - | ^ ^ - | -help: you might have meant to use `Self` to refer to the implementing type - | -LL - fn f(a: A) -> A; -LL + fn f(a: Self) -> Self; - | - -error: associated item referring to unboxed trait object for its own trait - --> $DIR/dyn-incompatible-trait-should-use-self-2021-without-dyn.rs:10:13 - | -LL | trait B { - | - in this trait -LL | fn f(b: B) -> B; - | ^ ^ - | -help: you might have meant to use `Self` to refer to the implementing type - | -LL - fn f(b: B) -> B; -LL + fn f(b: Self) -> Self; - | - error: associated item referring to unboxed trait object for its own trait --> $DIR/dyn-incompatible-trait-should-use-self-2021-without-dyn.rs:16:20 | diff --git a/tests/ui/suggestions/enum-method-probe.fixed b/tests/ui/suggestions/enum-method-probe.fixed index 611be9911d97..e097fa8cc1d8 100644 --- a/tests/ui/suggestions/enum-method-probe.fixed +++ b/tests/ui/suggestions/enum-method-probe.fixed @@ -1,4 +1,4 @@ -//@ compile-flags: --edition=2021 +//@ edition: 2021 //@ run-rustfix #![allow(unused)] diff --git a/tests/ui/suggestions/enum-method-probe.rs b/tests/ui/suggestions/enum-method-probe.rs index e183ebd25f2a..665ee7d0aaad 100644 --- a/tests/ui/suggestions/enum-method-probe.rs +++ b/tests/ui/suggestions/enum-method-probe.rs @@ -1,4 +1,4 @@ -//@ compile-flags: --edition=2021 +//@ edition: 2021 //@ run-rustfix #![allow(unused)] diff --git a/tests/ui/suggestions/field-has-method.rs b/tests/ui/suggestions/field-has-method.rs index 980000151e2f..d28b6ba546c4 100644 --- a/tests/ui/suggestions/field-has-method.rs +++ b/tests/ui/suggestions/field-has-method.rs @@ -17,7 +17,7 @@ struct InferOk { fn foo(i: InferOk) { let k = i.kind(); - //~^ no method named `kind` found for struct `InferOk` in the current scope + //~^ ERROR no method named `kind` found for struct `InferOk` in the current scope } fn main() {} diff --git a/tests/ui/suggestions/inner_type.fixed b/tests/ui/suggestions/inner_type.fixed index cfea66b57ec1..3dc939d6b5c4 100644 --- a/tests/ui/suggestions/inner_type.fixed +++ b/tests/ui/suggestions/inner_type.fixed @@ -1,4 +1,4 @@ -//@ compile-flags: --edition=2021 +//@ edition: 2021 //@ run-rustfix pub struct Struct { diff --git a/tests/ui/suggestions/inner_type.rs b/tests/ui/suggestions/inner_type.rs index 5fedf3f256e3..81a05c253119 100644 --- a/tests/ui/suggestions/inner_type.rs +++ b/tests/ui/suggestions/inner_type.rs @@ -1,4 +1,4 @@ -//@ compile-flags: --edition=2021 +//@ edition: 2021 //@ run-rustfix pub struct Struct { diff --git a/tests/ui/suggestions/issue-101465.rs b/tests/ui/suggestions/issue-101465.rs index 8e42e2c22243..3ec4e8160540 100644 --- a/tests/ui/suggestions/issue-101465.rs +++ b/tests/ui/suggestions/issue-101465.rs @@ -18,7 +18,7 @@ fn foo() -> impl Tr { match true { true => B, false => C, - //~^ `match` arms have incompatible types + //~^ ERROR `match` arms have incompatible types } } diff --git a/tests/ui/suggestions/issue-103646.rs b/tests/ui/suggestions/issue-103646.rs index f679640c5dc9..d8b06d663aff 100644 --- a/tests/ui/suggestions/issue-103646.rs +++ b/tests/ui/suggestions/issue-103646.rs @@ -5,7 +5,7 @@ trait Cat { fn uwu(c: T) { c.nya(); //~^ ERROR no method named `nya` found for type parameter `T` in the current scope - //~| Suggestion T::nya() + //~| SUGGESTION T::nya() } fn main() {} diff --git a/tests/ui/suggestions/issue-116434-2015.stderr b/tests/ui/suggestions/issue-116434-2015.stderr index e7b8cd2f101d..07a254432a28 100644 --- a/tests/ui/suggestions/issue-116434-2015.stderr +++ b/tests/ui/suggestions/issue-116434-2015.stderr @@ -12,19 +12,6 @@ help: if this is a dyn-compatible trait, use `dyn` LL | fn foo() -> dyn Clone; | +++ -warning: trait objects without an explicit `dyn` are deprecated - --> $DIR/issue-116434-2015.rs:18:20 - | -LL | fn handle() -> DbHandle; - | ^^^^^^^^ - | - = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! - = note: for more information, see -help: if this is a dyn-compatible trait, use `dyn` - | -LL | fn handle() -> dyn DbHandle; - | +++ - warning: trait objects without an explicit `dyn` are deprecated --> $DIR/issue-116434-2015.rs:3:17 | @@ -53,6 +40,19 @@ help: there is an associated type with the same name LL | fn foo() -> Self::Clone; | ++++++ +warning: trait objects without an explicit `dyn` are deprecated + --> $DIR/issue-116434-2015.rs:18:20 + | +LL | fn handle() -> DbHandle; + | ^^^^^^^^ + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! + = note: for more information, see +help: if this is a dyn-compatible trait, use `dyn` + | +LL | fn handle() -> dyn DbHandle; + | +++ + warning: trait objects without an explicit `dyn` are deprecated --> $DIR/issue-116434-2015.rs:18:20 | diff --git a/tests/ui/suggestions/issue-81839.rs b/tests/ui/suggestions/issue-81839.rs index 3971aa9fe841..99a03c175b39 100644 --- a/tests/ui/suggestions/issue-81839.rs +++ b/tests/ui/suggestions/issue-81839.rs @@ -8,7 +8,7 @@ async fn test(ans: &str, num: i32, cx: &issue_81839::Test) -> u32 { 1 => { cx.answer_str("hi"); } - _ => cx.answer_str("hi"), //~ `match` arms have incompatible types + _ => cx.answer_str("hi"), //~ ERROR `match` arms have incompatible types } 1 diff --git a/tests/ui/suggestions/issue-86667.rs b/tests/ui/suggestions/issue-86667.rs index 1f37e9a5f6de..cc5b878b6321 100644 --- a/tests/ui/suggestions/issue-86667.rs +++ b/tests/ui/suggestions/issue-86667.rs @@ -1,7 +1,7 @@ // Regression test for #86667, where a garbled suggestion was issued for // a missing named lifetime parameter. -//@ compile-flags: --edition 2018 +//@ edition: 2018 async fn a(s1: &str, s2: &str) -> &str { //~^ ERROR: missing lifetime specifier [E0106] diff --git a/tests/ui/suggestions/many-type-ascription.stderr b/tests/ui/suggestions/many-type-ascription.stderr index feddc7d62a75..47e19c508ef9 100644 --- a/tests/ui/suggestions/many-type-ascription.stderr +++ b/tests/ui/suggestions/many-type-ascription.stderr @@ -3,8 +3,6 @@ error: expected one of `.`, `;`, `?`, `else`, or an operator, found `:` | LL | let _ = 0: i32; | ^ expected one of `.`, `;`, `?`, `else`, or an operator - | - = note: type ascription syntax has been removed, see issue #101728 error: aborting due to 1 previous error diff --git a/tests/ui/suggestions/partialeq_suggest_swap.rs b/tests/ui/suggestions/partialeq_suggest_swap.rs index ee5583a5488e..090f17f2fe2f 100644 --- a/tests/ui/suggestions/partialeq_suggest_swap.rs +++ b/tests/ui/suggestions/partialeq_suggest_swap.rs @@ -7,5 +7,5 @@ impl PartialEq for T { } fn main() { - 4i32 == T(4); //~ mismatched types [E0308] + 4i32 == T(4); //~ ERROR mismatched types [E0308] } diff --git a/tests/ui/suggestions/partialeq_suggest_swap_on_e0277.rs b/tests/ui/suggestions/partialeq_suggest_swap_on_e0277.rs index 2ebbed3c740f..a54493e5922b 100644 --- a/tests/ui/suggestions/partialeq_suggest_swap_on_e0277.rs +++ b/tests/ui/suggestions/partialeq_suggest_swap_on_e0277.rs @@ -7,5 +7,5 @@ impl PartialEq for T { } fn main() { - String::from("Girls Band Cry") == T(String::from("Girls Band Cry")); //~ can't compare `String` with `T` [E0277] + String::from("Girls Band Cry") == T(String::from("Girls Band Cry")); //~ ERROR can't compare `String` with `T` [E0277] } diff --git a/tests/ui/suggestions/struct-field-type-including-single-colon.stderr b/tests/ui/suggestions/struct-field-type-including-single-colon.stderr index ce16aca1e14a..b9302b0453d5 100644 --- a/tests/ui/suggestions/struct-field-type-including-single-colon.stderr +++ b/tests/ui/suggestions/struct-field-type-including-single-colon.stderr @@ -4,7 +4,6 @@ error: path separator must be a double colon LL | a: foo:A, | ^ | - = note: if you meant to annotate an expression with a type, the type ascription syntax has been removed, see issue #101728 help: use a double colon instead | LL | a: foo::A, @@ -16,7 +15,6 @@ error: path separator must be a double colon LL | b: foo::bar:B, | ^ | - = note: if you meant to annotate an expression with a type, the type ascription syntax has been removed, see issue #101728 help: use a double colon instead | LL | b: foo::bar::B, diff --git a/tests/ui/suggestions/suggest-adding-reference-to-trait-assoc-item.fixed b/tests/ui/suggestions/suggest-adding-reference-to-trait-assoc-item.fixed index 3b739312942a..735c09438e2d 100644 --- a/tests/ui/suggestions/suggest-adding-reference-to-trait-assoc-item.fixed +++ b/tests/ui/suggestions/suggest-adding-reference-to-trait-assoc-item.fixed @@ -10,6 +10,6 @@ fn bar(bar: &usize) { } fn main() { - foo(&mut Default::default()); //~ the trait bound `&mut usize: Default` is not satisfied - bar(&Default::default()); //~ the trait bound `&usize: Default` is not satisfied + foo(&mut Default::default()); //~ ERROR the trait bound `&mut usize: Default` is not satisfied + bar(&Default::default()); //~ ERROR the trait bound `&usize: Default` is not satisfied } diff --git a/tests/ui/suggestions/suggest-adding-reference-to-trait-assoc-item.rs b/tests/ui/suggestions/suggest-adding-reference-to-trait-assoc-item.rs index 7fc870946b93..7364c59fd92e 100644 --- a/tests/ui/suggestions/suggest-adding-reference-to-trait-assoc-item.rs +++ b/tests/ui/suggestions/suggest-adding-reference-to-trait-assoc-item.rs @@ -10,6 +10,6 @@ fn bar(bar: &usize) { } fn main() { - foo(Default::default()); //~ the trait bound `&mut usize: Default` is not satisfied - bar(Default::default()); //~ the trait bound `&usize: Default` is not satisfied + foo(Default::default()); //~ ERROR the trait bound `&mut usize: Default` is not satisfied + bar(Default::default()); //~ ERROR the trait bound `&usize: Default` is not satisfied } diff --git a/tests/ui/suggestions/suggest-let-for-assignment.fixed b/tests/ui/suggestions/suggest-let-for-assignment.fixed index 80b9333827ec..6d40f74a0d81 100644 --- a/tests/ui/suggestions/suggest-let-for-assignment.fixed +++ b/tests/ui/suggestions/suggest-let-for-assignment.fixed @@ -7,10 +7,10 @@ fn main() { let x = "x"; //~ ERROR cannot find value `x` in this scope println!("x: {}", x); //~ ERROR cannot find value `x` in this scope - let some_variable = 6; //~ cannot find value `let_some_variable` in this scope + let some_variable = 6; //~ ERROR cannot find value `let_some_variable` in this scope println!("some_variable: {}", some_variable); //~ ERROR cannot find value `some_variable` in this scope - let other_variable = 6; //~ cannot find value `letother_variable` in this scope + let other_variable = 6; //~ ERROR cannot find value `letother_variable` in this scope println!("other_variable: {}", other_variable); //~ ERROR cannot find value `other_variable` in this scope if x == "x" { diff --git a/tests/ui/suggestions/suggest-let-for-assignment.rs b/tests/ui/suggestions/suggest-let-for-assignment.rs index 22560083d34c..aeb22a0ded03 100644 --- a/tests/ui/suggestions/suggest-let-for-assignment.rs +++ b/tests/ui/suggestions/suggest-let-for-assignment.rs @@ -7,10 +7,10 @@ fn main() { x = "x"; //~ ERROR cannot find value `x` in this scope println!("x: {}", x); //~ ERROR cannot find value `x` in this scope - let_some_variable = 6; //~ cannot find value `let_some_variable` in this scope + let_some_variable = 6; //~ ERROR cannot find value `let_some_variable` in this scope println!("some_variable: {}", some_variable); //~ ERROR cannot find value `some_variable` in this scope - letother_variable = 6; //~ cannot find value `letother_variable` in this scope + letother_variable = 6; //~ ERROR cannot find value `letother_variable` in this scope println!("other_variable: {}", other_variable); //~ ERROR cannot find value `other_variable` in this scope if x == "x" { diff --git a/tests/ui/suggestions/suggest-null-ptr.fixed b/tests/ui/suggestions/suggest-null-ptr.fixed index 55c90859c83e..97a628f8662b 100644 --- a/tests/ui/suggestions/suggest-null-ptr.fixed +++ b/tests/ui/suggestions/suggest-null-ptr.fixed @@ -16,16 +16,16 @@ extern "C" { fn main() { unsafe { foo(std::ptr::null()); - //~^ mismatched types [E0308] - //~| if you meant to create a null pointer, use `std::ptr::null()` + //~^ ERROR mismatched types [E0308] + //~| HELP if you meant to create a null pointer, use `std::ptr::null()` foo_mut(std::ptr::null_mut()); - //~^ mismatched types [E0308] - //~| if you meant to create a null pointer, use `std::ptr::null_mut()` + //~^ ERROR mismatched types [E0308] + //~| HELP if you meant to create a null pointer, use `std::ptr::null_mut()` usize(std::ptr::null()); - //~^ mismatched types [E0308] - //~| if you meant to create a null pointer, use `std::ptr::null()` + //~^ ERROR mismatched types [E0308] + //~| HELP if you meant to create a null pointer, use `std::ptr::null()` usize_mut(std::ptr::null_mut()); - //~^ mismatched types [E0308] - //~| if you meant to create a null pointer, use `std::ptr::null_mut()` + //~^ ERROR mismatched types [E0308] + //~| HELP if you meant to create a null pointer, use `std::ptr::null_mut()` } } diff --git a/tests/ui/suggestions/suggest-null-ptr.rs b/tests/ui/suggestions/suggest-null-ptr.rs index f4f1269d512d..46ace90c8aea 100644 --- a/tests/ui/suggestions/suggest-null-ptr.rs +++ b/tests/ui/suggestions/suggest-null-ptr.rs @@ -16,16 +16,16 @@ extern "C" { fn main() { unsafe { foo(0); - //~^ mismatched types [E0308] - //~| if you meant to create a null pointer, use `std::ptr::null()` + //~^ ERROR mismatched types [E0308] + //~| HELP if you meant to create a null pointer, use `std::ptr::null()` foo_mut(0); - //~^ mismatched types [E0308] - //~| if you meant to create a null pointer, use `std::ptr::null_mut()` + //~^ ERROR mismatched types [E0308] + //~| HELP if you meant to create a null pointer, use `std::ptr::null_mut()` usize(0); - //~^ mismatched types [E0308] - //~| if you meant to create a null pointer, use `std::ptr::null()` + //~^ ERROR mismatched types [E0308] + //~| HELP if you meant to create a null pointer, use `std::ptr::null()` usize_mut(0); - //~^ mismatched types [E0308] - //~| if you meant to create a null pointer, use `std::ptr::null_mut()` + //~^ ERROR mismatched types [E0308] + //~| HELP if you meant to create a null pointer, use `std::ptr::null_mut()` } } diff --git a/tests/ui/suggestions/suggest-ref-mut.rs b/tests/ui/suggestions/suggest-ref-mut.rs index 9f5df9303c33..2a933f6305f6 100644 --- a/tests/ui/suggestions/suggest-ref-mut.rs +++ b/tests/ui/suggestions/suggest-ref-mut.rs @@ -1,3 +1,5 @@ +//@ dont-require-annotations: SUGGESTION + struct X(usize); impl X { diff --git a/tests/ui/suggestions/suggest-ref-mut.stderr b/tests/ui/suggestions/suggest-ref-mut.stderr index 935a04c052ac..7c0899f0fbc1 100644 --- a/tests/ui/suggestions/suggest-ref-mut.stderr +++ b/tests/ui/suggestions/suggest-ref-mut.stderr @@ -1,5 +1,5 @@ error[E0594]: cannot assign to `self.0`, which is behind a `&` reference - --> $DIR/suggest-ref-mut.rs:7:9 + --> $DIR/suggest-ref-mut.rs:9:9 | LL | self.0 = 32; | ^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be written @@ -10,7 +10,7 @@ LL | fn zap(&mut self) { | +++ error[E0594]: cannot assign to `*foo`, which is behind a `&` reference - --> $DIR/suggest-ref-mut.rs:15:5 + --> $DIR/suggest-ref-mut.rs:17:5 | LL | *foo = 32; | ^^^^^^^^^ `foo` is a `&` reference, so the data it refers to cannot be written @@ -21,7 +21,7 @@ LL | let ref mut foo = 16; | +++ error[E0594]: cannot assign to `*bar`, which is behind a `&` reference - --> $DIR/suggest-ref-mut.rs:19:9 + --> $DIR/suggest-ref-mut.rs:21:9 | LL | *bar = 32; | ^^^^^^^^^ `bar` is a `&` reference, so the data it refers to cannot be written @@ -32,7 +32,7 @@ LL | if let Some(ref mut bar) = Some(16) { | +++ error[E0594]: cannot assign to `*quo`, which is behind a `&` reference - --> $DIR/suggest-ref-mut.rs:23:22 + --> $DIR/suggest-ref-mut.rs:25:22 | LL | ref quo => { *quo = 32; }, | ^^^^^^^^^ `quo` is a `&` reference, so the data it refers to cannot be written diff --git a/tests/ui/suggestions/type-ascription-and-other-error.rs b/tests/ui/suggestions/type-ascription-and-other-error.rs index 99ab2f3c858b..da985b53aef6 100644 --- a/tests/ui/suggestions/type-ascription-and-other-error.rs +++ b/tests/ui/suggestions/type-ascription-and-other-error.rs @@ -1,6 +1,6 @@ fn main() { not rust; //~ ERROR let _ = 0: i32; // (error hidden by existing error) - #[cfg(FALSE)] + #[cfg(false)] let _ = 0: i32; // (warning hidden by existing error) } diff --git a/tests/ui/suggestions/type-ascription-instead-of-method.stderr b/tests/ui/suggestions/type-ascription-instead-of-method.stderr index 0bef1c185db6..6dc7b5e18ef8 100644 --- a/tests/ui/suggestions/type-ascription-instead-of-method.stderr +++ b/tests/ui/suggestions/type-ascription-instead-of-method.stderr @@ -4,7 +4,6 @@ error: path separator must be a double colon LL | let _ = Box:new("foo".to_string()); | ^ | - = note: if you meant to annotate an expression with a type, the type ascription syntax has been removed, see issue #101728 help: use a double colon instead | LL | let _ = Box::new("foo".to_string()); diff --git a/tests/ui/suggestions/type-ascription-instead-of-path-2.stderr b/tests/ui/suggestions/type-ascription-instead-of-path-2.stderr index 0b37bf9a57bb..79dffc0cf9b0 100644 --- a/tests/ui/suggestions/type-ascription-instead-of-path-2.stderr +++ b/tests/ui/suggestions/type-ascription-instead-of-path-2.stderr @@ -4,7 +4,6 @@ error: expected one of `(`, `.`, `::`, `;`, `?`, `else`, or an operator, found ` LL | let _ = vec![Ok(2)].into_iter().collect:,_>>()?; | ^ expected one of 7 possible tokens | - = note: type ascription syntax has been removed, see issue #101728 help: maybe write a path separator here | LL | let _ = vec![Ok(2)].into_iter().collect::,_>>()?; diff --git a/tests/ui/suggestions/type-ascription-instead-of-path.stderr b/tests/ui/suggestions/type-ascription-instead-of-path.stderr index 8c16acff7994..a8364611b50c 100644 --- a/tests/ui/suggestions/type-ascription-instead-of-path.stderr +++ b/tests/ui/suggestions/type-ascription-instead-of-path.stderr @@ -4,7 +4,6 @@ error: path separator must be a double colon LL | std:io::stdin(); | ^ | - = note: if you meant to annotate an expression with a type, the type ascription syntax has been removed, see issue #101728 help: use a double colon instead | LL | std::io::stdin(); diff --git a/tests/ui/suggestions/type-ascription-instead-of-variant.stderr b/tests/ui/suggestions/type-ascription-instead-of-variant.stderr index f0b31722e40e..e836b37c100d 100644 --- a/tests/ui/suggestions/type-ascription-instead-of-variant.stderr +++ b/tests/ui/suggestions/type-ascription-instead-of-variant.stderr @@ -4,7 +4,6 @@ error: path separator must be a double colon LL | let _ = Option:Some(""); | ^ | - = note: if you meant to annotate an expression with a type, the type ascription syntax has been removed, see issue #101728 help: use a double colon instead | LL | let _ = Option::Some(""); diff --git a/tests/ui/suggestions/types/dont-suggest-path-names.rs b/tests/ui/suggestions/types/dont-suggest-path-names.rs index d160e49cd035..dfd671bfe556 100644 --- a/tests/ui/suggestions/types/dont-suggest-path-names.rs +++ b/tests/ui/suggestions/types/dont-suggest-path-names.rs @@ -5,11 +5,11 @@ struct Select(F, I); fn select(filter: F) -> Select {} -//~^ 7:31: 7:43: mismatched types [E0308] +//~^ ERROR mismatched types [E0308] fn parser1() { let lit = select(|x| match x { - //~^ 11:23: 11:24: type annotations needed [E0282] + //~^ ERROR type annotations needed [E0282] _ => (), }); } diff --git a/tests/ui/super-let.borrowck.stderr b/tests/ui/super-let.borrowck.stderr new file mode 100644 index 000000000000..01ef29d87588 --- /dev/null +++ b/tests/ui/super-let.borrowck.stderr @@ -0,0 +1,174 @@ +error[E0506]: cannot assign to `x` because it is borrowed + --> $DIR/super-let.rs:30:28 + | +LL | super let b = DropMe(&mut x); + | ------ `x` is borrowed here +... +LL | #[cfg(borrowck)] { x = true; } + | ^^^^^^^^ `x` is assigned to here but it was already borrowed +... +LL | } + | - borrow might be used here, when `b` is dropped and runs the `Drop` code for type `DropMe` + +error[E0506]: cannot assign to `x` because it is borrowed + --> $DIR/super-let.rs:46:28 + | +LL | super let b = &DropMe(&mut x); + | -------------- + | | | + | | `x` is borrowed here + | a temporary with access to the borrow is created here ... +... +LL | #[cfg(borrowck)] { x = true; } + | ^^^^^^^^ `x` is assigned to here but it was already borrowed +... +LL | } + | - ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `DropMe` + +error[E0506]: cannot assign to `x` because it is borrowed + --> $DIR/super-let.rs:64:32 + | +LL | super let b = identity(&DropMe(&mut x)); + | -------------- + | | | + | | `x` is borrowed here + | a temporary with access to the borrow is created here ... +LL | #[cfg(borrowck)] { x = true; } + | ^^^^^^^^ `x` is assigned to here but it was already borrowed +... +LL | }; + | - ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `DropMe` + +error[E0506]: cannot assign to `x` because it is borrowed + --> $DIR/super-let.rs:87:36 + | +LL | super let b = identity(&DropMe(&mut x)); + | -------------- + | | | + | | `x` is borrowed here + | a temporary with access to the borrow is created here ... +... +LL | #[cfg(borrowck)] { x = true; } + | ^^^^^^^^ `x` is assigned to here but it was already borrowed +... +LL | )); + | - ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `DropMe` + +error[E0506]: cannot assign to `x` because it is borrowed + --> $DIR/super-let.rs:107:28 + | +LL | super let b = DropMe(&mut x); + | ------ `x` is borrowed here +... +LL | #[cfg(borrowck)] { x = true; } + | ^^^^^^^^ `x` is assigned to here but it was already borrowed +... +LL | } + | - borrow might be used here, when `b` is dropped and runs the `Drop` code for type `DropMe` + +error[E0506]: cannot assign to `x` because it is borrowed + --> $DIR/super-let.rs:125:28 + | +LL | super let b = DropMe(&mut x); + | ------ `x` is borrowed here +... +LL | #[cfg(borrowck)] { x = true; } + | ^^^^^^^^ `x` is assigned to here but it was already borrowed +... +LL | } + | - borrow might be used here, when `b` is dropped and runs the `Drop` code for type `DropMe` + +error[E0506]: cannot assign to `x` because it is borrowed + --> $DIR/super-let.rs:143:28 + | +LL | super let b = DropMe(&mut x); + | ------ `x` is borrowed here +... +LL | #[cfg(borrowck)] { x = true; } + | ^^^^^^^^ `x` is assigned to here but it was already borrowed +... +LL | } + | - borrow might be used here, when `b` is dropped and runs the `Drop` code for type `DropMe` + +error[E0506]: cannot assign to `x` because it is borrowed + --> $DIR/super-let.rs:159:28 + | +LL | b = DropMe(&mut x); + | ------ `x` is borrowed here +... +LL | #[cfg(borrowck)] { x = true; } + | ^^^^^^^^ `x` is assigned to here but it was already borrowed +LL | drop(a); + | - borrow later used here + +error[E0716]: temporary value dropped while borrowed + --> $DIR/super-let.rs:172:33 + | +LL | #[cfg(borrowck)] { a = &String::from("asdf"); }; + | ^^^^^^^^^^^^^^^^^^^^- temporary value is freed at the end of this statement + | | + | creates a temporary value which is freed while still in use +... +LL | let _ = a; + | - borrow later used here + | + = note: consider using a `let` binding to create a longer lived value + +error[E0506]: cannot assign to `x` because it is borrowed + --> $DIR/super-let.rs:206:28 + | +LL | super let d = &DropMe(&mut x); + | -------------- + | | | + | | `x` is borrowed here + | a temporary with access to the borrow is created here ... +... +LL | #[cfg(borrowck)] { x = true; } + | ^^^^^^^^ `x` is assigned to here but it was already borrowed +... +LL | } + | - ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `DropMe` + +error[E0506]: cannot assign to `x` because it is borrowed + --> $DIR/super-let.rs:227:32 + | +LL | super let d = identity(&DropMe(&mut x)); + | -------------- + | | | + | | `x` is borrowed here + | a temporary with access to the borrow is created here ... +... +LL | #[cfg(borrowck)] { x = true; } + | ^^^^^^^^ `x` is assigned to here but it was already borrowed +... +LL | }; + | - ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `DropMe` + +error[E0506]: cannot assign to `x` because it is borrowed + --> $DIR/super-let.rs:246:28 + | +LL | super let b = DropMe(&mut x); + | ------ `x` is borrowed here +... +LL | #[cfg(borrowck)] { x = true; } + | ^^^^^^^^ `x` is assigned to here but it was already borrowed +... +LL | } + | - borrow might be used here, when `b` is dropped and runs the `Drop` code for type `DropMe` + +error[E0506]: cannot assign to `x` because it is borrowed + --> $DIR/super-let.rs:263:28 + | +LL | let dropme = Some(DropMe(&mut x)); + | ------ `x` is borrowed here +... +LL | #[cfg(borrowck)] { x = true; } + | ^^^^^^^^ `x` is assigned to here but it was already borrowed +... +LL | } + | - borrow might be used here, when `x` is dropped and runs the `Drop` code for type `DropMe` + +error: aborting due to 13 previous errors + +Some errors have detailed explanations: E0506, E0716. +For more information about an error, try `rustc --explain E0506`. diff --git a/tests/ui/super-let.rs b/tests/ui/super-let.rs new file mode 100644 index 000000000000..380470f792fe --- /dev/null +++ b/tests/ui/super-let.rs @@ -0,0 +1,286 @@ +// Check in two ways: +// - borrowck: Check with borrow checking errors when things are alive and dead. +// - runtime: Check with a mutable bool if things are dropped on time. +// +//@ revisions: runtime borrowck +//@ [runtime] run-pass +//@ [borrowck] check-fail + +#![allow(dropping_references)] +#![feature(super_let, stmt_expr_attributes)] + +use std::convert::identity; + +struct DropMe<'a>(&'a mut bool); + +impl Drop for DropMe<'_> { + fn drop(&mut self) { + *self.0 = true; + } +} + +// Check that a super let variable lives as long as the result of a block. +fn extended_variable() { + let mut x = false; + { + let a = { + super let b = DropMe(&mut x); + &b + }; + #[cfg(borrowck)] { x = true; } //[borrowck]~ ERROR borrowed + drop(a); + // DropMe is still alive here... + } + // ... but not here. + assert_eq!(x, true) // ok +} + +// Check that the init expression of a super let is subject to (temporary) lifetime extension. +fn extended_temporary() { + let mut x = false; + { + let a = { + super let b = &DropMe(&mut x); + b + }; + #[cfg(borrowck)] { x = true; } //[borrowck]~ ERROR borrowed + drop(a); + // DropMe is still alive here... + } + // ... but not here. + assert_eq!(x, true); // ok +} + +// Check that even non-extended temporaries live until the end of the block, +// but (unlike extended temporaries) not beyond that. +// +// This is necessary for things like select(pin!(identity(&temp()))) to work. +fn non_extended() { + let mut x = false; + { + let _a = { + // Use identity() to supress temporary lifetime extension. + super let b = identity(&DropMe(&mut x)); + #[cfg(borrowck)] { x = true; } //[borrowck]~ ERROR borrowed + b + // DropMe is still alive here... + }; + // ... but not here. + assert_eq!(x, true); // ok + } +} + +// Check that even non-extended temporaries live until the end of the block, +// but (unlike extended temporaries) not beyond that. +// +// This is necessary for things like select(pin!(identity(&temp()))) to work. +fn non_extended_in_expression() { + let mut x = false; + { + identity(( + { + // Use identity() to supress temporary lifetime extension. + super let b = identity(&DropMe(&mut x)); + b + }, + { + #[cfg(borrowck)] { x = true; } //[borrowck]~ ERROR borrowed + // DropMe is still alive here... + } + )); + // ... but not here. + assert_eq!(x, true); // ok + } +} + +// Check `super let` in a match arm. +fn match_arm() { + let mut x = false; + { + let a = match Some(123) { + Some(_) => { + super let b = DropMe(&mut x); + &b + } + None => unreachable!(), + }; + #[cfg(borrowck)] { x = true; } //[borrowck]~ ERROR borrowed + drop(a); + // DropMe is still alive here... + } + // ... but not here. + assert_eq!(x, true); // ok +} + +// Check `super let` in an if body. +fn if_body() { + let mut x = false; + { + let a = if true { + super let b = DropMe(&mut x); + &b + } else { + unreachable!() + }; + #[cfg(borrowck)] { x = true; } //[borrowck]~ ERROR borrowed + drop(a); + // DropMe is still alive here... + } + // ... but not here. + assert_eq!(x, true); // ok +} + +// Check `super let` in an else body. +fn else_body() { + let mut x = false; + { + let a = if false { + unreachable!() + } else { + super let b = DropMe(&mut x); + &b + }; + #[cfg(borrowck)] { x = true; } //[borrowck]~ ERROR borrowed + drop(a); + // DropMe is still alive here... + } + // ... but not here. + assert_eq!(x, true); // ok +} + +fn without_initializer() { + let mut x = false; + { + let a = { + super let b; + b = DropMe(&mut x); + b + }; + #[cfg(borrowck)] { x = true; } //[borrowck]~ ERROR borrowed + drop(a); + // DropMe is still alive here... + } + // ... but not here. + assert_eq!(x, true); +} + +// Assignment isn't special, even when assigning to a `super let` variable. +fn assignment() { + let mut x = false; + { + super let a; + #[cfg(borrowck)] { a = &String::from("asdf"); }; //[borrowck]~ ERROR dropped while borrowed + #[cfg(runtime)] { a = drop(&DropMe(&mut x)); } // Temporary dropped at the `;` as usual. + assert_eq!(x, true); + let _ = a; + } +} + +// `super let mut` should work just fine. +fn mutable() { + let mut x = false; + { + let a = { + super let mut b = None; + &mut b + }; + *a = Some(DropMe(&mut x)); + } + assert_eq!(x, true); +} + +// Temporary lifetime extension should recurse through `super let`s. +fn multiple_levels() { + let mut x = false; + { + let a = { + super let b = { + super let c = { + super let d = &DropMe(&mut x); + d + }; + c + }; + b + }; + #[cfg(borrowck)] { x = true; } //[borrowck]~ ERROR borrowed + drop(a); + // DropMe is still alive here... + } + // ... but not here. + assert_eq!(x, true); +} + +// Non-extended temporaries should be dropped at the +// end of the first parent statement that isn't `super`. +fn multiple_levels_but_no_extension() { + let mut x = false; + { + let _a = { + super let b = { + super let c = { + super let d = identity(&DropMe(&mut x)); + d + }; + c + }; + #[cfg(borrowck)] { x = true; } //[borrowck]~ ERROR borrowed + b + // DropMe is still alive here... + }; + // ... but not here. + assert_eq!(x, true); + } +} + +// Check for potential weird interactions with `let else`. +fn super_let_and_let_else() { + let mut x = false; + { + let a = 'a: { + let Some(_) = Some(123) else { unreachable!() }; + super let b = DropMe(&mut x); + let None = Some(123) else { break 'a &b }; + unreachable!() + }; + #[cfg(borrowck)] { x = true; } //[borrowck]~ ERROR borrowed + // DropMe is still alive here... + drop(a); + } + // ... but not here. + assert_eq!(x, true); +} + +// Check if `super let .. else ..;` works. +fn super_let_else() { + let mut x = false; + { + let a = { + let dropme = Some(DropMe(&mut x)); + super let Some(x) = dropme else { unreachable!() }; + &x + }; + #[cfg(borrowck)] { x = true; } //[borrowck]~ ERROR borrowed + // DropMe is still alive here... + drop(a); + } + // ... but not here. + assert_eq!(x, true); +} + +fn main() { + extended_variable(); + extended_temporary(); + non_extended(); + non_extended_in_expression(); + match_arm(); + if_body(); + else_body(); + without_initializer(); + assignment(); + mutable(); + multiple_levels(); + multiple_levels_but_no_extension(); + super_let_and_let_else(); + super_let_else(); +} diff --git a/tests/ui/target-feature/forbidden-target-feature-flag-disable.rs b/tests/ui/target-feature/forbidden-target-feature-flag-disable.rs index fda0b1c08cb2..d394dbe7b15d 100644 --- a/tests/ui/target-feature/forbidden-target-feature-flag-disable.rs +++ b/tests/ui/target-feature/forbidden-target-feature-flag-disable.rs @@ -4,7 +4,7 @@ //@ compile-flags: -Ctarget-feature=-forced-atomics // For now this is just a warning. //@ build-pass -//@error-pattern: unsound because it changes the ABI + #![feature(no_core, lang_items)] #![no_core] diff --git a/tests/ui/target-feature/tied-features-no-implication-1.rs b/tests/ui/target-feature/tied-features-no-implication-1.rs index 0a98a7eeccf4..63a1d77dae9f 100644 --- a/tests/ui/target-feature/tied-features-no-implication-1.rs +++ b/tests/ui/target-feature/tied-features-no-implication-1.rs @@ -2,9 +2,7 @@ //@ compile-flags: --crate-type=rlib --target=aarch64-unknown-linux-gnu //@ needs-llvm-components: aarch64 //@[paca] compile-flags: -Ctarget-feature=+paca -//@[paca] error-pattern: the target features paca, pacg must all be either enabled or disabled together //@[pacg] compile-flags: -Ctarget-feature=+pacg -//@[paca] error-pattern: the target features paca, pacg must all be either enabled or disabled together #![feature(no_core, lang_items)] #![no_core] diff --git a/tests/ui/test-attrs/test-should-panic-failed-show-span.rs b/tests/ui/test-attrs/test-should-panic-failed-show-span.rs new file mode 100644 index 000000000000..f400f614142d --- /dev/null +++ b/tests/ui/test-attrs/test-should-panic-failed-show-span.rs @@ -0,0 +1,46 @@ +//@ compile-flags: --test +//@ run-flags: --test-threads=1 --nocapture +//@ run-fail +//@ check-run-results +//@ exec-env:RUST_BACKTRACE=0 +//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME" +//@ normalize-stdout: "TypeId\(0x[0-9a-f]+\)" -> "TypeId($$HEX)" +//@ needs-threads +//@ needs-unwind (panic) + +#[test] +#[should_panic] +fn should_panic_with_any_message() { + panic!("Panic!"); +} + +#[test] +#[should_panic = "message"] +fn should_panic_with_message() { + panic!("message"); +} + +#[test] +#[should_panic] +fn should_panic_with_any_message_does_not_panic() { + // DON'T PANIC +} + +#[test] +#[should_panic = "message"] +fn should_panic_with_message_does_not_panic() { + // DON'T PANIC +} + +#[test] +#[should_panic = "message"] +fn should_panic_with_substring_panics_with_incorrect_string() { + panic!("ZOMGWTFBBQ"); +} + +#[test] +#[should_panic = "message"] +#[expect(non_fmt_panics)] +fn should_panic_with_substring_panics_with_non_string_value() { + panic!(123); +} diff --git a/tests/ui/test-attrs/test-should-panic-failed-show-span.run.stderr b/tests/ui/test-attrs/test-should-panic-failed-show-span.run.stderr new file mode 100644 index 000000000000..db379a16b52a --- /dev/null +++ b/tests/ui/test-attrs/test-should-panic-failed-show-span.run.stderr @@ -0,0 +1,13 @@ + +thread 'should_panic_with_any_message' panicked at $DIR/test-should-panic-failed-show-span.rs:14:5: +Panic! +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace + +thread 'should_panic_with_message' panicked at $DIR/test-should-panic-failed-show-span.rs:20:5: +message + +thread 'should_panic_with_substring_panics_with_incorrect_string' panicked at $DIR/test-should-panic-failed-show-span.rs:38:5: +ZOMGWTFBBQ + +thread 'should_panic_with_substring_panics_with_non_string_value' panicked at $DIR/test-should-panic-failed-show-span.rs:45:5: +Box diff --git a/tests/ui/test-attrs/test-should-panic-failed-show-span.run.stdout b/tests/ui/test-attrs/test-should-panic-failed-show-span.run.stdout new file mode 100644 index 000000000000..75600b4d3d66 --- /dev/null +++ b/tests/ui/test-attrs/test-should-panic-failed-show-span.run.stdout @@ -0,0 +1,32 @@ + +running 6 tests +test should_panic_with_any_message - should panic ... ok +test should_panic_with_any_message_does_not_panic - should panic ... FAILED +test should_panic_with_message - should panic ... ok +test should_panic_with_message_does_not_panic - should panic ... FAILED +test should_panic_with_substring_panics_with_incorrect_string - should panic ... FAILED +test should_panic_with_substring_panics_with_non_string_value - should panic ... FAILED + +failures: + +---- should_panic_with_any_message_does_not_panic stdout ---- +note: test did not panic as expected at $DIR/test-should-panic-failed-show-span.rs:25:4 +---- should_panic_with_message_does_not_panic stdout ---- +note: test did not panic as expected at $DIR/test-should-panic-failed-show-span.rs:31:4 +---- should_panic_with_substring_panics_with_incorrect_string stdout ---- +note: panic did not contain expected string + panic message: `"ZOMGWTFBBQ"`, + expected substring: `"message"` +---- should_panic_with_substring_panics_with_non_string_value stdout ---- +note: expected panic with string value, + found non-string value: `TypeId($HEX)` + expected substring: `"message"` + +failures: + should_panic_with_any_message_does_not_panic + should_panic_with_message_does_not_panic + should_panic_with_substring_panics_with_incorrect_string + should_panic_with_substring_panics_with_non_string_value + +test result: FAILED. 2 passed; 4 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/tests/ui/tool-attributes/tool_lints.rs b/tests/ui/tool-attributes/tool_lints.rs index ef27532f6de1..9e4aa7a939ac 100644 --- a/tests/ui/tool-attributes/tool_lints.rs +++ b/tests/ui/tool-attributes/tool_lints.rs @@ -1,4 +1,5 @@ #[warn(foo::bar)] //~^ ERROR unknown tool name `foo` found in scoped lint: `foo::bar` //~| ERROR unknown tool name `foo` found in scoped lint: `foo::bar` +//~| ERROR unknown tool name `foo` found in scoped lint: `foo::bar` fn main() {} diff --git a/tests/ui/tool-attributes/tool_lints.stderr b/tests/ui/tool-attributes/tool_lints.stderr index f1d825caba15..eee0a9784ece 100644 --- a/tests/ui/tool-attributes/tool_lints.stderr +++ b/tests/ui/tool-attributes/tool_lints.stderr @@ -15,6 +15,15 @@ LL | #[warn(foo::bar)] = help: add `#![register_tool(foo)]` to the crate root = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: aborting due to 2 previous errors +error[E0710]: unknown tool name `foo` found in scoped lint: `foo::bar` + --> $DIR/tool_lints.rs:1:8 + | +LL | #[warn(foo::bar)] + | ^^^ + | + = help: add `#![register_tool(foo)]` to the crate root + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0710`. diff --git a/tests/ui/tool-attributes/unknown-lint-tool-name.rs b/tests/ui/tool-attributes/unknown-lint-tool-name.rs index 59fc56d820ee..84ab7c1944ab 100644 --- a/tests/ui/tool-attributes/unknown-lint-tool-name.rs +++ b/tests/ui/tool-attributes/unknown-lint-tool-name.rs @@ -4,4 +4,5 @@ #[allow(foo::bar)] //~ ERROR unknown tool name `foo` found in scoped lint: `foo::bar` //~| ERROR unknown tool name `foo` found in scoped lint: `foo::bar` + //~| ERROR unknown tool name `foo` found in scoped lint: `foo::bar` fn main() {} diff --git a/tests/ui/tool-attributes/unknown-lint-tool-name.stderr b/tests/ui/tool-attributes/unknown-lint-tool-name.stderr index 5d99777a14ae..91baf8827375 100644 --- a/tests/ui/tool-attributes/unknown-lint-tool-name.stderr +++ b/tests/ui/tool-attributes/unknown-lint-tool-name.stderr @@ -41,6 +41,15 @@ LL | #![deny(foo::bar)] = help: add `#![register_tool(foo)]` to the crate root = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: aborting due to 5 previous errors +error[E0710]: unknown tool name `foo` found in scoped lint: `foo::bar` + --> $DIR/unknown-lint-tool-name.rs:5:9 + | +LL | #[allow(foo::bar)] + | ^^^ + | + = help: add `#![register_tool(foo)]` to the crate root + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0710`. diff --git a/tests/ui/trait-bounds/mismatch-fn-trait.stderr b/tests/ui/trait-bounds/mismatch-fn-trait.stderr index 519aa9ea3f3b..051e660c2d10 100644 --- a/tests/ui/trait-bounds/mismatch-fn-trait.stderr +++ b/tests/ui/trait-bounds/mismatch-fn-trait.stderr @@ -6,8 +6,8 @@ LL | take(f) | | | required by a bound introduced by this call | - = note: expected a closure with arguments `(u32,)` - found a closure with arguments `(i32,)` + = note: expected a closure with signature `fn(i32)` + found a closure with signature `fn(u32)` note: required by a bound in `take` --> $DIR/mismatch-fn-trait.rs:1:18 | @@ -68,8 +68,8 @@ LL | take(f) | required by a bound introduced by this call | = note: `impl FnOnce(u32)` implements `FnOnce`, but it must implement `FnMut`, which is more general - = note: expected a closure with arguments `(u32,)` - found a closure with arguments `(i32,)` + = note: expected a closure with signature `fn(i32)` + found a closure with signature `fn(u32)` note: required by a bound in `take` --> $DIR/mismatch-fn-trait.rs:1:18 | diff --git a/tests/ui/traits/alias/issue-108132-unmet-trait-alias-bound-on-generic-impl.rs b/tests/ui/traits/alias/issue-108132-unmet-trait-alias-bound-on-generic-impl.rs index 0b1f9ab57c98..39ca19fc3a58 100644 --- a/tests/ui/traits/alias/issue-108132-unmet-trait-alias-bound-on-generic-impl.rs +++ b/tests/ui/traits/alias/issue-108132-unmet-trait-alias-bound-on-generic-impl.rs @@ -11,5 +11,5 @@ impl Foo { } fn main() { - Foo::<()>::f() //~ trait bounds were not satisfied + Foo::<()>::f() //~ ERROR trait bounds were not satisfied } diff --git a/tests/ui/traits/associated_type_bound/check-trait-object-bounds-2.rs b/tests/ui/traits/associated_type_bound/check-trait-object-bounds-2.rs index 1359eb6cb87a..891cc32e7b75 100644 --- a/tests/ui/traits/associated_type_bound/check-trait-object-bounds-2.rs +++ b/tests/ui/traits/associated_type_bound/check-trait-object-bounds-2.rs @@ -11,5 +11,5 @@ fn f X<'r> + ?Sized>() { fn main() { f:: X<'x, F = i32>>(); - //~^ expected a `FnOnce(&i32)` closure, found `i32` + //~^ ERROR expected a `FnOnce(&i32)` closure, found `i32` } diff --git a/tests/ui/traits/associated_type_bound/check-trait-object-bounds-5.rs b/tests/ui/traits/associated_type_bound/check-trait-object-bounds-5.rs index 7d733ad26b75..829a40c64e66 100644 --- a/tests/ui/traits/associated_type_bound/check-trait-object-bounds-5.rs +++ b/tests/ui/traits/associated_type_bound/check-trait-object-bounds-5.rs @@ -21,7 +21,7 @@ fn is_obj(_: &T) {} fn f(x: &dyn Obj) { is_obj(x) - //~^ type mismatch resolving `::T == i64` + //~^ ERROR type mismatch resolving `::T == i64` } fn main() {} diff --git a/tests/ui/traits/associated_type_bound/hrtb-associated.rs b/tests/ui/traits/associated_type_bound/hrtb-associated.rs new file mode 100644 index 000000000000..59e5a09c0cbb --- /dev/null +++ b/tests/ui/traits/associated_type_bound/hrtb-associated.rs @@ -0,0 +1,30 @@ +//@ check-pass +//! This test ensures that HRTB (higher-ranked trait bounds) on associated types +//! compile correctly. This was previously rejected by the compiler. +//! Related issue: + +pub trait Provides<'a> { + type Item; +} + +pub trait Selector: for<'a> Provides<'a> { + type Namespace: PartialEq + for<'a> PartialEq<>::Item>; + + fn get_namespace(&self) -> ::Item; +} + +pub struct MySelector; + +impl<'a> Provides<'a> for MySelector { + type Item = &'a str; +} + +impl Selector for MySelector { + type Namespace = String; + + fn get_namespace(&self) -> &str { + unimplemented!() + } +} + +fn main() {} diff --git a/tests/ui/traits/const-traits/ice-119717-constant-lifetime.rs b/tests/ui/traits/const-traits/ice-119717-constant-lifetime.rs index dc1e719bded1..e53b87274d3a 100644 --- a/tests/ui/traits/const-traits/ice-119717-constant-lifetime.rs +++ b/tests/ui/traits/const-traits/ice-119717-constant-lifetime.rs @@ -5,9 +5,9 @@ use std::ops::FromResidual; impl const FromResidual for T { //~^ ERROR const `impl` for trait `FromResidual` which is not marked with `#[const_trait]` - //~| type parameter `T` must be used as the type parameter for some local type + //~| ERROR type parameter `T` must be used as the type parameter for some local type fn from_residual(t: T) -> _ { - //~^ the placeholder `_` is not allowed + //~^ ERROR the placeholder `_` is not allowed t } } diff --git a/tests/ui/traits/const-traits/staged-api.rs b/tests/ui/traits/const-traits/staged-api.rs index 8dd7226fc298..bf09a5f78038 100644 --- a/tests/ui/traits/const-traits/staged-api.rs +++ b/tests/ui/traits/const-traits/staged-api.rs @@ -96,12 +96,12 @@ trait S {} // implied stable impl const U for u8 {} -//~^ const stability on the impl does not match the const stability on the trait +//~^ ERROR const stability on the impl does not match the const stability on the trait #[rustc_const_stable(since = "0.0.0", feature = "beef2")] impl const U for u16 {} -//~^ const stability on the impl does not match the const stability on the trait -//~| trait implementations cannot be const stable yet +//~^ ERROR const stability on the impl does not match the const stability on the trait +//~| ERROR trait implementations cannot be const stable yet #[rustc_const_unstable(feature = "beef", issue = "none")] impl const U for u32 {} @@ -111,10 +111,10 @@ impl const S for u8 {} #[rustc_const_stable(since = "0.0.0", feature = "beef2")] impl const S for u16 {} -//~^ trait implementations cannot be const stable yet +//~^ ERROR trait implementations cannot be const stable yet #[rustc_const_unstable(feature = "beef", issue = "none")] impl const S for u32 {} -//~^ const stability on the impl does not match the const stability on the trait +//~^ ERROR const stability on the impl does not match the const stability on the trait fn main() {} diff --git a/tests/ui/traits/const-traits/unsatisfied-const-trait-bound.stderr b/tests/ui/traits/const-traits/unsatisfied-const-trait-bound.stderr index be761e49ba0c..03e26615d7ed 100644 --- a/tests/ui/traits/const-traits/unsatisfied-const-trait-bound.stderr +++ b/tests/ui/traits/const-traits/unsatisfied-const-trait-bound.stderr @@ -6,30 +6,134 @@ LL | #![feature(const_trait_impl, generic_const_exprs)] | = help: remove one of these features -error[E0277]: the trait bound `T: const Trait` is not satisfied - --> $DIR/unsatisfied-const-trait-bound.rs:29:37 +error[E0391]: cycle detected when evaluating type-level constant + --> $DIR/unsatisfied-const-trait-bound.rs:29:35 | LL | fn accept0(_: Container<{ T::make() }>) {} - | ^ + | ^^^^^^^^^^^^^ + | +note: ...which requires const-evaluating + checking `accept0::{constant#0}`... + --> $DIR/unsatisfied-const-trait-bound.rs:29:35 + | +LL | fn accept0(_: Container<{ T::make() }>) {} + | ^^^^^^^^^^^^^ +note: ...which requires caching mir of `accept0::{constant#0}` for CTFE... + --> $DIR/unsatisfied-const-trait-bound.rs:29:35 + | +LL | fn accept0(_: Container<{ T::make() }>) {} + | ^^^^^^^^^^^^^ +note: ...which requires elaborating drops for `accept0::{constant#0}`... + --> $DIR/unsatisfied-const-trait-bound.rs:29:35 + | +LL | fn accept0(_: Container<{ T::make() }>) {} + | ^^^^^^^^^^^^^ +note: ...which requires borrow-checking `accept0::{constant#0}`... + --> $DIR/unsatisfied-const-trait-bound.rs:29:35 + | +LL | fn accept0(_: Container<{ T::make() }>) {} + | ^^^^^^^^^^^^^ +note: ...which requires promoting constants in MIR for `accept0::{constant#0}`... + --> $DIR/unsatisfied-const-trait-bound.rs:29:35 + | +LL | fn accept0(_: Container<{ T::make() }>) {} + | ^^^^^^^^^^^^^ +note: ...which requires const checking `accept0::{constant#0}`... + --> $DIR/unsatisfied-const-trait-bound.rs:29:35 + | +LL | fn accept0(_: Container<{ T::make() }>) {} + | ^^^^^^^^^^^^^ +note: ...which requires building MIR for `accept0::{constant#0}`... + --> $DIR/unsatisfied-const-trait-bound.rs:29:35 + | +LL | fn accept0(_: Container<{ T::make() }>) {} + | ^^^^^^^^^^^^^ +note: ...which requires building an abstract representation for `accept0::{constant#0}`... + --> $DIR/unsatisfied-const-trait-bound.rs:29:35 + | +LL | fn accept0(_: Container<{ T::make() }>) {} + | ^^^^^^^^^^^^^ +note: ...which requires building THIR for `accept0::{constant#0}`... + --> $DIR/unsatisfied-const-trait-bound.rs:29:35 + | +LL | fn accept0(_: Container<{ T::make() }>) {} + | ^^^^^^^^^^^^^ +note: ...which requires type-checking `accept0::{constant#0}`... + --> $DIR/unsatisfied-const-trait-bound.rs:29:35 + | +LL | fn accept0(_: Container<{ T::make() }>) {} + | ^^^^^^^^^^^^^ + = note: ...which again requires evaluating type-level constant, completing the cycle +note: cycle used when checking that `accept0` is well-formed + --> $DIR/unsatisfied-const-trait-bound.rs:29:1 + | +LL | fn accept0(_: Container<{ T::make() }>) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information -error[E0277]: the trait bound `T: const Trait` is not satisfied - --> $DIR/unsatisfied-const-trait-bound.rs:33:50 +error[E0391]: cycle detected when caching mir of `accept1::{constant#0}` for CTFE + --> $DIR/unsatisfied-const-trait-bound.rs:33:48 | LL | const fn accept1(_: Container<{ T::make() }>) {} - | ^ - -error[E0277]: the trait bound `Ty: const Trait` is not satisfied - --> $DIR/unsatisfied-const-trait-bound.rs:22:15 + | ^^^^^^^^^^^^^ | -LL | require::(); - | ^^ +note: ...which requires elaborating drops for `accept1::{constant#0}`... + --> $DIR/unsatisfied-const-trait-bound.rs:33:48 | -note: required by a bound in `require` - --> $DIR/unsatisfied-const-trait-bound.rs:8:15 +LL | const fn accept1(_: Container<{ T::make() }>) {} + | ^^^^^^^^^^^^^ +note: ...which requires borrow-checking `accept1::{constant#0}`... + --> $DIR/unsatisfied-const-trait-bound.rs:33:48 | -LL | fn require() {} - | ^^^^^^^^^^^ required by this bound in `require` +LL | const fn accept1(_: Container<{ T::make() }>) {} + | ^^^^^^^^^^^^^ +note: ...which requires promoting constants in MIR for `accept1::{constant#0}`... + --> $DIR/unsatisfied-const-trait-bound.rs:33:48 + | +LL | const fn accept1(_: Container<{ T::make() }>) {} + | ^^^^^^^^^^^^^ +note: ...which requires const checking `accept1::{constant#0}`... + --> $DIR/unsatisfied-const-trait-bound.rs:33:48 + | +LL | const fn accept1(_: Container<{ T::make() }>) {} + | ^^^^^^^^^^^^^ +note: ...which requires building MIR for `accept1::{constant#0}`... + --> $DIR/unsatisfied-const-trait-bound.rs:33:48 + | +LL | const fn accept1(_: Container<{ T::make() }>) {} + | ^^^^^^^^^^^^^ +note: ...which requires building an abstract representation for `accept1::{constant#0}`... + --> $DIR/unsatisfied-const-trait-bound.rs:33:48 + | +LL | const fn accept1(_: Container<{ T::make() }>) {} + | ^^^^^^^^^^^^^ +note: ...which requires building THIR for `accept1::{constant#0}`... + --> $DIR/unsatisfied-const-trait-bound.rs:33:48 + | +LL | const fn accept1(_: Container<{ T::make() }>) {} + | ^^^^^^^^^^^^^ +note: ...which requires type-checking `accept1::{constant#0}`... + --> $DIR/unsatisfied-const-trait-bound.rs:33:48 + | +LL | const fn accept1(_: Container<{ T::make() }>) {} + | ^^^^^^^^^^^^^ +note: ...which requires evaluating type-level constant... + --> $DIR/unsatisfied-const-trait-bound.rs:33:48 + | +LL | const fn accept1(_: Container<{ T::make() }>) {} + | ^^^^^^^^^^^^^ +note: ...which requires const-evaluating + checking `accept1::{constant#0}`... + --> $DIR/unsatisfied-const-trait-bound.rs:33:48 + | +LL | const fn accept1(_: Container<{ T::make() }>) {} + | ^^^^^^^^^^^^^ + = note: ...which again requires caching mir of `accept1::{constant#0}` for CTFE, completing the cycle +note: cycle used when const-evaluating + checking `accept1::{constant#0}` + --> $DIR/unsatisfied-const-trait-bound.rs:33:48 + | +LL | const fn accept1(_: Container<{ T::make() }>) {} + | ^^^^^^^^^^^^^ + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0277`. +For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/traits/copy-is-not-modulo-regions.rs b/tests/ui/traits/copy-is-not-modulo-regions.rs index 1e7d2d9c691a..2efbeb4889de 100644 --- a/tests/ui/traits/copy-is-not-modulo-regions.rs +++ b/tests/ui/traits/copy-is-not-modulo-regions.rs @@ -11,7 +11,7 @@ struct Bar<'lt>(Foo<'lt>); #[cfg(not_static)] impl<'any> Copy for Bar<'any> {} -//[not_static]~^ the trait `Copy` cannot be implemented for this type +//[not_static]~^ ERROR the trait `Copy` cannot be implemented for this type #[cfg(yes_static)] impl<'any> Copy for Bar<'static> {} diff --git a/tests/ui/traits/default-method/rustc_must_implement_one_of.rs b/tests/ui/traits/default-method/rustc_must_implement_one_of.rs index 5ba2f5ce3342..a77f1d5e608e 100644 --- a/tests/ui/traits/default-method/rustc_must_implement_one_of.rs +++ b/tests/ui/traits/default-method/rustc_must_implement_one_of.rs @@ -39,6 +39,6 @@ impl Equal for T2 { } impl Equal for T3 {} -//~^ not all trait items implemented, missing one of: `eq`, `neq` +//~^ ERROR not all trait items implemented, missing one of: `eq`, `neq` fn main() {} diff --git a/tests/ui/traits/default-method/rustc_must_implement_one_of_duplicates.rs b/tests/ui/traits/default-method/rustc_must_implement_one_of_duplicates.rs index 8db5fa615c08..1e91b0607926 100644 --- a/tests/ui/traits/default-method/rustc_must_implement_one_of_duplicates.rs +++ b/tests/ui/traits/default-method/rustc_must_implement_one_of_duplicates.rs @@ -1,15 +1,15 @@ #![feature(rustc_attrs)] #[rustc_must_implement_one_of(a, a)] -//~^ functions names are duplicated +//~^ ERROR functions names are duplicated trait Trait { fn a() {} } #[rustc_must_implement_one_of(b, a, a, c, b, c)] -//~^ functions names are duplicated -//~| functions names are duplicated -//~| functions names are duplicated +//~^ ERROR functions names are duplicated +//~| ERROR functions names are duplicated +//~| ERROR functions names are duplicated trait Trait1 { fn a() {} fn b() {} diff --git a/tests/ui/traits/default-method/rustc_must_implement_one_of_gated.rs b/tests/ui/traits/default-method/rustc_must_implement_one_of_gated.rs index ec2995872de0..27e70556b7af 100644 --- a/tests/ui/traits/default-method/rustc_must_implement_one_of_gated.rs +++ b/tests/ui/traits/default-method/rustc_must_implement_one_of_gated.rs @@ -1,5 +1,5 @@ #[rustc_must_implement_one_of(eq, neq)] -//~^ the `#[rustc_must_implement_one_of]` attribute is used to change minimal complete definition of a trait, it's currently in experimental form and should be changed before being exposed outside of the std +//~^ ERROR the `#[rustc_must_implement_one_of]` attribute is used to change minimal complete definition of a trait, it's currently in experimental form and should be changed before being exposed outside of the std trait Equal { fn eq(&self, other: &Self) -> bool { !self.neq(other) diff --git a/tests/ui/traits/default-method/rustc_must_implement_one_of_misuse.rs b/tests/ui/traits/default-method/rustc_must_implement_one_of_misuse.rs index b1b91966c8d8..9b2e489c5425 100644 --- a/tests/ui/traits/default-method/rustc_must_implement_one_of_misuse.rs +++ b/tests/ui/traits/default-method/rustc_must_implement_one_of_misuse.rs @@ -1,46 +1,46 @@ #![feature(rustc_attrs)] #[rustc_must_implement_one_of(a, b)] -//~^ function not found in this trait -//~| function not found in this trait +//~^ ERROR function not found in this trait +//~| ERROR function not found in this trait trait Tr0 {} #[rustc_must_implement_one_of(a, b)] -//~^ function not found in this trait +//~^ ERROR function not found in this trait trait Tr1 { fn a() {} } #[rustc_must_implement_one_of(a)] -//~^ the `#[rustc_must_implement_one_of]` attribute must be used with at least 2 args +//~^ ERROR the `#[rustc_must_implement_one_of]` attribute must be used with at least 2 args trait Tr2 { fn a() {} } #[rustc_must_implement_one_of] -//~^ malformed `rustc_must_implement_one_of` attribute input +//~^ ERROR malformed `rustc_must_implement_one_of` attribute input trait Tr3 {} #[rustc_must_implement_one_of(A, B)] trait Tr4 { - const A: u8 = 1; //~ not a function + const A: u8 = 1; //~ ERROR not a function - type B; //~ not a function + type B; //~ ERROR not a function } #[rustc_must_implement_one_of(a, b)] trait Tr5 { - fn a(); //~ function doesn't have a default implementation + fn a(); //~ ERROR function doesn't have a default implementation - fn b(); //~ function doesn't have a default implementation + fn b(); //~ ERROR function doesn't have a default implementation } #[rustc_must_implement_one_of(abc, xyz)] -//~^ attribute should be applied to a trait +//~^ ERROR attribute should be applied to a trait fn function() {} #[rustc_must_implement_one_of(abc, xyz)] -//~^ attribute should be applied to a trait +//~^ ERROR attribute should be applied to a trait struct Struct {} fn main() {} diff --git a/tests/ui/traits/default_auto_traits/maybe-bounds-in-traits.rs b/tests/ui/traits/default_auto_traits/maybe-bounds-in-traits.rs index 761f22d1be5e..4cb38bc8e795 100644 --- a/tests/ui/traits/default_auto_traits/maybe-bounds-in-traits.rs +++ b/tests/ui/traits/default_auto_traits/maybe-bounds-in-traits.rs @@ -97,7 +97,7 @@ mod methods { fn mut_leak_foo(&mut self) {} // there is no relax bound on corresponding Receiver impl fn mut_maybe_leak_foo(&mut self) where Self: ?Leak {} - //~^ `&mut Self` cannot be used as the type of `self` without the `arbitrary_self_types` + //~^ ERROR `&mut Self` cannot be used as the type of `self` without the `arbitrary_self_types` } impl Trait for NonLeakS {} diff --git a/tests/ui/traits/dont-suggest-impl-as-closure-arg.rs b/tests/ui/traits/dont-suggest-impl-as-closure-arg.rs new file mode 100644 index 000000000000..68e234b0f20d --- /dev/null +++ b/tests/ui/traits/dont-suggest-impl-as-closure-arg.rs @@ -0,0 +1,5 @@ +// Suggestion to use impl trait in closure parameter is invalid, see issue 138932 +fn main() { + let c = |f: dyn Fn()| f(); + //~^ ERROR: the size for values of type `(dyn Fn() + 'static)` cannot be known at compilation time +} diff --git a/tests/ui/traits/dont-suggest-impl-as-closure-arg.stderr b/tests/ui/traits/dont-suggest-impl-as-closure-arg.stderr new file mode 100644 index 000000000000..8218990503c2 --- /dev/null +++ b/tests/ui/traits/dont-suggest-impl-as-closure-arg.stderr @@ -0,0 +1,16 @@ +error[E0277]: the size for values of type `(dyn Fn() + 'static)` cannot be known at compilation time + --> $DIR/dont-suggest-impl-as-closure-arg.rs:3:17 + | +LL | let c = |f: dyn Fn()| f(); + | ^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `(dyn Fn() + 'static)` + = help: unsized fn params are gated as an unstable feature +help: function arguments must have a statically known size, borrowed types always have a known size + | +LL | let c = |f: &dyn Fn()| f(); + | + + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/dyn-drop-principal-with-projections.rs b/tests/ui/traits/dyn-drop-principal-with-projections.rs new file mode 100644 index 000000000000..912061847c69 --- /dev/null +++ b/tests/ui/traits/dyn-drop-principal-with-projections.rs @@ -0,0 +1,13 @@ +//@ check-pass + +trait Tr { + type Assoc; +} + +impl Tr for () { + type Assoc = (); +} + +fn main() { + let x = &() as &(dyn Tr + Send) as &dyn Send; +} diff --git a/tests/ui/traits/issue-106072.rs b/tests/ui/traits/issue-106072.rs index d75c26642c60..d45668312218 100644 --- a/tests/ui/traits/issue-106072.rs +++ b/tests/ui/traits/issue-106072.rs @@ -1,6 +1,6 @@ #[derive(Clone)] -//~^ expected a type, found a trait -//~| expected a type, found a trait +//~^ ERROR expected a type, found a trait +//~| ERROR expected a type, found a trait struct Foo; -trait Foo {} //~ the name `Foo` is defined multiple times +trait Foo {} //~ ERROR the name `Foo` is defined multiple times fn main() {} diff --git a/tests/ui/traits/issue-85360-eval-obligation-ice.rs b/tests/ui/traits/issue-85360-eval-obligation-ice.rs index 931879a67226..f7c49049e2d3 100644 --- a/tests/ui/traits/issue-85360-eval-obligation-ice.rs +++ b/tests/ui/traits/issue-85360-eval-obligation-ice.rs @@ -1,4 +1,4 @@ -//@ compile-flags: --edition=2021 +//@ edition: 2021 #![feature(rustc_attrs)] diff --git a/tests/ui/traits/next-solver/async.fail.stderr b/tests/ui/traits/next-solver/async.fail.stderr index bc89842d16a1..a76a10d20ee8 100644 --- a/tests/ui/traits/next-solver/async.fail.stderr +++ b/tests/ui/traits/next-solver/async.fail.stderr @@ -1,8 +1,8 @@ -error[E0271]: expected `{async block@$DIR/async.rs:12:17: 12:22}` to be a future that resolves to `i32`, but it resolves to `()` +error[E0271]: type mismatch resolving `() == i32` --> $DIR/async.rs:12:17 | LL | needs_async(async {}); - | ----------- ^^^^^^^^ expected `i32`, found `()` + | ----------- ^^^^^^^^ types differ | | | required by a bound introduced by this call | diff --git a/tests/ui/traits/next-solver/async.rs b/tests/ui/traits/next-solver/async.rs index fded77435475..34c0ed02eeb1 100644 --- a/tests/ui/traits/next-solver/async.rs +++ b/tests/ui/traits/next-solver/async.rs @@ -10,7 +10,7 @@ fn needs_async(_: impl Future) {} #[cfg(fail)] fn main() { needs_async(async {}); - //[fail]~^ ERROR expected `{async block@$DIR/async.rs:12:17: 12:22}` to be a future that resolves to `i32`, but it resolves to `()` + //[fail]~^ ERROR type mismatch resolving `() == i32` } #[cfg(pass)] diff --git a/tests/ui/traits/next-solver/builtin-fn-must-return-sized.rs b/tests/ui/traits/next-solver/builtin-fn-must-return-sized.rs index f8926b24e3fa..fbe801aedcd8 100644 --- a/tests/ui/traits/next-solver/builtin-fn-must-return-sized.rs +++ b/tests/ui/traits/next-solver/builtin-fn-must-return-sized.rs @@ -13,5 +13,5 @@ fn foo, T: Tuple>(f: Option, t: T) { fn main() { foo:: str, _>(None, ()); - //~^ the size for values of type `str` cannot be known at compilation time + //~^ ERROR the size for values of type `str` cannot be known at compilation time } diff --git a/tests/ui/traits/next-solver/cycles/inductive-cycle-but-err.rs b/tests/ui/traits/next-solver/cycles/inductive-cycle-but-err.rs index b0c778e7f574..754fc872e457 100644 --- a/tests/ui/traits/next-solver/cycles/inductive-cycle-but-err.rs +++ b/tests/ui/traits/next-solver/cycles/inductive-cycle-but-err.rs @@ -34,9 +34,17 @@ where MultipleNested: Trait, {} +// We ignore the trivially true global where-bounds when checking that this +// impl is well-formed, meaning that we depend on `MultipleNested: Trait` when +// recursively proving `MultipleCandidates: Trait`. +// +// These overflow errors will disappear once we treat these cycles as either +// productive or an error. impl Trait for MultipleNested +//~^ ERROR overflow evaluating the requirement `MultipleNested: Trait` where MultipleCandidates: Trait, + //~^ ERROR overflow evaluating the requirement `MultipleCandidates: Trait` DoesNotImpl: Trait, {} diff --git a/tests/ui/traits/next-solver/cycles/inductive-cycle-but-err.stderr b/tests/ui/traits/next-solver/cycles/inductive-cycle-but-err.stderr index acacaf6a331d..7895a2636345 100644 --- a/tests/ui/traits/next-solver/cycles/inductive-cycle-but-err.stderr +++ b/tests/ui/traits/next-solver/cycles/inductive-cycle-but-err.stderr @@ -1,16 +1,29 @@ +error[E0275]: overflow evaluating the requirement `MultipleNested: Trait` + --> $DIR/inductive-cycle-but-err.rs:43:16 + | +LL | impl Trait for MultipleNested + | ^^^^^^^^^^^^^^ + +error[E0275]: overflow evaluating the requirement `MultipleCandidates: Trait` + --> $DIR/inductive-cycle-but-err.rs:46:25 + | +LL | MultipleCandidates: Trait, + | ^^^^^ + error[E0277]: the trait bound `MultipleCandidates: Trait` is not satisfied - --> $DIR/inductive-cycle-but-err.rs:46:19 + --> $DIR/inductive-cycle-but-err.rs:54:19 | LL | impls_trait::(); | ^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `MultipleCandidates` | = help: the trait `Trait` is implemented for `MultipleCandidates` note: required by a bound in `impls_trait` - --> $DIR/inductive-cycle-but-err.rs:43:19 + --> $DIR/inductive-cycle-but-err.rs:51:19 | LL | fn impls_trait() {} | ^^^^^ required by this bound in `impls_trait` -error: aborting due to 1 previous error +error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0275, E0277. +For more information about an error, try `rustc --explain E0275`. diff --git a/tests/ui/traits/next-solver/cycles/normalizes-to-is-not-productive-2.rs b/tests/ui/traits/next-solver/cycles/normalizes-to-is-not-productive-2.rs new file mode 100644 index 000000000000..bb3540f9a214 --- /dev/null +++ b/tests/ui/traits/next-solver/cycles/normalizes-to-is-not-productive-2.rs @@ -0,0 +1,24 @@ +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver +//@ check-pass + +// Regression test for trait-system-refactor-initiative#176. +// +// Normalizing ` as IntoIterator>::IntoIter` has two candidates +// inside of the function: +// - `impl IntoIterator for Vec` which trivially applies +// - `impl IntoIterator for I` +// - requires `Vec: Iterator` +// - where-clause requires ` as IntoIterator>::IntoIter eq Vec` +// - normalize ` as IntoIterator>::IntoIter` again, cycle +// +// We need to treat this cycle as an error to be able to use the actual impl. + +fn test() +where + as IntoIterator>::IntoIter: Iterator, +{ +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/cycles/normalizes-to-is-not-productive.current.stderr b/tests/ui/traits/next-solver/cycles/normalizes-to-is-not-productive.current.stderr new file mode 100644 index 000000000000..0a5b90f3d12b --- /dev/null +++ b/tests/ui/traits/next-solver/cycles/normalizes-to-is-not-productive.current.stderr @@ -0,0 +1,48 @@ +error[E0277]: the trait bound `Foo: Bound` is not satisfied + --> $DIR/normalizes-to-is-not-productive.rs:41:1 + | +LL | / fn generic() +LL | | where +LL | | >::Assoc: Bound, + | |____________________________________^ the trait `Bound` is not implemented for `Foo` + | + = help: the trait `Bound` is implemented for `u32` +note: required for `Foo` to implement `Trait` + --> $DIR/normalizes-to-is-not-productive.rs:24:19 + | +LL | impl Trait for T { + | ----- ^^^^^^^^ ^ + | | + | unsatisfied trait bound introduced here + +error[E0277]: the trait bound `Foo: Bound` is not satisfied + --> $DIR/normalizes-to-is-not-productive.rs:41:4 + | +LL | fn generic() + | ^^^^^^^ the trait `Bound` is not implemented for `Foo` + | + = help: the trait `Bound` is implemented for `u32` +note: required for `Foo` to implement `Trait` + --> $DIR/normalizes-to-is-not-productive.rs:24:19 + | +LL | impl Trait for T { + | ----- ^^^^^^^^ ^ + | | + | unsatisfied trait bound introduced here + +error[E0277]: the trait bound `Foo: Bound` is not satisfied + --> $DIR/normalizes-to-is-not-productive.rs:48:19 + | +LL | impls_bound::(); + | ^^^ the trait `Bound` is not implemented for `Foo` + | + = help: the trait `Bound` is implemented for `u32` +note: required by a bound in `impls_bound` + --> $DIR/normalizes-to-is-not-productive.rs:28:19 + | +LL | fn impls_bound() { + | ^^^^^ required by this bound in `impls_bound` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/next-solver/cycles/normalizes-to-is-not-productive.next.stderr b/tests/ui/traits/next-solver/cycles/normalizes-to-is-not-productive.next.stderr new file mode 100644 index 000000000000..d888fbf9db18 --- /dev/null +++ b/tests/ui/traits/next-solver/cycles/normalizes-to-is-not-productive.next.stderr @@ -0,0 +1,31 @@ +error[E0277]: the trait bound `Foo: Bound` is not satisfied + --> $DIR/normalizes-to-is-not-productive.rs:43:31 + | +LL | >::Assoc: Bound, + | ^^^^^ the trait `Bound` is not implemented for `Foo` + | + = help: the trait `Bound` is implemented for `u32` +note: required for `Foo` to implement `Trait` + --> $DIR/normalizes-to-is-not-productive.rs:24:19 + | +LL | impl Trait for T { + | ----- ^^^^^^^^ ^ + | | + | unsatisfied trait bound introduced here + +error[E0277]: the trait bound `Foo: Bound` is not satisfied + --> $DIR/normalizes-to-is-not-productive.rs:48:19 + | +LL | impls_bound::(); + | ^^^ the trait `Bound` is not implemented for `Foo` + | + = help: the trait `Bound` is implemented for `u32` +note: required by a bound in `impls_bound` + --> $DIR/normalizes-to-is-not-productive.rs:28:19 + | +LL | fn impls_bound() { + | ^^^^^ required by this bound in `impls_bound` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/next-solver/cycles/normalizes-to-is-not-productive.rs b/tests/ui/traits/next-solver/cycles/normalizes-to-is-not-productive.rs new file mode 100644 index 000000000000..ffbbecaf8957 --- /dev/null +++ b/tests/ui/traits/next-solver/cycles/normalizes-to-is-not-productive.rs @@ -0,0 +1,54 @@ +//@ ignore-compare-mode-next-solver (explicit) +//@ compile-flags: -Znext-solver + +// Make sure that stepping into impl where-clauses of `NormalizesTo` +// goals is unproductive. This must not compile, see the inline +// comments. + +trait Bound { + fn method(); +} +impl Bound for u32 { + fn method() {} +} +trait Trait { + type Assoc: Bound; +} + +struct Foo; + +impl Trait for Foo { + type Assoc = u32; +} +impl Trait for T { + type Assoc = T; +} + +fn impls_bound() { + T::method(); +} + +// The where-clause requires `Foo: Trait` to hold to be wf. +// If stepping into where-clauses during normalization is considered +// to be productive, this would be the case: +// +// - `Foo: Trait` +// - via blanket impls, requires `Foo: Bound` +// - via where-bound, requires `Foo eq >::Assoc` +// - normalize `>::Assoc` +// - via blanket impl, requires where-clause `Foo: Bound` -> cycle +fn generic() +where + >::Assoc: Bound, + //~^ ERROR the trait bound `Foo: Bound` is not satisfied +{ + // Requires proving `Foo: Bound` by normalizing + // `>::Assoc` to `Foo`. + impls_bound::(); + //~^ ERROR the trait bound `Foo: Bound` is not satisfied +} +fn main() { + // Requires proving `>::Assoc: Bound`. + // This is trivially true. + generic::(); +} diff --git a/tests/ui/traits/next-solver/cycles/normalizes-to-is-not-productive.stderr b/tests/ui/traits/next-solver/cycles/normalizes-to-is-not-productive.stderr new file mode 100644 index 000000000000..8901805a20f5 --- /dev/null +++ b/tests/ui/traits/next-solver/cycles/normalizes-to-is-not-productive.stderr @@ -0,0 +1,31 @@ +error[E0277]: the trait bound `Foo: Bound` is not satisfied + --> $DIR/normalizes-to-is-not-productive.rs:42:31 + | +LL | >::Assoc: Bound, + | ^^^^^ the trait `Bound` is not implemented for `Foo` + | + = help: the trait `Bound` is implemented for `u32` +note: required for `Foo` to implement `Trait` + --> $DIR/normalizes-to-is-not-productive.rs:23:19 + | +LL | impl Trait for T { + | ----- ^^^^^^^^ ^ + | | + | unsatisfied trait bound introduced here + +error[E0277]: the trait bound `Foo: Bound` is not satisfied + --> $DIR/normalizes-to-is-not-productive.rs:47:19 + | +LL | impls_bound::(); + | ^^^ the trait `Bound` is not implemented for `Foo` + | + = help: the trait `Bound` is implemented for `u32` +note: required by a bound in `impls_bound` + --> $DIR/normalizes-to-is-not-productive.rs:27:19 + | +LL | fn impls_bound() { + | ^^^^^ required by this bound in `impls_bound` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/next-solver/diagnostics/point-at-failing-nested.rs b/tests/ui/traits/next-solver/diagnostics/point-at-failing-nested.rs index 840a4eb648c5..6da08619b47a 100644 --- a/tests/ui/traits/next-solver/diagnostics/point-at-failing-nested.rs +++ b/tests/ui/traits/next-solver/diagnostics/point-at-failing-nested.rs @@ -20,5 +20,5 @@ impl Constrain for () { fn needs_foo() {} fn main() { needs_foo::<()>(); - //~^ the trait bound `(): Foo` is not satisfied + //~^ ERROR the trait bound `(): Foo` is not satisfied } diff --git a/tests/ui/traits/next-solver/gat-wf.rs b/tests/ui/traits/next-solver/gat-wf.rs index ff6e2665ef3e..cd4b96b3a583 100644 --- a/tests/ui/traits/next-solver/gat-wf.rs +++ b/tests/ui/traits/next-solver/gat-wf.rs @@ -10,7 +10,7 @@ trait Foo { } impl Foo for &() { - type T<'a> = (); //~ the type `&()` does not fulfill the required lifetime + type T<'a> = (); //~ ERROR the type `&()` does not fulfill the required lifetime } fn main() {} diff --git a/tests/ui/traits/next-solver/more-object-bound.rs b/tests/ui/traits/next-solver/more-object-bound.rs index 3d3fdc926f65..1dad1903a649 100644 --- a/tests/ui/traits/next-solver/more-object-bound.rs +++ b/tests/ui/traits/next-solver/more-object-bound.rs @@ -10,7 +10,7 @@ trait Trait: SuperTrait::B> {} fn transmute(x: A) -> B { foo::>(x) - //~^ ERROR type mismatch resolving ` as SuperTrait>::A == B` + //~^ ERROR type mismatch resolving `A == B` } fn foo(x: T::A) -> B diff --git a/tests/ui/traits/next-solver/more-object-bound.stderr b/tests/ui/traits/next-solver/more-object-bound.stderr index 39849d4c865e..d04376cc9c64 100644 --- a/tests/ui/traits/next-solver/more-object-bound.stderr +++ b/tests/ui/traits/next-solver/more-object-bound.stderr @@ -1,17 +1,9 @@ -error[E0271]: type mismatch resolving ` as SuperTrait>::A == B` +error[E0271]: type mismatch resolving `A == B` --> $DIR/more-object-bound.rs:12:5 | -LL | fn transmute(x: A) -> B { - | - - expected type parameter - | | - | found type parameter LL | foo::>(x) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected type parameter `B`, found type parameter `A` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ | - = note: expected type parameter `B` - found type parameter `A` - = 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 = note: required because it appears within the type `dyn Trait` note: required by a bound in `foo` --> $DIR/more-object-bound.rs:18:8 diff --git a/tests/ui/traits/next-solver/normalize/normalize-param-env-2.stderr b/tests/ui/traits/next-solver/normalize/normalize-param-env-2.stderr index 74a0a90885da..d179c8059623 100644 --- a/tests/ui/traits/next-solver/normalize/normalize-param-env-2.stderr +++ b/tests/ui/traits/next-solver/normalize/normalize-param-env-2.stderr @@ -4,14 +4,14 @@ error[E0275]: overflow evaluating the requirement `<() as A>::Assoc: A` LL | Self::Assoc: A, | ^^^^ | -note: the requirement `<() as A>::Assoc: A` appears on the `impl`'s method `f` but not on the corresponding trait's method +note: the requirement `<() as A>::Assoc: A` appears on the `impl`'s associated function `f` but not on the corresponding trait's associated function --> $DIR/normalize-param-env-2.rs:12:8 | LL | trait A { | - in this trait ... LL | fn f() - | ^ this trait's method doesn't have the requirement `<() as A>::Assoc: A` + | ^ this trait's associated function doesn't have the requirement `<() as A>::Assoc: A` error[E0275]: overflow evaluating the requirement `<() as A>::Assoc: A` --> $DIR/normalize-param-env-2.rs:24:22 diff --git a/tests/ui/traits/next-solver/object-soundness-requires-generalization.rs b/tests/ui/traits/next-solver/object-soundness-requires-generalization.rs index 11a2617ad427..3ef6bea4fd5c 100644 --- a/tests/ui/traits/next-solver/object-soundness-requires-generalization.rs +++ b/tests/ui/traits/next-solver/object-soundness-requires-generalization.rs @@ -1,5 +1,5 @@ //@ compile-flags: -Znext-solver -//@ ignore-test +//@ ignore-test (see #114196) trait Trait { type Gat<'lt>; diff --git a/tests/ui/traits/next-solver/opaques/ambig-in-mir-typeck.rs b/tests/ui/traits/next-solver/opaques/ambig-in-mir-typeck.rs index e5208e3e47d0..198e6199e92c 100644 --- a/tests/ui/traits/next-solver/opaques/ambig-in-mir-typeck.rs +++ b/tests/ui/traits/next-solver/opaques/ambig-in-mir-typeck.rs @@ -1,7 +1,8 @@ // Regression test for #132335. This previously ICE'd due to ambiguity // in MIR typeck. -//@ compile-flags: -Znext-solver=globally --crate-type lib --edition=2018 +//@ compile-flags: -Znext-solver=globally --crate-type lib +//@ edition: 2018 //@ check-pass use core::future::Future; use core::pin::Pin; diff --git a/tests/ui/traits/next-solver/opaques/revealing-use-in-nested-body.rs b/tests/ui/traits/next-solver/opaques/revealing-use-in-nested-body.rs index 8388751fea64..b79926eebda3 100644 --- a/tests/ui/traits/next-solver/opaques/revealing-use-in-nested-body.rs +++ b/tests/ui/traits/next-solver/opaques/revealing-use-in-nested-body.rs @@ -3,7 +3,7 @@ // of the async block. This caused borrowck of the recursive // call to ICE. -//@ compile-flags: --edition=2021 +//@ edition: 2021 //@ check-pass async fn test() { Box::pin(test()).await; diff --git a/tests/ui/traits/next-solver/overflow/recursive-self-normalization-2.rs b/tests/ui/traits/next-solver/overflow/recursive-self-normalization-2.rs index 94a9484ecdcf..b2a8c8cb4ae6 100644 --- a/tests/ui/traits/next-solver/overflow/recursive-self-normalization-2.rs +++ b/tests/ui/traits/next-solver/overflow/recursive-self-normalization-2.rs @@ -13,7 +13,7 @@ fn needs_bar() {} fn test::Assoc2> + Foo2::Assoc1>>() { needs_bar::(); - //~^ ERROR the trait bound `::Assoc1: Bar` is not satisfied + //~^ ERROR the trait bound `::Assoc2: Bar` is not satisfied } fn main() {} diff --git a/tests/ui/traits/next-solver/overflow/recursive-self-normalization-2.stderr b/tests/ui/traits/next-solver/overflow/recursive-self-normalization-2.stderr index 6f5111a6193c..c4be47e3520d 100644 --- a/tests/ui/traits/next-solver/overflow/recursive-self-normalization-2.stderr +++ b/tests/ui/traits/next-solver/overflow/recursive-self-normalization-2.stderr @@ -1,8 +1,8 @@ -error[E0277]: the trait bound `::Assoc1: Bar` is not satisfied +error[E0277]: the trait bound `::Assoc2: Bar` is not satisfied --> $DIR/recursive-self-normalization-2.rs:15:17 | LL | needs_bar::(); - | ^^^^^^^^^ the trait `Bar` is not implemented for `::Assoc1` + | ^^^^^^^^^ the trait `Bar` is not implemented for `::Assoc2` | note: required by a bound in `needs_bar` --> $DIR/recursive-self-normalization-2.rs:12:17 @@ -11,7 +11,7 @@ LL | fn needs_bar() {} | ^^^ required by this bound in `needs_bar` help: consider further restricting the associated type | -LL | fn test::Assoc2> + Foo2::Assoc1>>() where ::Assoc1: Bar { +LL | fn test::Assoc2> + Foo2::Assoc1>>() where ::Assoc2: Bar { | ++++++++++++++++++++++++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/traits/next-solver/supertrait-alias-1.rs b/tests/ui/traits/next-solver/supertrait-alias-1.rs new file mode 100644 index 000000000000..579a44677c2e --- /dev/null +++ b/tests/ui/traits/next-solver/supertrait-alias-1.rs @@ -0,0 +1,22 @@ +//@ compile-flags: -Znext-solver +//@ check-pass + +// Regression test for . +// Tests that we don't try to replace `::Output` when replacing projections in the +// required bounds for `dyn Trait`, b/c `V` is not relevant to the dyn type, which we were +// previously encountering b/c we were walking into the existential projection bounds of the dyn +// type itself. + +pub trait Trait: Super {} + +pub trait Super { + type Output; +} + +fn bound() {} + +fn visit_simd_operator() { + bound::::Output>>(); +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/supertrait-alias-2.rs b/tests/ui/traits/next-solver/supertrait-alias-2.rs new file mode 100644 index 000000000000..a0f3e038dca6 --- /dev/null +++ b/tests/ui/traits/next-solver/supertrait-alias-2.rs @@ -0,0 +1,25 @@ +//@ compile-flags: -Znext-solver +//@ check-pass + +// Regression test for . +// Tests that we don't try to replace `::Assoc` when replacing projections in the +// required bounds for `dyn Foo`, b/c `T` is not relevant to the dyn type, which we were +// encountering when walking through the elaborated supertraits of `dyn Foo`. + +trait Other {} + +trait Foo>: Other<>::Assoc> { + type Assoc; +} + +impl Foo for T { + type Assoc = (); +} + +impl Other<()> for T {} + +fn is_foo + ?Sized>() {} + +fn main() { + is_foo::>(); +} diff --git a/tests/ui/traits/next-solver/supertrait-alias-3.rs b/tests/ui/traits/next-solver/supertrait-alias-3.rs new file mode 100644 index 000000000000..78182bbc4156 --- /dev/null +++ b/tests/ui/traits/next-solver/supertrait-alias-3.rs @@ -0,0 +1,32 @@ +//@ compile-flags: -Znext-solver +//@ check-pass + +// Regression test for . +// Exercises a case where structural equality is insufficient when replacing projections in a dyn's +// bounds. In this case, the bound will contain `:Assoc>::Assoc`, but +// the existential projections from the dyn will have `>::Assoc` because as an +// optimization we eagerly normalize aliases in goals. + +trait Other {} +impl Other for T {} + +trait Super { + type Assoc; +} + +trait Mirror { + type Assoc; +} +impl Mirror for T { + type Assoc = T; +} + +trait Foo: Super<::Assoc, Assoc = A> { + type FooAssoc: Other<::Assoc>>::Assoc>; +} + +fn is_foo + ?Sized, T, U>() {} + +fn main() { + is_foo::, _, _>(); +} diff --git a/tests/ui/traits/next-solver/supertrait-alias-4.rs b/tests/ui/traits/next-solver/supertrait-alias-4.rs new file mode 100644 index 000000000000..919a768fcf28 --- /dev/null +++ b/tests/ui/traits/next-solver/supertrait-alias-4.rs @@ -0,0 +1,24 @@ +//@ compile-flags: -Znext-solver +//@ check-pass + +// Exercises the ambiguity that comes from replacing the associated types within the bounds +// that are required for a `impl Trait for dyn Trait` built-in object impl to hold. + +trait Sup { + type Assoc; +} + +trait Foo: Sup + Sup { + type Other: Bar<>::Assoc>; +} + +trait Bar {} +impl Bar for () {} + +fn foo(x: &(impl Foo + ?Sized)) {} + +fn main() { + let x: &dyn Foo<_, _, Other = ()> = todo!(); + foo(x); + let y: &dyn Foo = x; +} diff --git a/tests/ui/traits/non_lifetime_binders/diagnostic-hir-wf-check.rs b/tests/ui/traits/non_lifetime_binders/diagnostic-hir-wf-check.rs new file mode 100644 index 000000000000..74c23a59bee9 --- /dev/null +++ b/tests/ui/traits/non_lifetime_binders/diagnostic-hir-wf-check.rs @@ -0,0 +1,18 @@ +// Make sure not to construct predicates with escaping bound vars in `diagnostic_hir_wf_check`. +// Regression test for . + +#![feature(non_lifetime_binders)] +//~^ WARN the feature `non_lifetime_binders` is incomplete + +trait A {} +impl A for () {} + +trait B {} +struct W(T); + +fn b() -> (W<()>, impl for A) { (W(()), ()) } +//~^ ERROR the trait bound `(): B` is not satisfied +//~| ERROR the trait bound `(): B` is not satisfied +//~| ERROR the trait bound `(): B` is not satisfied + +fn main() {} diff --git a/tests/ui/traits/non_lifetime_binders/diagnostic-hir-wf-check.stderr b/tests/ui/traits/non_lifetime_binders/diagnostic-hir-wf-check.stderr new file mode 100644 index 000000000000..df99f4a67abb --- /dev/null +++ b/tests/ui/traits/non_lifetime_binders/diagnostic-hir-wf-check.stderr @@ -0,0 +1,65 @@ +warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/diagnostic-hir-wf-check.rs:4:12 + | +LL | #![feature(non_lifetime_binders)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #108185 for more information + = note: `#[warn(incomplete_features)]` on by default + +error[E0277]: the trait bound `(): B` is not satisfied + --> $DIR/diagnostic-hir-wf-check.rs:13:12 + | +LL | fn b() -> (W<()>, impl for A) { (W(()), ()) } + | ^^^^^ the trait `B` is not implemented for `()` + | +help: this trait has no implementations, consider adding one + --> $DIR/diagnostic-hir-wf-check.rs:10:1 + | +LL | trait B {} + | ^^^^^^^ +note: required by a bound in `W` + --> $DIR/diagnostic-hir-wf-check.rs:11:13 + | +LL | struct W(T); + | ^ required by this bound in `W` + +error[E0277]: the trait bound `(): B` is not satisfied + --> $DIR/diagnostic-hir-wf-check.rs:13:42 + | +LL | fn b() -> (W<()>, impl for A) { (W(()), ()) } + | - ^^ the trait `B` is not implemented for `()` + | | + | required by a bound introduced by this call + | +help: this trait has no implementations, consider adding one + --> $DIR/diagnostic-hir-wf-check.rs:10:1 + | +LL | trait B {} + | ^^^^^^^ +note: required by a bound in `W` + --> $DIR/diagnostic-hir-wf-check.rs:11:13 + | +LL | struct W(T); + | ^ required by this bound in `W` + +error[E0277]: the trait bound `(): B` is not satisfied + --> $DIR/diagnostic-hir-wf-check.rs:13:40 + | +LL | fn b() -> (W<()>, impl for A) { (W(()), ()) } + | ^^^^^ the trait `B` is not implemented for `()` + | +help: this trait has no implementations, consider adding one + --> $DIR/diagnostic-hir-wf-check.rs:10:1 + | +LL | trait B {} + | ^^^^^^^ +note: required by a bound in `W` + --> $DIR/diagnostic-hir-wf-check.rs:11:13 + | +LL | struct W(T); + | ^ required by this bound in `W` + +error: aborting due to 3 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/non_lifetime_binders/type-alias-impl-trait/non-lifetime-binder-in-constraint.rs b/tests/ui/traits/non_lifetime_binders/type-alias-impl-trait/non-lifetime-binder-in-constraint.rs index 2a3017885255..aff81207a930 100644 --- a/tests/ui/traits/non_lifetime_binders/type-alias-impl-trait/non-lifetime-binder-in-constraint.rs +++ b/tests/ui/traits/non_lifetime_binders/type-alias-impl-trait/non-lifetime-binder-in-constraint.rs @@ -6,7 +6,7 @@ trait Trait {} fn produce() -> impl for Trait<(), Assoc = impl Trait> { //~^ ERROR associated type `Assoc` not found for `Trait` //~| ERROR associated type `Assoc` not found for `Trait` - //~| the trait bound `{integer}: Trait<()>` is not satisfied + //~| ERROR the trait bound `{integer}: Trait<()>` is not satisfied //~| ERROR cannot capture late-bound type parameter in nested `impl Trait` 16 } diff --git a/tests/ui/traits/object/suggestion-trait-object-issue-139174.rs b/tests/ui/traits/object/suggestion-trait-object-issue-139174.rs index f8fa410b7d49..50851a5b0f84 100644 --- a/tests/ui/traits/object/suggestion-trait-object-issue-139174.rs +++ b/tests/ui/traits/object/suggestion-trait-object-issue-139174.rs @@ -1,4 +1,4 @@ -//@compile-flags: --edition 2021 +//@ edition: 2021 fn f<'a>(x: Box Option>) -> usize { //~^ ERROR expected trait, found builtin type `usize` diff --git a/tests/ui/traits/object/vs-lifetime.rs b/tests/ui/traits/object/vs-lifetime.rs index d3e6c0b217c9..52385b263843 100644 --- a/tests/ui/traits/object/vs-lifetime.rs +++ b/tests/ui/traits/object/vs-lifetime.rs @@ -7,7 +7,7 @@ fn main() { // `'static` is a lifetime argument, `'static +` is a type argument let _: S<'static, u8>; let _: S<'static, dyn 'static +>; - //~^ at least one trait is required for an object type + //~^ ERROR at least one trait is required for an object type let _: S<'static, 'static>; //~^ ERROR struct takes 1 lifetime argument but 2 lifetime arguments were supplied //~| ERROR struct takes 1 generic argument but 0 generic arguments were supplied diff --git a/tests/ui/traits/trivial-unsized-projection-2.bad.stderr b/tests/ui/traits/trivial-unsized-projection-2.bad.stderr new file mode 100644 index 000000000000..bf8d3c40cf65 --- /dev/null +++ b/tests/ui/traits/trivial-unsized-projection-2.bad.stderr @@ -0,0 +1,54 @@ +error[E0277]: the size for values of type `[()]` cannot be known at compilation time + --> $DIR/trivial-unsized-projection-2.rs:22:12 + | +LL | const FOO: ::Assert = todo!(); + | ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: within `Tail`, the trait `Sized` is not implemented for `[()]` +note: required because it appears within the type `Tail` + --> $DIR/trivial-unsized-projection-2.rs:17:8 + | +LL | struct Tail([()]); + | ^^^^ +note: required by a bound in `Bad::Assert` + --> $DIR/trivial-unsized-projection-2.rs:14:15 + | +LL | type Assert + | ------ required by a bound in this associated type +LL | where +LL | Self: Sized; + | ^^^^^ required by this bound in `Bad::Assert` +help: consider relaxing the implicit `Sized` restriction + | +LL | type Assert: ?Sized + | ++++++++ + +error[E0277]: the size for values of type `[()]` cannot be known at compilation time + --> $DIR/trivial-unsized-projection-2.rs:22:12 + | +LL | const FOO: ::Assert = todo!(); + | ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: within `Tail`, the trait `Sized` is not implemented for `[()]` +note: required because it appears within the type `Tail` + --> $DIR/trivial-unsized-projection-2.rs:17:8 + | +LL | struct Tail([()]); + | ^^^^ +note: required by a bound in `Bad::Assert` + --> $DIR/trivial-unsized-projection-2.rs:14:15 + | +LL | type Assert + | ------ required by a bound in this associated type +LL | where +LL | Self: Sized; + | ^^^^^ required by this bound in `Bad::Assert` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider relaxing the implicit `Sized` restriction + | +LL | type Assert: ?Sized + | ++++++++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/trivial-unsized-projection-2.bad_new.stderr b/tests/ui/traits/trivial-unsized-projection-2.bad_new.stderr new file mode 100644 index 000000000000..bf8d3c40cf65 --- /dev/null +++ b/tests/ui/traits/trivial-unsized-projection-2.bad_new.stderr @@ -0,0 +1,54 @@ +error[E0277]: the size for values of type `[()]` cannot be known at compilation time + --> $DIR/trivial-unsized-projection-2.rs:22:12 + | +LL | const FOO: ::Assert = todo!(); + | ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: within `Tail`, the trait `Sized` is not implemented for `[()]` +note: required because it appears within the type `Tail` + --> $DIR/trivial-unsized-projection-2.rs:17:8 + | +LL | struct Tail([()]); + | ^^^^ +note: required by a bound in `Bad::Assert` + --> $DIR/trivial-unsized-projection-2.rs:14:15 + | +LL | type Assert + | ------ required by a bound in this associated type +LL | where +LL | Self: Sized; + | ^^^^^ required by this bound in `Bad::Assert` +help: consider relaxing the implicit `Sized` restriction + | +LL | type Assert: ?Sized + | ++++++++ + +error[E0277]: the size for values of type `[()]` cannot be known at compilation time + --> $DIR/trivial-unsized-projection-2.rs:22:12 + | +LL | const FOO: ::Assert = todo!(); + | ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: within `Tail`, the trait `Sized` is not implemented for `[()]` +note: required because it appears within the type `Tail` + --> $DIR/trivial-unsized-projection-2.rs:17:8 + | +LL | struct Tail([()]); + | ^^^^ +note: required by a bound in `Bad::Assert` + --> $DIR/trivial-unsized-projection-2.rs:14:15 + | +LL | type Assert + | ------ required by a bound in this associated type +LL | where +LL | Self: Sized; + | ^^^^^ required by this bound in `Bad::Assert` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider relaxing the implicit `Sized` restriction + | +LL | type Assert: ?Sized + | ++++++++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/trivial-unsized-projection-2.rs b/tests/ui/traits/trivial-unsized-projection-2.rs new file mode 100644 index 000000000000..af4e12f6f900 --- /dev/null +++ b/tests/ui/traits/trivial-unsized-projection-2.rs @@ -0,0 +1,34 @@ +//@ revisions: good bad good_new bad_new +//@[good_new] compile-flags: -Znext-solver +//@[bad_new] compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[good] check-pass +//@[good_new] check-pass + +#![feature(trivial_bounds)] +#![allow(trivial_bounds)] + +trait Bad { + type Assert + where + Self: Sized; +} + +struct Tail([()]); + +impl Bad for Tail {} + +#[cfg(any(bad, bad_new))] +const FOO: ::Assert = todo!(); +//[bad]~^ ERROR the size for values of type `[()]` cannot be known at compilation time +//[bad]~| ERROR the size for values of type `[()]` cannot be known at compilation time +//[bad_new]~^^^ ERROR the size for values of type `[()]` cannot be known at compilation time +//[bad_new]~| ERROR the size for values of type `[()]` cannot be known at compilation time + +#[cfg(any(good, good_new))] +// Well-formed in trivially false param-env +fn foo() where Tail: Sized { + let _: ::Assert; +} + +fn main() {} diff --git a/tests/ui/traits/trivial-unsized-projection-in-coherence.rs b/tests/ui/traits/trivial-unsized-projection-in-coherence.rs new file mode 100644 index 000000000000..4407d544b4ef --- /dev/null +++ b/tests/ui/traits/trivial-unsized-projection-in-coherence.rs @@ -0,0 +1,45 @@ +// Make sure we don't treat missing associated items as rigid +// during coherence, even if we know they've got an impossible +// `Sized`-bound. As we check whether the self type is definitely +// not `Sized` outside of coherence, this check can be incomplete. +// +// In this test we only use `impl Overlap for T` to normalize +// the field of `MaybeUnsized` when checking whether it's +// definitely not `Sized`. However, for `MaybeUnsized` we +// could also use `impl Overlap for u32` for normalization, which +// would result in a `Sized` type. cc #139000 + +struct MaybeUnsized, U>(>::MaybeUnsized); + +trait ReqSized { + type Missing1 + where + Self: Sized; + type Missing2 + where + Self: Sized; +} +impl ReqSized for MaybeUnsized {} + +struct W(T); +trait Eq {} +impl Eq for W {} + +trait RelateReqSized {} +impl RelateReqSized for T where W: Eq {} + +trait Overlap { + type MaybeUnsized: ?Sized; +} +impl Overlap for T { + type MaybeUnsized = str; +} +impl Overlap for u32 +//~^ ERROR conflicting implementations of trait `Overlap` for type `u32` +where + MaybeUnsized: RelateReqSized, +{ + type MaybeUnsized = u32; +} + +fn main() {} diff --git a/tests/ui/traits/trivial-unsized-projection-in-coherence.stderr b/tests/ui/traits/trivial-unsized-projection-in-coherence.stderr new file mode 100644 index 000000000000..52fca9479ca4 --- /dev/null +++ b/tests/ui/traits/trivial-unsized-projection-in-coherence.stderr @@ -0,0 +1,15 @@ +error[E0119]: conflicting implementations of trait `Overlap` for type `u32` + --> $DIR/trivial-unsized-projection-in-coherence.rs:37:1 + | +LL | impl Overlap for T { + | -------------------------- first implementation here +... +LL | / impl Overlap for u32 +LL | | +LL | | where +LL | | MaybeUnsized: RelateReqSized, + | |_________________________________________^ conflicting implementation for `u32` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/traits/trivial-unsized-projection.bad.stderr b/tests/ui/traits/trivial-unsized-projection.bad.stderr new file mode 100644 index 000000000000..4aea63329b36 --- /dev/null +++ b/tests/ui/traits/trivial-unsized-projection.bad.stderr @@ -0,0 +1,44 @@ +error[E0277]: the size for values of type `[()]` cannot be known at compilation time + --> $DIR/trivial-unsized-projection.rs:20:12 + | +LL | const FOO: <[()] as Bad>::Assert = todo!(); + | ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[()]` +note: required by a bound in `Bad::Assert` + --> $DIR/trivial-unsized-projection.rs:14:15 + | +LL | type Assert + | ------ required by a bound in this associated type +LL | where +LL | Self: Sized; + | ^^^^^ required by this bound in `Bad::Assert` +help: consider relaxing the implicit `Sized` restriction + | +LL | type Assert: ?Sized + | ++++++++ + +error[E0277]: the size for values of type `[()]` cannot be known at compilation time + --> $DIR/trivial-unsized-projection.rs:20:12 + | +LL | const FOO: <[()] as Bad>::Assert = todo!(); + | ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[()]` +note: required by a bound in `Bad::Assert` + --> $DIR/trivial-unsized-projection.rs:14:15 + | +LL | type Assert + | ------ required by a bound in this associated type +LL | where +LL | Self: Sized; + | ^^^^^ required by this bound in `Bad::Assert` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider relaxing the implicit `Sized` restriction + | +LL | type Assert: ?Sized + | ++++++++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/trivial-unsized-projection.bad_new.stderr b/tests/ui/traits/trivial-unsized-projection.bad_new.stderr new file mode 100644 index 000000000000..4aea63329b36 --- /dev/null +++ b/tests/ui/traits/trivial-unsized-projection.bad_new.stderr @@ -0,0 +1,44 @@ +error[E0277]: the size for values of type `[()]` cannot be known at compilation time + --> $DIR/trivial-unsized-projection.rs:20:12 + | +LL | const FOO: <[()] as Bad>::Assert = todo!(); + | ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[()]` +note: required by a bound in `Bad::Assert` + --> $DIR/trivial-unsized-projection.rs:14:15 + | +LL | type Assert + | ------ required by a bound in this associated type +LL | where +LL | Self: Sized; + | ^^^^^ required by this bound in `Bad::Assert` +help: consider relaxing the implicit `Sized` restriction + | +LL | type Assert: ?Sized + | ++++++++ + +error[E0277]: the size for values of type `[()]` cannot be known at compilation time + --> $DIR/trivial-unsized-projection.rs:20:12 + | +LL | const FOO: <[()] as Bad>::Assert = todo!(); + | ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[()]` +note: required by a bound in `Bad::Assert` + --> $DIR/trivial-unsized-projection.rs:14:15 + | +LL | type Assert + | ------ required by a bound in this associated type +LL | where +LL | Self: Sized; + | ^^^^^ required by this bound in `Bad::Assert` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider relaxing the implicit `Sized` restriction + | +LL | type Assert: ?Sized + | ++++++++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/trivial-unsized-projection.rs b/tests/ui/traits/trivial-unsized-projection.rs new file mode 100644 index 000000000000..62ff25fb7ac0 --- /dev/null +++ b/tests/ui/traits/trivial-unsized-projection.rs @@ -0,0 +1,32 @@ +//@ revisions: good bad good_new bad_new +//@[good_new] compile-flags: -Znext-solver +//@[bad_new] compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[good] check-pass +//@[good_new] check-pass + +#![feature(trivial_bounds)] +#![allow(trivial_bounds)] + +trait Bad { + type Assert + where + Self: Sized; +} + +impl Bad for [()] {} + +#[cfg(any(bad, bad_new))] +const FOO: <[()] as Bad>::Assert = todo!(); +//[bad]~^ ERROR the size for values of type `[()]` cannot be known at compilation time +//[bad]~| ERROR the size for values of type `[()]` cannot be known at compilation time +//[bad_new]~^^^ ERROR the size for values of type `[()]` cannot be known at compilation time +//[bad_new]~| ERROR the size for values of type `[()]` cannot be known at compilation time + +#[cfg(any(good, good_new))] +// Well-formed in trivially false param-env +fn foo() where [()]: Sized { + let _: <[()] as Bad>::Assert; +} + +fn main() {} diff --git a/tests/ui/traits/winnowing/global-where-bound-region-constraints-2.rs b/tests/ui/traits/winnowing/global-where-bound-region-constraints-2.rs new file mode 100644 index 000000000000..d422605a2923 --- /dev/null +++ b/tests/ui/traits/winnowing/global-where-bound-region-constraints-2.rs @@ -0,0 +1,33 @@ +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver +//@ check-pass + +// Regression test for trait-system-refactor-initiative#172. +// +// In this test the global where-bound simply constrains the +// object lifetime bound to 'static while the builtin impl +// ends up also emitting a `dyn Any: 'static` type outlives +// constraint. This previously resulted in ambiguity. We now +// always prefer the impl. + +pub trait Any: 'static {} + +pub trait Downcast: Any +where + T: Any, +{ +} + +// elided object lifetime: `dyn Any + 'static` +impl dyn Any { + pub fn is(&self) + where + T: Any, + // elaboration adds global where-clause `dyn Any + 'static: Any` + Self: Downcast, + { + } +} + +fn main() {} diff --git a/tests/ui/traits/winnowing/global-where-bound-region-constraints.rs b/tests/ui/traits/winnowing/global-where-bound-region-constraints.rs new file mode 100644 index 000000000000..3bc8b0438bf8 --- /dev/null +++ b/tests/ui/traits/winnowing/global-where-bound-region-constraints.rs @@ -0,0 +1,29 @@ +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver +//@ check-pass + +// Regression test for trait-system-refactor-initiative#172. +// +// The next-generation trait solver previously simply tried +// to merge the global where-bounds with the impl candidates. +// This caused ambiguity in case the where-bound had stricter +// region requirements than the impl. + +trait Trait {} +struct Foo<'a, 'b>(&'a (), &'b ()); +impl<'a> Trait for Foo<'a, 'static> {} + +fn impls_trait() {} +fn foo() +where + Foo<'static, 'static>: Trait, +{ + // impl requires `'1 to be 'static + // global where-bound requires both '0 and '1 to be 'static + // + // we always prefer the impl here. + impls_trait::>(); +} + +fn main() {} diff --git a/tests/ui/traits/winnowing/norm-where-bound-gt-alias-bound.rs b/tests/ui/traits/winnowing/norm-where-bound-gt-alias-bound.rs new file mode 100644 index 000000000000..cdfb0ee45af4 --- /dev/null +++ b/tests/ui/traits/winnowing/norm-where-bound-gt-alias-bound.rs @@ -0,0 +1,29 @@ +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver +//@ check-pass + +// Make sure we prefer the `I::IntoIterator: Iterator` +// where-bound over the `I::Intoiterator: Iterator` +// alias-bound. + +trait Iterator { + type Item; +} + +trait IntoIterator { + type Item; + type IntoIter: Iterator; +} + +fn normalize>() {} + +fn foo() +where + I: IntoIterator, + I::IntoIter: Iterator, +{ + normalize::(); +} + +fn main() {} diff --git a/tests/ui/transmutability/issue-101739-1.rs b/tests/ui/transmutability/issue-101739-1.rs index 4fde120e2be8..b801e2355404 100644 --- a/tests/ui/transmutability/issue-101739-1.rs +++ b/tests/ui/transmutability/issue-101739-1.rs @@ -6,7 +6,7 @@ mod assert { pub fn is_transmutable() where Dst: TransmuteFrom, //~ ERROR cannot find type `Dst` in this scope - //~| the constant `ASSUME_ALIGNMENT` is not of type `Assume` + //~| ERROR the constant `ASSUME_ALIGNMENT` is not of type `Assume` { } } diff --git a/tests/ui/transmutability/malformed-program-gracefulness/unknown_dst.rs b/tests/ui/transmutability/malformed-program-gracefulness/unknown_dst.rs index b8828c59d355..e004f2cf4feb 100644 --- a/tests/ui/transmutability/malformed-program-gracefulness/unknown_dst.rs +++ b/tests/ui/transmutability/malformed-program-gracefulness/unknown_dst.rs @@ -15,5 +15,5 @@ mod assert { fn should_gracefully_handle_unknown_dst() { struct Src; - assert::is_transmutable::(); //~ cannot find type + assert::is_transmutable::(); //~ ERROR cannot find type } diff --git a/tests/ui/transmutability/malformed-program-gracefulness/unknown_dst_field.rs b/tests/ui/transmutability/malformed-program-gracefulness/unknown_dst_field.rs index 2285d2f532ee..081d1bf11ec0 100644 --- a/tests/ui/transmutability/malformed-program-gracefulness/unknown_dst_field.rs +++ b/tests/ui/transmutability/malformed-program-gracefulness/unknown_dst_field.rs @@ -15,12 +15,12 @@ mod assert { fn should_gracefully_handle_unknown_dst_field() { #[repr(C)] struct Src; - #[repr(C)] struct Dst(Missing); //~ cannot find type + #[repr(C)] struct Dst(Missing); //~ ERROR cannot find type assert::is_transmutable::(); //~ ERROR cannot be safely transmuted } fn should_gracefully_handle_unknown_dst_ref_field() { #[repr(C)] struct Src(&'static Src); - #[repr(C)] struct Dst(&'static Missing); //~ cannot find type + #[repr(C)] struct Dst(&'static Missing); //~ ERROR cannot find type assert::is_transmutable::(); //~ ERROR cannot be safely transmuted } diff --git a/tests/ui/transmutability/malformed-program-gracefulness/unknown_src.rs b/tests/ui/transmutability/malformed-program-gracefulness/unknown_src.rs index 10ba7a61b872..0aca4acd0a32 100644 --- a/tests/ui/transmutability/malformed-program-gracefulness/unknown_src.rs +++ b/tests/ui/transmutability/malformed-program-gracefulness/unknown_src.rs @@ -15,5 +15,5 @@ mod assert { fn should_gracefully_handle_unknown_src() { #[repr(C)] struct Dst; - assert::is_transmutable::(); //~ cannot find type + assert::is_transmutable::(); //~ ERROR cannot find type } diff --git a/tests/ui/transmutability/malformed-program-gracefulness/unknown_src_field.rs b/tests/ui/transmutability/malformed-program-gracefulness/unknown_src_field.rs index 598e04971e28..ee09651d7410 100644 --- a/tests/ui/transmutability/malformed-program-gracefulness/unknown_src_field.rs +++ b/tests/ui/transmutability/malformed-program-gracefulness/unknown_src_field.rs @@ -14,13 +14,13 @@ mod assert { } fn should_gracefully_handle_unknown_src_field() { - #[repr(C)] struct Src(Missing); //~ cannot find type + #[repr(C)] struct Src(Missing); //~ ERROR cannot find type #[repr(C)] struct Dst(); assert::is_transmutable::(); //~ ERROR cannot be safely transmuted } fn should_gracefully_handle_unknown_src_ref_field() { - #[repr(C)] struct Src(&'static Missing); //~ cannot find type + #[repr(C)] struct Src(&'static Missing); //~ ERROR cannot find type #[repr(C)] struct Dst(&'static Dst); assert::is_transmutable::(); //~ ERROR cannot be safely transmuted } diff --git a/tests/ui/transmutability/transmute-higher-ranked.rs b/tests/ui/transmutability/transmute-higher-ranked.rs new file mode 100644 index 000000000000..f0fe02a7908e --- /dev/null +++ b/tests/ui/transmutability/transmute-higher-ranked.rs @@ -0,0 +1,18 @@ +// Ensure we don't ICE when transmuting higher-ranked types via a +// higher-ranked transmute goal. + +//@ check-pass + +#![feature(transmutability)] + +use std::mem::TransmuteFrom; + +pub fn transmute() +where + for<'a> &'a &'a i32: TransmuteFrom<&'a &'a u32>, +{ +} + +fn main() { + transmute(); +} diff --git a/tests/ui/try-block/issue-45124.rs b/tests/ui/try-block/issue-45124.rs index e9e0e767efa2..26e1736faaca 100644 --- a/tests/ui/try-block/issue-45124.rs +++ b/tests/ui/try-block/issue-45124.rs @@ -1,6 +1,6 @@ //@ run-pass #![allow(unreachable_code)] -//@ compile-flags: --edition 2018 +//@ edition: 2018 #![feature(try_blocks)] diff --git a/tests/ui/try-block/try-block-bad-lifetime.rs b/tests/ui/try-block/try-block-bad-lifetime.rs index bfff757a2df6..9b45b0d95594 100644 --- a/tests/ui/try-block/try-block-bad-lifetime.rs +++ b/tests/ui/try-block/try-block-bad-lifetime.rs @@ -1,4 +1,4 @@ -//@ compile-flags: --edition 2018 +//@ edition: 2018 #![feature(try_blocks)] diff --git a/tests/ui/try-block/try-block-bad-type.rs b/tests/ui/try-block/try-block-bad-type.rs index 71eb832dd4eb..00cd0af127c8 100644 --- a/tests/ui/try-block/try-block-bad-type.rs +++ b/tests/ui/try-block/try-block-bad-type.rs @@ -1,4 +1,4 @@ -//@ compile-flags: --edition 2018 +//@ edition: 2018 #![feature(try_blocks)] diff --git a/tests/ui/try-block/try-block-catch.rs b/tests/ui/try-block/try-block-catch.rs index c3aa442ba663..170d5bab3e50 100644 --- a/tests/ui/try-block/try-block-catch.rs +++ b/tests/ui/try-block/try-block-catch.rs @@ -1,4 +1,4 @@ -//@ compile-flags: --edition 2018 +//@ edition: 2018 #![feature(try_blocks)] diff --git a/tests/ui/try-block/try-block-in-edition2015.rs b/tests/ui/try-block/try-block-in-edition2015.rs index 423269df12d6..4ebe2d31b81d 100644 --- a/tests/ui/try-block/try-block-in-edition2015.rs +++ b/tests/ui/try-block/try-block-in-edition2015.rs @@ -1,4 +1,4 @@ -//@ compile-flags: --edition 2015 +//@ edition: 2015 pub fn main() { let try_result: Option<_> = try { diff --git a/tests/ui/try-block/try-block-in-match-arm.rs b/tests/ui/try-block/try-block-in-match-arm.rs index cecbf724916c..703b1c54bbb1 100644 --- a/tests/ui/try-block/try-block-in-match-arm.rs +++ b/tests/ui/try-block/try-block-in-match-arm.rs @@ -1,5 +1,5 @@ //@ check-pass -//@ compile-flags: --edition 2018 +//@ edition: 2018 #![feature(try_blocks)] diff --git a/tests/ui/try-block/try-block-in-match.rs b/tests/ui/try-block/try-block-in-match.rs index 5c62f41efdba..63a32000f625 100644 --- a/tests/ui/try-block/try-block-in-match.rs +++ b/tests/ui/try-block/try-block-in-match.rs @@ -1,5 +1,5 @@ //@ run-pass -//@ compile-flags: --edition 2018 +//@ edition: 2018 #![feature(try_blocks)] diff --git a/tests/ui/try-block/try-block-in-return.rs b/tests/ui/try-block/try-block-in-return.rs index ee5ca696b6d6..7dc023b90dbc 100644 --- a/tests/ui/try-block/try-block-in-return.rs +++ b/tests/ui/try-block/try-block-in-return.rs @@ -1,5 +1,5 @@ //@ run-pass -//@ compile-flags: --edition 2018 +//@ edition: 2018 #![feature(try_blocks)] diff --git a/tests/ui/try-block/try-block-in-while.rs b/tests/ui/try-block/try-block-in-while.rs index 88a97136c594..d6232546cea0 100644 --- a/tests/ui/try-block/try-block-in-while.rs +++ b/tests/ui/try-block/try-block-in-while.rs @@ -1,4 +1,4 @@ -//@ compile-flags: --edition 2018 +//@ edition: 2018 #![feature(try_blocks)] diff --git a/tests/ui/try-block/try-block-maybe-bad-lifetime.rs b/tests/ui/try-block/try-block-maybe-bad-lifetime.rs index 52ec0c44a059..14adee8944fa 100644 --- a/tests/ui/try-block/try-block-maybe-bad-lifetime.rs +++ b/tests/ui/try-block/try-block-maybe-bad-lifetime.rs @@ -1,4 +1,4 @@ -//@ compile-flags: --edition 2018 +//@ edition: 2018 #![feature(try_blocks)] diff --git a/tests/ui/try-block/try-block-opt-init.rs b/tests/ui/try-block/try-block-opt-init.rs index fbe7f90d0303..55ac5b4a37cc 100644 --- a/tests/ui/try-block/try-block-opt-init.rs +++ b/tests/ui/try-block/try-block-opt-init.rs @@ -1,4 +1,4 @@ -//@ compile-flags: --edition 2018 +//@ edition: 2018 #![feature(try_blocks)] diff --git a/tests/ui/try-block/try-block-type-error.rs b/tests/ui/try-block/try-block-type-error.rs index 79cdb7a2e48d..4e482b40140d 100644 --- a/tests/ui/try-block/try-block-type-error.rs +++ b/tests/ui/try-block/try-block-type-error.rs @@ -1,4 +1,4 @@ -//@ compile-flags: --edition 2018 +//@ edition: 2018 #![feature(try_blocks)] diff --git a/tests/ui/try-block/try-block-unreachable-code-lint.rs b/tests/ui/try-block/try-block-unreachable-code-lint.rs index 62c74b76d59c..9135882a57b2 100644 --- a/tests/ui/try-block/try-block-unreachable-code-lint.rs +++ b/tests/ui/try-block/try-block-unreachable-code-lint.rs @@ -1,6 +1,6 @@ // Test unreachable_code lint for `try {}` block ok-wrapping. See issues #54165, #63324. -//@ compile-flags: --edition 2018 +//@ edition: 2018 //@ check-pass #![feature(try_blocks)] #![warn(unreachable_code)] diff --git a/tests/ui/try-block/try-block-unused-delims.fixed b/tests/ui/try-block/try-block-unused-delims.fixed index 348eb8f79656..4769c45d38cc 100644 --- a/tests/ui/try-block/try-block-unused-delims.fixed +++ b/tests/ui/try-block/try-block-unused-delims.fixed @@ -1,5 +1,5 @@ //@ check-pass -//@ compile-flags: --edition 2018 +//@ edition: 2018 //@ run-rustfix #![feature(try_blocks)] diff --git a/tests/ui/try-block/try-block-unused-delims.rs b/tests/ui/try-block/try-block-unused-delims.rs index f119e1074f6e..0520d1d620f5 100644 --- a/tests/ui/try-block/try-block-unused-delims.rs +++ b/tests/ui/try-block/try-block-unused-delims.rs @@ -1,5 +1,5 @@ //@ check-pass -//@ compile-flags: --edition 2018 +//@ edition: 2018 //@ run-rustfix #![feature(try_blocks)] diff --git a/tests/ui/try-block/try-block.rs b/tests/ui/try-block/try-block.rs index 7520cbaad378..3fa0d2ba0f24 100644 --- a/tests/ui/try-block/try-block.rs +++ b/tests/ui/try-block/try-block.rs @@ -2,7 +2,7 @@ #![allow(non_camel_case_types)] #![allow(dead_code)] -//@ compile-flags: --edition 2018 +//@ edition: 2018 #![feature(try_blocks)] diff --git a/tests/ui/try-block/try-is-identifier-edition2015.rs b/tests/ui/try-block/try-is-identifier-edition2015.rs index 54bd049442fc..99f4d2068599 100644 --- a/tests/ui/try-block/try-is-identifier-edition2015.rs +++ b/tests/ui/try-block/try-is-identifier-edition2015.rs @@ -1,7 +1,7 @@ //@ run-pass #![allow(non_camel_case_types)] -//@ compile-flags: --edition 2015 +//@ edition: 2015 fn main() { let try = 2; diff --git a/tests/ui/type-alias-impl-trait/auto-trait-leakage2.rs b/tests/ui/type-alias-impl-trait/auto-trait-leakage2.rs index 6132eef0db5f..0b60640272b5 100644 --- a/tests/ui/type-alias-impl-trait/auto-trait-leakage2.rs +++ b/tests/ui/type-alias-impl-trait/auto-trait-leakage2.rs @@ -4,8 +4,8 @@ use std::rc::Rc; type Foo = impl std::fmt::Debug; //~ NOTE appears within the type -//~^ within this `Foo` -//~| expansion of desugaring +//~^ NOTE within this `Foo` +//~| NOTE expansion of desugaring #[define_opaque(Foo)] pub fn foo() -> Foo { @@ -13,8 +13,8 @@ pub fn foo() -> Foo { } fn is_send(_: T) {} -//~^ required by this bound -//~| required by a bound +//~^ NOTE required by this bound +//~| NOTE required by a bound fn main() { is_send(foo()); diff --git a/tests/ui/type-alias-impl-trait/constrain_in_projection.rs b/tests/ui/type-alias-impl-trait/constrain_in_projection.rs index 64b9c583ca2e..62a105611b08 100644 --- a/tests/ui/type-alias-impl-trait/constrain_in_projection.rs +++ b/tests/ui/type-alias-impl-trait/constrain_in_projection.rs @@ -23,8 +23,8 @@ impl Trait<()> for Foo { #[define_opaque(Bar)] fn bop() { let x = >::Assoc::default(); - //[current]~^ `Foo: Trait` is not satisfied - //[current]~| `Foo: Trait` is not satisfied + //[current]~^ ERROR `Foo: Trait` is not satisfied + //[current]~| ERROR `Foo: Trait` is not satisfied } fn main() {} diff --git a/tests/ui/type-alias-impl-trait/cross_inference_pattern_bug.rs b/tests/ui/type-alias-impl-trait/cross_inference_pattern_bug.rs index 4f3f6d37eff4..f69fd5747b65 100644 --- a/tests/ui/type-alias-impl-trait/cross_inference_pattern_bug.rs +++ b/tests/ui/type-alias-impl-trait/cross_inference_pattern_bug.rs @@ -1,4 +1,4 @@ -//@ compile-flags: --edition=2021 +//@ edition: 2021 //@ build-pass #![feature(type_alias_impl_trait)] diff --git a/tests/ui/type-alias-impl-trait/cross_inference_pattern_bug_no_type.rs b/tests/ui/type-alias-impl-trait/cross_inference_pattern_bug_no_type.rs index cad1cbf61a29..be8b7fa6a935 100644 --- a/tests/ui/type-alias-impl-trait/cross_inference_pattern_bug_no_type.rs +++ b/tests/ui/type-alias-impl-trait/cross_inference_pattern_bug_no_type.rs @@ -1,5 +1,5 @@ -//@ compile-flags: --edition=2021 --crate-type=lib -//@ rustc-env:RUST_BACKTRACE=0 +//@ compile-flags: --crate-type=lib +//@ edition: 2021 //@ check-pass // tracked in https://github.com/rust-lang/rust/issues/96572 diff --git a/tests/ui/type-alias-impl-trait/declared_but_not_defined_in_scope.rs b/tests/ui/type-alias-impl-trait/declared_but_not_defined_in_scope.rs index 5bda5f0fceaa..2c538853e7ba 100644 --- a/tests/ui/type-alias-impl-trait/declared_but_not_defined_in_scope.rs +++ b/tests/ui/type-alias-impl-trait/declared_but_not_defined_in_scope.rs @@ -9,5 +9,5 @@ mod boo { fn bomp() -> boo::Boo { "" - //~^ mismatched types + //~^ ERROR mismatched types } diff --git a/tests/ui/type-alias-impl-trait/destructure_tait-ice-113594.rs b/tests/ui/type-alias-impl-trait/destructure_tait-ice-113594.rs index a3b1aba70411..a42ea083d740 100644 --- a/tests/ui/type-alias-impl-trait/destructure_tait-ice-113594.rs +++ b/tests/ui/type-alias-impl-trait/destructure_tait-ice-113594.rs @@ -1,3 +1,5 @@ +//@ revisions: current next +//@ [next] compile-flags: -Znext-solver //@ build-pass //@ edition: 2021 diff --git a/tests/ui/type-alias-impl-trait/generic_duplicate_param_use8.rs b/tests/ui/type-alias-impl-trait/generic_duplicate_param_use8.rs index d01cc7ff04eb..febe1df81ae8 100644 --- a/tests/ui/type-alias-impl-trait/generic_duplicate_param_use8.rs +++ b/tests/ui/type-alias-impl-trait/generic_duplicate_param_use8.rs @@ -13,6 +13,6 @@ fn two(t: T, _: U) -> Two { #[define_opaque(Two)] fn three(_: T, u: U) -> Two { - //~^ concrete type differs + //~^ ERROR concrete type differs (u, 4u32) } diff --git a/tests/ui/type-alias-impl-trait/impl-trait-in-type-alias-with-bad-substs.stderr b/tests/ui/type-alias-impl-trait/impl-trait-in-type-alias-with-bad-substs.stderr index 13f5d8b8ea6e..c58d919c4b12 100644 --- a/tests/ui/type-alias-impl-trait/impl-trait-in-type-alias-with-bad-substs.stderr +++ b/tests/ui/type-alias-impl-trait/impl-trait-in-type-alias-with-bad-substs.stderr @@ -1,4 +1,4 @@ -error[E0049]: type `Baz` has 1 type parameter but its trait declaration has 0 type parameters +error[E0049]: associated type `Baz` has 1 type parameter but its trait declaration has 0 type parameters --> $DIR/impl-trait-in-type-alias-with-bad-substs.rs:19:14 | LL | type Baz<'a>; diff --git a/tests/ui/type-alias-impl-trait/issue-104817.rs b/tests/ui/type-alias-impl-trait/issue-104817.rs index 13bbfa12a67a..01935407e2bb 100644 --- a/tests/ui/type-alias-impl-trait/issue-104817.rs +++ b/tests/ui/type-alias-impl-trait/issue-104817.rs @@ -15,6 +15,6 @@ fn mk_opaque() -> OpaqueType { trait AnotherTrait {} impl AnotherTrait for T {} impl AnotherTrait for OpaqueType {} -//[stock]~^ conflicting implementations of trait `AnotherTrait` +//[stock]~^ ERROR conflicting implementations of trait `AnotherTrait` fn main() {} diff --git a/tests/ui/type-alias-impl-trait/issue-53598.rs b/tests/ui/type-alias-impl-trait/issue-53598.rs index 3262c69cf5a4..d8eee3218ed3 100644 --- a/tests/ui/type-alias-impl-trait/issue-53598.rs +++ b/tests/ui/type-alias-impl-trait/issue-53598.rs @@ -17,7 +17,7 @@ impl Foo for S2 { type Item = impl Debug; fn foo(_: T) -> Self::Item { - //~^ Error type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias + //~^ ERROR type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias S::(Default::default()) } } diff --git a/tests/ui/type-alias-impl-trait/issue-60662.rs b/tests/ui/type-alias-impl-trait/issue-60662.rs index 35d96e52fd61..7ecdd2647355 100644 --- a/tests/ui/type-alias-impl-trait/issue-60662.rs +++ b/tests/ui/type-alias-impl-trait/issue-60662.rs @@ -1,5 +1,6 @@ //@ check-pass //@ compile-flags: -Z unpretty=hir +//@ edition: 2015 #![feature(type_alias_impl_trait)] diff --git a/tests/ui/type-alias-impl-trait/issue-60662.stdout b/tests/ui/type-alias-impl-trait/issue-60662.stdout index b541cbeb2279..56fef852e37b 100644 --- a/tests/ui/type-alias-impl-trait/issue-60662.stdout +++ b/tests/ui/type-alias-impl-trait/issue-60662.stdout @@ -1,5 +1,6 @@ //@ check-pass //@ compile-flags: -Z unpretty=hir +//@ edition: 2015 #![feature(type_alias_impl_trait)] #[prelude_import] diff --git a/tests/ui/type-alias-impl-trait/issue-93411.rs b/tests/ui/type-alias-impl-trait/issue-93411.rs index 11cbb8766315..614d2d0471b9 100644 --- a/tests/ui/type-alias-impl-trait/issue-93411.rs +++ b/tests/ui/type-alias-impl-trait/issue-93411.rs @@ -2,7 +2,7 @@ // this test used to stack overflow due to infinite recursion. //@ check-pass -//@ compile-flags: --edition=2018 +//@ edition: 2018 use std::future::Future; diff --git a/tests/ui/type-alias-impl-trait/issue-96572-unconstrained.rs b/tests/ui/type-alias-impl-trait/issue-96572-unconstrained.rs index 08f3c404bed6..7f0f6a214aae 100644 --- a/tests/ui/type-alias-impl-trait/issue-96572-unconstrained.rs +++ b/tests/ui/type-alias-impl-trait/issue-96572-unconstrained.rs @@ -1,7 +1,7 @@ #![feature(type_alias_impl_trait)] //@ check-pass //@ revisions: default edition2021 -//@[edition2021] compile-flags: --edition 2021 +//@[edition2021]edition: 2021 fn main() { type T = impl Copy; diff --git a/tests/ui/type-alias-impl-trait/not_well_formed.rs b/tests/ui/type-alias-impl-trait/not_well_formed.rs index bd4477dbf0f3..f8f7f8a20e9b 100644 --- a/tests/ui/type-alias-impl-trait/not_well_formed.rs +++ b/tests/ui/type-alias-impl-trait/not_well_formed.rs @@ -9,8 +9,8 @@ trait TraitWithAssoc { } type Foo = impl Trait; -//~^ associated type `Assoc` not found for `V` -//~| associated type `Assoc` not found for `V` +//~^ ERROR associated type `Assoc` not found for `V` +//~| ERROR associated type `Assoc` not found for `V` trait Trait {} diff --git a/tests/ui/type-alias-impl-trait/structural-match-no-leak.rs b/tests/ui/type-alias-impl-trait/structural-match-no-leak.rs index a20ae814908b..37cb2322175e 100644 --- a/tests/ui/type-alias-impl-trait/structural-match-no-leak.rs +++ b/tests/ui/type-alias-impl-trait/structural-match-no-leak.rs @@ -14,7 +14,7 @@ const LEAK_FREE: Bar = leak_free(); fn leak_free_test() { match LEAK_FREE { LEAK_FREE => (), - //~^ `Bar` cannot be used in patterns + //~^ ERROR `Bar` cannot be used in patterns _ => (), } } diff --git a/tests/ui/type-alias-impl-trait/structural-match.rs b/tests/ui/type-alias-impl-trait/structural-match.rs index 68a95560a465..e922ffb74a54 100644 --- a/tests/ui/type-alias-impl-trait/structural-match.rs +++ b/tests/ui/type-alias-impl-trait/structural-match.rs @@ -15,7 +15,7 @@ const VALUE: Foo = value(); fn test() { match VALUE { VALUE => (), - //~^ `Foo` cannot be used in patterns + //~^ ERROR `Foo` cannot be used in patterns _ => (), } } diff --git a/tests/ui/type-alias-impl-trait/tait-normalize.rs b/tests/ui/type-alias-impl-trait/tait-normalize.rs index 38e09b6087b6..a34d167bcc39 100644 --- a/tests/ui/type-alias-impl-trait/tait-normalize.rs +++ b/tests/ui/type-alias-impl-trait/tait-normalize.rs @@ -1,3 +1,5 @@ +//@ revisions: current next +//@ [next] compile-flags: -Znext-solver //@ check-pass #![feature(type_alias_impl_trait)] diff --git a/tests/ui/type-alias-impl-trait/variance.rs b/tests/ui/type-alias-impl-trait/variance.rs index ecd7158223c8..d9140695dae2 100644 --- a/tests/ui/type-alias-impl-trait/variance.rs +++ b/tests/ui/type-alias-impl-trait/variance.rs @@ -5,17 +5,17 @@ trait Captures<'a> {} impl Captures<'_> for T {} -type NotCapturedEarly<'a> = impl Sized; //~ ['a: *, 'a: o] +type NotCapturedEarly<'a> = impl Sized; //~ ERROR ['a: *, 'a: o] //~^ ERROR: unconstrained opaque type -type CapturedEarly<'a> = impl Sized + Captures<'a>; //~ ['a: *, 'a: o] +type CapturedEarly<'a> = impl Sized + Captures<'a>; //~ ERROR ['a: *, 'a: o] //~^ ERROR: unconstrained opaque type -type NotCapturedLate<'a> = dyn for<'b> Iterator; //~ ['a: *, 'a: o, 'b: o] +type NotCapturedLate<'a> = dyn for<'b> Iterator; //~ ERROR ['a: *, 'a: o, 'b: o] //~^ ERROR `impl Trait` cannot capture higher-ranked lifetime from `dyn` type //~| ERROR: unconstrained opaque type -type Captured<'a> = dyn for<'b> Iterator>; //~ ['a: *, 'a: o, 'b: o] +type Captured<'a> = dyn for<'b> Iterator>; //~ ERROR ['a: *, 'a: o, 'b: o] //~^ ERROR `impl Trait` cannot capture higher-ranked lifetime from `dyn` type //~| ERROR: unconstrained opaque type @@ -31,24 +31,24 @@ trait Foo<'i> { } impl<'i> Foo<'i> for &'i () { - type ImplicitCapture<'a> = impl Sized; //~ ['i: *, 'a: *, 'i: o, 'a: o] + type ImplicitCapture<'a> = impl Sized; //~ ERROR ['i: *, 'a: *, 'i: o, 'a: o] //~^ ERROR: unconstrained opaque type - type ExplicitCaptureFromHeader<'a> = impl Sized + Captures<'i>; //~ ['i: *, 'a: *, 'i: o, 'a: o] + type ExplicitCaptureFromHeader<'a> = impl Sized + Captures<'i>; //~ ERROR ['i: *, 'a: *, 'i: o, 'a: o] //~^ ERROR: unconstrained opaque type - type ExplicitCaptureFromGat<'a> = impl Sized + Captures<'a>; //~ ['i: *, 'a: *, 'i: o, 'a: o] + type ExplicitCaptureFromGat<'a> = impl Sized + Captures<'a>; //~ ERROR ['i: *, 'a: *, 'i: o, 'a: o] //~^ ERROR: unconstrained opaque type } impl<'i> Foo<'i> for () { - type ImplicitCapture<'a> = impl Sized; //~ ['i: *, 'a: *, 'i: o, 'a: o] + type ImplicitCapture<'a> = impl Sized; //~ ERROR ['i: *, 'a: *, 'i: o, 'a: o] //~^ ERROR: unconstrained opaque type - type ExplicitCaptureFromHeader<'a> = impl Sized + Captures<'i>; //~ ['i: *, 'a: *, 'i: o, 'a: o] + type ExplicitCaptureFromHeader<'a> = impl Sized + Captures<'i>; //~ ERROR ['i: *, 'a: *, 'i: o, 'a: o] //~^ ERROR: unconstrained opaque type - type ExplicitCaptureFromGat<'a> = impl Sized + Captures<'a>; //~ ['i: *, 'a: *, 'i: o, 'a: o] + type ExplicitCaptureFromGat<'a> = impl Sized + Captures<'a>; //~ ERROR ['i: *, 'a: *, 'i: o, 'a: o] //~^ ERROR: unconstrained opaque type } @@ -59,15 +59,15 @@ impl<'a> Nesting<'a> for &'a () { type Output = &'a (); } type NestedDeeply<'a> = - impl Nesting< //~ ['a: *, 'a: o] + impl Nesting< //~ ERROR ['a: *, 'a: o] 'a, - Output = impl Nesting< //~ ['a: *, 'a: o] + Output = impl Nesting< //~ ERROR ['a: *, 'a: o] 'a, - Output = impl Nesting< //~ ['a: *, 'a: o] + Output = impl Nesting< //~ ERROR ['a: *, 'a: o] 'a, - Output = impl Nesting< //~ ['a: *, 'a: o] + Output = impl Nesting< //~ ERROR ['a: *, 'a: o] 'a, - Output = impl Nesting<'a> //~ ['a: *, 'a: o] + Output = impl Nesting<'a> //~ ERROR ['a: *, 'a: o] > >, >, diff --git a/tests/ui/type/ascription/issue-47666.stderr b/tests/ui/type/ascription/issue-47666.stderr index fd825e86675d..6568845fe5de 100644 --- a/tests/ui/type/ascription/issue-47666.stderr +++ b/tests/ui/type/ascription/issue-47666.stderr @@ -4,7 +4,6 @@ error: path separator must be a double colon LL | let _ = Option:Some(vec![0, 1]); | ^ | - = note: if you meant to annotate an expression with a type, the type ascription syntax has been removed, see issue #101728 help: use a double colon instead | LL | let _ = Option::Some(vec![0, 1]); diff --git a/tests/ui/type/ascription/issue-54516.stderr b/tests/ui/type/ascription/issue-54516.stderr index 64fdc1fa24a6..925080e9050b 100644 --- a/tests/ui/type/ascription/issue-54516.stderr +++ b/tests/ui/type/ascription/issue-54516.stderr @@ -4,7 +4,6 @@ error: path separator must be a double colon LL | println!("{}", std::mem:size_of::>()); | ^ | - = note: if you meant to annotate an expression with a type, the type ascription syntax has been removed, see issue #101728 help: use a double colon instead | LL | println!("{}", std::mem::size_of::>()); diff --git a/tests/ui/type/ascription/issue-60933.stderr b/tests/ui/type/ascription/issue-60933.stderr index c68394d0504a..7b55935b35ba 100644 --- a/tests/ui/type/ascription/issue-60933.stderr +++ b/tests/ui/type/ascription/issue-60933.stderr @@ -4,7 +4,6 @@ error: path separator must be a double colon LL | let _: usize = std::mem:size_of::(); | ^ | - = note: if you meant to annotate an expression with a type, the type ascription syntax has been removed, see issue #101728 help: use a double colon instead | LL | let _: usize = std::mem::size_of::(); diff --git a/tests/ui/type/issue-103271.rs b/tests/ui/type/issue-103271.rs index 7cd76286a929..98cfaaf5cff7 100644 --- a/tests/ui/type/issue-103271.rs +++ b/tests/ui/type/issue-103271.rs @@ -1,15 +1,15 @@ fn main() { let iter_fun = <&[u32]>::iter; //~^ ERROR no function or associated item named `iter` found for reference `&[u32]` in the current scope [E0599] - //~| function or associated item not found in `&[u32]` + //~| NOTE function or associated item not found in `&[u32]` //~| HELP the function `iter` is implemented on `[u32]` for item in iter_fun(&[1,1]) { let x: &u32 = item; assert_eq!(x, &1); } let iter_fun2 = <(&[u32])>::iter; - //~^ no function or associated item named `iter` found for reference `&[u32]` in the current scope [E0599] - //~| function or associated item not found in `&[u32]` + //~^ ERROR no function or associated item named `iter` found for reference `&[u32]` in the current scope [E0599] + //~| NOTE function or associated item not found in `&[u32]` //~| HELP the function `iter` is implemented on `[u32]` for item2 in iter_fun2(&[1,1]) { let x: &u32 = item2; diff --git a/tests/ui/type/missing-let-in-binding.stderr b/tests/ui/type/missing-let-in-binding.stderr index a9d766e4c3cf..dee3d56dc51e 100644 --- a/tests/ui/type/missing-let-in-binding.stderr +++ b/tests/ui/type/missing-let-in-binding.stderr @@ -4,7 +4,6 @@ error: expected identifier, found `:` LL | _foo: i32 = 4; | ^ expected identifier | - = note: type ascription syntax has been removed, see issue #101728 help: you might have meant to introduce a new binding | LL | let _foo: i32 = 4; diff --git a/tests/ui/type/pattern_types/derives.rs b/tests/ui/type/pattern_types/derives.rs index 3878c47554d9..a3959b383177 100644 --- a/tests/ui/type/pattern_types/derives.rs +++ b/tests/ui/type/pattern_types/derives.rs @@ -1,4 +1,5 @@ -//! Check that pattern types don't implement traits of their base automatically +//! Check that pattern types don't implement traits of their base automatically. +//! Exceptions are `Clone` and `Copy`, which have builtin impls for pattern types. #![feature(pattern_types)] #![feature(pattern_type_macro)] diff --git a/tests/ui/type/pattern_types/derives.stderr b/tests/ui/type/pattern_types/derives.stderr index f59617ebc456..2d83684b152e 100644 --- a/tests/ui/type/pattern_types/derives.stderr +++ b/tests/ui/type/pattern_types/derives.stderr @@ -1,5 +1,5 @@ error[E0369]: binary operation `==` cannot be applied to type `(i32) is 0..=999999999` - --> $DIR/derives.rs:10:20 + --> $DIR/derives.rs:11:20 | LL | #[derive(Clone, Copy, PartialEq)] | --------- in this derive macro expansion diff --git a/tests/ui/type/pattern_types/derives_fail.rs b/tests/ui/type/pattern_types/derives_fail.rs new file mode 100644 index 000000000000..a3fbad667207 --- /dev/null +++ b/tests/ui/type/pattern_types/derives_fail.rs @@ -0,0 +1,26 @@ +//! Check that pattern types don't implement traits of their base automatically. +//! Exceptions are `Clone` and `Copy`, which have bultin impls for pattern types. + +#![feature(pattern_types)] +#![feature(pattern_type_macro)] + +use std::pat::pattern_type; + +#[derive(Clone, Copy, PartialEq, Eq, Debug, Ord, PartialOrd, Hash, Default)] +#[repr(transparent)] +struct Nanoseconds(NanoI32); +//~^ ERROR: the trait bound `(i32) is 0..=999999999: Eq` is not satisfied +//~| ERROR: `(i32) is 0..=999999999` doesn't implement `Debug` +//~| ERROR: the trait bound `(i32) is 0..=999999999: Ord` is not satisfied +//~| ERROR: the trait bound `(i32) is 0..=999999999: Hash` is not satisfied +//~| ERROR: the trait bound `(i32) is 0..=999999999: Default` is not satisfied +//~| ERROR: can't compare `(i32) is 0..=999999999` with `_` +//~| ERROR: `==` cannot be applied + +type NanoI32 = crate::pattern_type!(i32 is 0..=999_999_999); + +fn main() { + let x = Nanoseconds(unsafe { std::mem::transmute(42) }); + let y = x.clone(); + if y == x {} +} diff --git a/tests/ui/type/pattern_types/derives_fail.stderr b/tests/ui/type/pattern_types/derives_fail.stderr new file mode 100644 index 000000000000..78bef726341d --- /dev/null +++ b/tests/ui/type/pattern_types/derives_fail.stderr @@ -0,0 +1,74 @@ +error[E0369]: binary operation `==` cannot be applied to type `(i32) is 0..=999999999` + --> $DIR/derives_fail.rs:11:20 + | +LL | #[derive(Clone, Copy, PartialEq, Eq, Debug, Ord, PartialOrd, Hash, Default)] + | --------- in this derive macro expansion +LL | #[repr(transparent)] +LL | struct Nanoseconds(NanoI32); + | ^^^^^^^ + +error[E0277]: the trait bound `(i32) is 0..=999999999: Eq` is not satisfied + --> $DIR/derives_fail.rs:11:20 + | +LL | #[derive(Clone, Copy, PartialEq, Eq, Debug, Ord, PartialOrd, Hash, Default)] + | -- in this derive macro expansion +LL | #[repr(transparent)] +LL | struct Nanoseconds(NanoI32); + | ^^^^^^^ the trait `Eq` is not implemented for `(i32) is 0..=999999999` + | +note: required by a bound in `AssertParamIsEq` + --> $SRC_DIR/core/src/cmp.rs:LL:COL + +error[E0277]: `(i32) is 0..=999999999` doesn't implement `Debug` + --> $DIR/derives_fail.rs:11:20 + | +LL | #[derive(Clone, Copy, PartialEq, Eq, Debug, Ord, PartialOrd, Hash, Default)] + | ----- in this derive macro expansion +LL | #[repr(transparent)] +LL | struct Nanoseconds(NanoI32); + | ^^^^^^^ `(i32) is 0..=999999999` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | + = help: the trait `Debug` is not implemented for `(i32) is 0..=999999999` + +error[E0277]: the trait bound `(i32) is 0..=999999999: Ord` is not satisfied + --> $DIR/derives_fail.rs:11:20 + | +LL | #[derive(Clone, Copy, PartialEq, Eq, Debug, Ord, PartialOrd, Hash, Default)] + | --- in this derive macro expansion +LL | #[repr(transparent)] +LL | struct Nanoseconds(NanoI32); + | ^^^^^^^ the trait `Ord` is not implemented for `(i32) is 0..=999999999` + +error[E0277]: can't compare `(i32) is 0..=999999999` with `_` + --> $DIR/derives_fail.rs:11:20 + | +LL | #[derive(Clone, Copy, PartialEq, Eq, Debug, Ord, PartialOrd, Hash, Default)] + | ---------- in this derive macro expansion +LL | #[repr(transparent)] +LL | struct Nanoseconds(NanoI32); + | ^^^^^^^ no implementation for `(i32) is 0..=999999999 < _` and `(i32) is 0..=999999999 > _` + | + = help: the trait `PartialOrd<_>` is not implemented for `(i32) is 0..=999999999` + +error[E0277]: the trait bound `(i32) is 0..=999999999: Hash` is not satisfied + --> $DIR/derives_fail.rs:11:20 + | +LL | #[derive(Clone, Copy, PartialEq, Eq, Debug, Ord, PartialOrd, Hash, Default)] + | ---- in this derive macro expansion +LL | #[repr(transparent)] +LL | struct Nanoseconds(NanoI32); + | ^^^^^^^ the trait `Hash` is not implemented for `(i32) is 0..=999999999` + +error[E0277]: the trait bound `(i32) is 0..=999999999: Default` is not satisfied + --> $DIR/derives_fail.rs:11:20 + | +LL | #[derive(Clone, Copy, PartialEq, Eq, Debug, Ord, PartialOrd, Hash, Default)] + | ------- in this derive macro expansion +LL | #[repr(transparent)] +LL | struct Nanoseconds(NanoI32); + | ^^^^^^^ the trait `Default` is not implemented for `(i32) is 0..=999999999` + +error: aborting due to 7 previous errors + +Some errors have detailed explanations: E0277, E0369. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/type/pattern_types/feature-gate-pattern_types.rs b/tests/ui/type/pattern_types/feature-gate-pattern_types.rs index b4f4bd656f5f..a51741675bbd 100644 --- a/tests/ui/type/pattern_types/feature-gate-pattern_types.rs +++ b/tests/ui/type/pattern_types/feature-gate-pattern_types.rs @@ -3,13 +3,13 @@ use std::pat::pattern_type; type NonNullU32 = pattern_type!(u32 is 1..); -//~^ use of unstable library feature `pattern_type_macro` +//~^ ERROR use of unstable library feature `pattern_type_macro` type Percent = pattern_type!(u32 is 0..=100); -//~^ use of unstable library feature `pattern_type_macro` +//~^ ERROR use of unstable library feature `pattern_type_macro` type Negative = pattern_type!(i32 is ..=0); -//~^ use of unstable library feature `pattern_type_macro` +//~^ ERROR use of unstable library feature `pattern_type_macro` type Positive = pattern_type!(i32 is 0..); -//~^ use of unstable library feature `pattern_type_macro` +//~^ ERROR use of unstable library feature `pattern_type_macro` type Always = pattern_type!(Option is Some(_)); -//~^ use of unstable library feature `pattern_type_macro` +//~^ ERROR use of unstable library feature `pattern_type_macro` //~| ERROR pattern not supported in pattern types diff --git a/tests/ui/type/pattern_types/literals.rs b/tests/ui/type/pattern_types/literals.rs index 7fd630dab3ad..b2a83a2a8bdc 100644 --- a/tests/ui/type/pattern_types/literals.rs +++ b/tests/ui/type/pattern_types/literals.rs @@ -7,7 +7,7 @@ use std::pat::pattern_type; fn out_of_range() -> pattern_type!(u32 is 1..) { 0 - //~^ mismatched types + //~^ ERROR mismatched types } fn at_range_start() -> pattern_type!(u32 is 1..) { @@ -34,7 +34,7 @@ fn positive_lit_in_range_of_signed() -> pattern_type!(i8 is -5..5) { fn negative_lit_at_range_start() -> pattern_type!(i8 is -5..5) { -5 - //~^ mismatched types + //~^ ERROR mismatched types } fn positive_lit_at_range_end() -> pattern_type!(i8 is -5..5) { @@ -43,22 +43,22 @@ fn positive_lit_at_range_end() -> pattern_type!(i8 is -5..5) { fn lit_one_beyond_range_end() -> pattern_type!(i8 is -5..5) { 5 - //~^ mismatched types + //~^ ERROR mismatched types } fn wrong_lit_kind() -> pattern_type!(u32 is 1..) { '3' - //~^ mismatched types + //~^ ERROR mismatched types } fn char_lit_in_range() -> pattern_type!(char is 'a'..'z') { 'b' - //~^ mismatched types + //~^ ERROR mismatched types } fn char_lit_out_of_range() -> pattern_type!(char is 'a'..'z') { 'A' - //~^ mismatched types + //~^ ERROR mismatched types } fn lit_at_unsigned_range_inclusive_end() -> pattern_type!(u32 is 0..=1) { @@ -71,12 +71,12 @@ fn single_element_range() -> pattern_type!(u32 is 0..=0) { fn lit_oob_single_element_range() -> pattern_type!(u32 is 0..=0) { 1 - //~^ mismatched types + //~^ ERROR mismatched types } fn lit_oob_single_element_range_exclusive() -> pattern_type!(u32 is 0..1) { 1 - //~^ mismatched types + //~^ ERROR mismatched types } fn single_element_range_exclusive() -> pattern_type!(u32 is 0..1) { @@ -84,53 +84,53 @@ fn single_element_range_exclusive() -> pattern_type!(u32 is 0..1) { } fn empty_range_at_base_type_min() -> pattern_type!(u32 is 0..0) { - //~^ evaluation of constant value failed + //~^ ERROR evaluation of constant value failed 0 } fn empty_range_at_base_type_min2() -> pattern_type!(u32 is 0..0) { - //~^ evaluation of constant value failed + //~^ ERROR evaluation of constant value failed 1 } fn empty_range() -> pattern_type!(u32 is 1..1) { 0 - //~^ mismatched types + //~^ ERROR mismatched types } fn empty_range2() -> pattern_type!(u32 is 1..1) { 1 - //~^ mismatched types + //~^ ERROR mismatched types } fn wraparound_range_at_base_ty_end() -> pattern_type!(u32 is 1..0) { - //~^ evaluation of constant value failed + //~^ ERROR evaluation of constant value failed 1 } fn wraparound_range_at_base_ty_end2() -> pattern_type!(u32 is 1..0) { - //~^ evaluation of constant value failed + //~^ ERROR evaluation of constant value failed 0 } fn wraparound_range_at_base_ty_end3() -> pattern_type!(u32 is 1..0) { - //~^ evaluation of constant value failed + //~^ ERROR evaluation of constant value failed 2 } fn wraparound_range() -> pattern_type!(u32 is 2..1) { 1 - //~^ mismatched types + //~^ ERROR mismatched types } fn lit_in_wraparound_range() -> pattern_type!(u32 is 2..1) { 0 - //~^ mismatched types + //~^ ERROR mismatched types } fn lit_at_wraparound_range_start() -> pattern_type!(u32 is 2..1) { 2 - //~^ mismatched types + //~^ ERROR mismatched types } fn main() {} diff --git a/tests/ui/type/pattern_types/matching.rs b/tests/ui/type/pattern_types/matching.rs new file mode 100644 index 000000000000..b8463a8e8229 --- /dev/null +++ b/tests/ui/type/pattern_types/matching.rs @@ -0,0 +1,26 @@ +#![feature(pattern_types, pattern_type_macro, structural_match)] + +//@ check-pass + +use std::marker::StructuralPartialEq; +use std::pat::pattern_type; + +struct Thing(pattern_type!(u32 is 1..)); + +impl StructuralPartialEq for Thing {} +impl PartialEq for Thing { + fn eq(&self, other: &Thing) -> bool { + unsafe { std::mem::transmute::<_, u32>(self.0) == std::mem::transmute::<_, u32>(other.0) } + } +} + +impl Eq for Thing {} + +const TWO: Thing = Thing(2); + +const _: () = match TWO { + TWO => {} + _ => unreachable!(), +}; + +fn main() {} diff --git a/tests/ui/type/pattern_types/matching_fail.rs b/tests/ui/type/pattern_types/matching_fail.rs new file mode 100644 index 000000000000..8e2c741e3e0a --- /dev/null +++ b/tests/ui/type/pattern_types/matching_fail.rs @@ -0,0 +1,25 @@ +#![feature(pattern_types, pattern_type_macro, structural_match)] + +use std::pat::pattern_type; + +const THREE: pattern_type!(u32 is 1..) = 3; + +const _: () = match THREE { + THREE => {} + //~^ ERROR non-structural type + _ => unreachable!(), +}; + +const _: () = match THREE { + 3 => {} + //~^ ERROR mismatched types + _ => unreachable!(), +}; + +const _: () = match 3 { + THREE => {} + //~^ ERROR mismatched types + _ => unreachable!(), +}; + +fn main() {} diff --git a/tests/ui/type/pattern_types/matching_fail.stderr b/tests/ui/type/pattern_types/matching_fail.stderr new file mode 100644 index 000000000000..446180d80f24 --- /dev/null +++ b/tests/ui/type/pattern_types/matching_fail.stderr @@ -0,0 +1,43 @@ +error: constant of non-structural type `(u32) is 1..` in a pattern + --> $DIR/matching_fail.rs:8:5 + | +LL | const THREE: pattern_type!(u32 is 1..) = 3; + | -------------------------------------- constant defined here +... +LL | THREE => {} + | ^^^^^ constant of non-structural type + | + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details + +error[E0308]: mismatched types + --> $DIR/matching_fail.rs:14:5 + | +LL | const _: () = match THREE { + | ----- this expression has type `(u32) is 1..` +LL | 3 => {} + | ^ expected `(u32) is 1..`, found integer + | + = note: expected pattern type `(u32) is 1..` + found type `{integer}` + +error[E0308]: mismatched types + --> $DIR/matching_fail.rs:20:5 + | +LL | const THREE: pattern_type!(u32 is 1..) = 3; + | -------------------------------------- constant defined here +... +LL | const _: () = match 3 { + | - this expression has type `{integer}` +LL | THREE => {} + | ^^^^^ + | | + | expected integer, found `(u32) is 1..` + | `THREE` is interpreted as a constant, not a new binding + | help: introduce a new binding instead: `other_three` + | + = note: expected type `{integer}` + found pattern type `(u32) is 1..` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/type/type-ascription-instead-of-statement-end.stderr b/tests/ui/type/type-ascription-instead-of-statement-end.stderr index 34759b413d89..82b7fd23a4d9 100644 --- a/tests/ui/type/type-ascription-instead-of-statement-end.stderr +++ b/tests/ui/type/type-ascription-instead-of-statement-end.stderr @@ -4,7 +4,6 @@ error: statements are terminated with a semicolon LL | println!("test"): | ^ | - = note: if you meant to annotate an expression with a type, the type ascription syntax has been removed, see issue #101728 help: use a semicolon instead | LL - println!("test"): diff --git a/tests/ui/type/type-ascription-precedence.stderr b/tests/ui/type/type-ascription-precedence.stderr index 09cdc370309d..f7ae612ef60f 100644 --- a/tests/ui/type/type-ascription-precedence.stderr +++ b/tests/ui/type/type-ascription-precedence.stderr @@ -33,8 +33,6 @@ error: expected identifier, found `:` | LL | S .. S: S; | ^ expected identifier - | - = note: type ascription syntax has been removed, see issue #101728 error: expected one of `.`, `;`, `?`, `}`, or an operator, found `:` --> $DIR/type-ascription-precedence.rs:53:13 diff --git a/tests/ui/type/type-ascription-with-fn-call.stderr b/tests/ui/type/type-ascription-with-fn-call.stderr index 4222762373dc..803c9f1c302e 100644 --- a/tests/ui/type/type-ascription-with-fn-call.stderr +++ b/tests/ui/type/type-ascription-with-fn-call.stderr @@ -4,7 +4,6 @@ error: statements are terminated with a semicolon LL | f() : | ^ | - = note: if you meant to annotate an expression with a type, the type ascription syntax has been removed, see issue #101728 help: use a semicolon instead | LL - f() : diff --git a/tests/ui/typeck/attempted-access-non-fatal.rs b/tests/ui/typeck/attempted-access-non-fatal.rs index 15deb9e2f609..ba391cfa486d 100644 --- a/tests/ui/typeck/attempted-access-non-fatal.rs +++ b/tests/ui/typeck/attempted-access-non-fatal.rs @@ -1,10 +1,10 @@ // Check that bogus field access is non-fatal fn main() { let x = 0; - let _ = x.foo; //~ `{integer}` is a primitive type and therefore doesn't have fields [E0610] - let _ = x.bar; //~ `{integer}` is a primitive type and therefore doesn't have fields [E0610] - let _ = 0.f; //~ `{integer}` is a primitive type and therefore doesn't have fields [E0610] - let _ = 2.l; //~ `{integer}` is a primitive type and therefore doesn't have fields [E0610] - let _ = 12.F; //~ `{integer}` is a primitive type and therefore doesn't have fields [E0610] - let _ = 34.L; //~ `{integer}` is a primitive type and therefore doesn't have fields [E0610] + let _ = x.foo; //~ ERROR `{integer}` is a primitive type and therefore doesn't have fields [E0610] + let _ = x.bar; //~ ERROR `{integer}` is a primitive type and therefore doesn't have fields [E0610] + let _ = 0.f; //~ ERROR `{integer}` is a primitive type and therefore doesn't have fields [E0610] + let _ = 2.l; //~ ERROR `{integer}` is a primitive type and therefore doesn't have fields [E0610] + let _ = 12.F; //~ ERROR `{integer}` is a primitive type and therefore doesn't have fields [E0610] + let _ = 34.L; //~ ERROR `{integer}` is a primitive type and therefore doesn't have fields [E0610] } diff --git a/tests/ui/typeck/autoderef-with-param-env-error.rs b/tests/ui/typeck/autoderef-with-param-env-error.rs index ec96c61c63e3..d68f2d492ffe 100644 --- a/tests/ui/typeck/autoderef-with-param-env-error.rs +++ b/tests/ui/typeck/autoderef-with-param-env-error.rs @@ -1,7 +1,7 @@ fn foo() where T: Send, - //~^ cannot find type `T` in this scope + //~^ ERROR cannot find type `T` in this scope { let s = "abc".to_string(); } diff --git a/tests/ui/typeck/auxiliary/suggest-trait-reexported-as-not-doc-visible-a.rs b/tests/ui/typeck/auxiliary/suggest-trait-reexported-as-not-doc-visible-a.rs new file mode 100644 index 000000000000..87d83663626b --- /dev/null +++ b/tests/ui/typeck/auxiliary/suggest-trait-reexported-as-not-doc-visible-a.rs @@ -0,0 +1,5 @@ +//@ edition: 2021 + +pub trait Foo { + fn foo(); +} diff --git a/tests/ui/typeck/auxiliary/suggest-trait-reexported-as-not-doc-visible-b.rs b/tests/ui/typeck/auxiliary/suggest-trait-reexported-as-not-doc-visible-b.rs new file mode 100644 index 000000000000..9e90e0f0b356 --- /dev/null +++ b/tests/ui/typeck/auxiliary/suggest-trait-reexported-as-not-doc-visible-b.rs @@ -0,0 +1,14 @@ +// ignore-tidy-linelength +//@ edition: 2021 +//@ aux-crate:suggest_trait_reexported_as_not_doc_visible_a=suggest-trait-reexported-as-not-doc-visible-a.rs + +pub struct Bar; + +impl __DocHidden::Foo for Bar { + fn foo() {} +} + +#[doc(hidden)] +pub mod __DocHidden { + pub use suggest_trait_reexported_as_not_doc_visible_a::Foo; +} diff --git a/tests/ui/typeck/issue-46112.rs b/tests/ui/typeck/issue-46112.rs index cc8029771d6d..a3fe03b17c10 100644 --- a/tests/ui/typeck/issue-46112.rs +++ b/tests/ui/typeck/issue-46112.rs @@ -6,4 +6,4 @@ extern crate xcrate_issue_46112_rexport_core; fn test(r: Result, &'static str>) { } fn main() { test(Ok(())); } -//~^ mismatched types +//~^ ERROR mismatched types diff --git a/tests/ui/typeck/issue-65611.rs b/tests/ui/typeck/issue-65611.rs index 7645311496d8..0dae75927a86 100644 --- a/tests/ui/typeck/issue-65611.rs +++ b/tests/ui/typeck/issue-65611.rs @@ -58,6 +58,5 @@ fn main() { let mut buffer = ArrayVec::new(); let x = buffer.last().unwrap().0.clone(); //~^ ERROR type annotations needed - //~| ERROR no field `0` on type `&_` buffer.reverse(); } diff --git a/tests/ui/typeck/issue-65611.stderr b/tests/ui/typeck/issue-65611.stderr index 2278450a6d8e..52f0f0cffff9 100644 --- a/tests/ui/typeck/issue-65611.stderr +++ b/tests/ui/typeck/issue-65611.stderr @@ -4,13 +4,6 @@ error[E0282]: type annotations needed LL | let x = buffer.last().unwrap().0.clone(); | ^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `T` -error[E0609]: no field `0` on type `&_` - --> $DIR/issue-65611.rs:59:36 - | -LL | let x = buffer.last().unwrap().0.clone(); - | ^ unknown field +error: aborting due to 1 previous error -error: aborting due to 2 previous errors - -Some errors have detailed explanations: E0282, E0609. -For more information about an error, try `rustc --explain E0282`. +For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/typeck/issue-79040.rs b/tests/ui/typeck/issue-79040.rs index f8e38e7867d5..fe8dc4534618 100644 --- a/tests/ui/typeck/issue-79040.rs +++ b/tests/ui/typeck/issue-79040.rs @@ -1,6 +1,6 @@ fn main() { const FOO = "hello" + 1; //~^ ERROR cannot add `{integer}` to `&str` - //~| missing type for `const` item + //~| ERROR missing type for `const` item println!("{}", FOO); } diff --git a/tests/ui/typeck/issue-83693.rs b/tests/ui/typeck/issue-83693.rs index 02a0bb30d7ce..68a1416517a7 100644 --- a/tests/ui/typeck/issue-83693.rs +++ b/tests/ui/typeck/issue-83693.rs @@ -8,7 +8,7 @@ impl F { fn call() { ::call //~^ ERROR: cannot find type `TestResult` in this scope [E0412] - //~| associated item constraints are not allowed here [E0229] + //~| ERROR associated item constraints are not allowed here [E0229] } } diff --git a/tests/ui/typeck/issue-90027-async-fn-return-suggestion.rs b/tests/ui/typeck/issue-90027-async-fn-return-suggestion.rs index 0be1237749fc..dd833957a70a 100644 --- a/tests/ui/typeck/issue-90027-async-fn-return-suggestion.rs +++ b/tests/ui/typeck/issue-90027-async-fn-return-suggestion.rs @@ -1,4 +1,5 @@ //@ edition:2018 +//@ dont-require-annotations: SUGGESTION async fn hello() { //~ HELP try adding a return type 0 diff --git a/tests/ui/typeck/issue-90027-async-fn-return-suggestion.stderr b/tests/ui/typeck/issue-90027-async-fn-return-suggestion.stderr index c46f4ec1ec30..3680df25f0ba 100644 --- a/tests/ui/typeck/issue-90027-async-fn-return-suggestion.stderr +++ b/tests/ui/typeck/issue-90027-async-fn-return-suggestion.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/issue-90027-async-fn-return-suggestion.rs:4:5 + --> $DIR/issue-90027-async-fn-return-suggestion.rs:5:5 | LL | async fn hello() { | - help: try adding a return type: `-> i32` @@ -7,7 +7,7 @@ LL | 0 | ^ expected `()`, found integer error[E0308]: mismatched types - --> $DIR/issue-90027-async-fn-return-suggestion.rs:9:5 + --> $DIR/issue-90027-async-fn-return-suggestion.rs:10:5 | LL | async fn world() -> () { | -- expected `()` because of return type @@ -15,13 +15,13 @@ LL | 0 | ^ expected `()`, found integer error[E0308]: mismatched types - --> $DIR/issue-90027-async-fn-return-suggestion.rs:14:5 + --> $DIR/issue-90027-async-fn-return-suggestion.rs:15:5 | LL | hello() | ^^^^^^^ expected `()`, found future | note: calling an async function returns a future - --> $DIR/issue-90027-async-fn-return-suggestion.rs:14:5 + --> $DIR/issue-90027-async-fn-return-suggestion.rs:15:5 | LL | hello() | ^^^^^^^ diff --git a/tests/ui/typeck/no-type-for-node-ice.rs b/tests/ui/typeck/no-type-for-node-ice.rs index d0cfdbf504de..ed56272e63cc 100644 --- a/tests/ui/typeck/no-type-for-node-ice.rs +++ b/tests/ui/typeck/no-type-for-node-ice.rs @@ -1,5 +1,5 @@ // Related issues: #20401, #20506, #20614, #20752, #20829, #20846, #20885, #20886 fn main() { - "".homura[""]; //~ no field `homura` on type `&'static str` + "".homura[""]; //~ ERROR no field `homura` on type `&'static str` } diff --git a/tests/ui/typeck/suggest-trait-reexported-as-not-doc-visible.rs b/tests/ui/typeck/suggest-trait-reexported-as-not-doc-visible.rs new file mode 100644 index 000000000000..3cb775e85ac6 --- /dev/null +++ b/tests/ui/typeck/suggest-trait-reexported-as-not-doc-visible.rs @@ -0,0 +1,11 @@ +// ignore-tidy-linelength +//@ edition: 2021 +//@ aux-crate:suggest_trait_reexported_as_not_doc_visible_a=suggest-trait-reexported-as-not-doc-visible-a.rs +//@ aux-crate:suggest_trait_reexported_as_not_doc_visible_b=suggest-trait-reexported-as-not-doc-visible-b.rs + +use suggest_trait_reexported_as_not_doc_visible_b::Bar; + +fn main() { + Bar::foo(); + //~^ ERROR: no function or associated item named `foo` found for struct `Bar` in the current scope [E0599] +} diff --git a/tests/ui/typeck/suggest-trait-reexported-as-not-doc-visible.stderr b/tests/ui/typeck/suggest-trait-reexported-as-not-doc-visible.stderr new file mode 100644 index 000000000000..9128ee684446 --- /dev/null +++ b/tests/ui/typeck/suggest-trait-reexported-as-not-doc-visible.stderr @@ -0,0 +1,15 @@ +error[E0599]: no function or associated item named `foo` found for struct `Bar` in the current scope + --> $DIR/suggest-trait-reexported-as-not-doc-visible.rs:9:10 + | +LL | Bar::foo(); + | ^^^ function or associated item not found in `Bar` + | + = help: items from traits can only be used if the trait is in scope +help: trait `Foo` which provides `foo` is implemented but not in scope; perhaps you want to import it + | +LL + use suggest_trait_reexported_as_not_doc_visible_a::Foo; + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/typeck/typeck_type_placeholder_item.stderr b/tests/ui/typeck/typeck_type_placeholder_item.stderr index 2a4a5a62ab4c..7184244f5dc9 100644 --- a/tests/ui/typeck/typeck_type_placeholder_item.stderr +++ b/tests/ui/typeck/typeck_type_placeholder_item.stderr @@ -439,6 +439,18 @@ LL | fn fn_test13(x: _) -> (i32, _) { (x, x) } | | not allowed in type signatures | help: replace with the correct return type: `(i32, i32)` +error[E0121]: the placeholder `_` is not allowed within types on item signatures for structs + --> $DIR/typeck_type_placeholder_item.rs:154:21 + | +LL | struct BadStruct<_>(_); + | ^ not allowed in type signatures + | +help: use type parameters instead + | +LL - struct BadStruct<_>(_); +LL + struct BadStruct(T); + | + error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions --> $DIR/typeck_type_placeholder_item.rs:140:31 | @@ -515,18 +527,6 @@ LL - fn assoc_fn_test3() -> _; LL + fn assoc_fn_test3() -> T; | -error[E0121]: the placeholder `_` is not allowed within types on item signatures for structs - --> $DIR/typeck_type_placeholder_item.rs:154:21 - | -LL | struct BadStruct<_>(_); - | ^ not allowed in type signatures - | -help: use type parameters instead - | -LL - struct BadStruct<_>(_); -LL + struct BadStruct(T); - | - error[E0121]: the placeholder `_` is not allowed within types on item signatures for implementations --> $DIR/typeck_type_placeholder_item.rs:159:15 | diff --git a/tests/ui/unboxed-closures/unboxed-closures-infer-argument-types-two-region-pointers.rs b/tests/ui/unboxed-closures/unboxed-closures-infer-argument-types-two-region-pointers.rs index 6765da42132b..c57e665724b4 100644 --- a/tests/ui/unboxed-closures/unboxed-closures-infer-argument-types-two-region-pointers.rs +++ b/tests/ui/unboxed-closures/unboxed-closures-infer-argument-types-two-region-pointers.rs @@ -15,6 +15,6 @@ fn doit(val: T, f: &F) pub fn main() { doit(0, &|x, y| { x.set(y); - //~^ lifetime may not live long enough + //~^ ERROR lifetime may not live long enough }); } diff --git a/tests/ui/uninhabited/uninhabited-irrefutable.rs b/tests/ui/uninhabited/uninhabited-irrefutable.rs index cbaa98960033..3f7414e596bf 100644 --- a/tests/ui/uninhabited/uninhabited-irrefutable.rs +++ b/tests/ui/uninhabited/uninhabited-irrefutable.rs @@ -29,7 +29,7 @@ fn main() { let x: Foo = Foo::D(123, 456); let Foo::D(_y, _z) = x; //~^ ERROR refutable pattern in local binding - //~| `Foo::A(_)` not covered + //~| NOTE `Foo::A(_)` not covered //~| NOTE `let` bindings require an "irrefutable pattern" //~| NOTE for more information //~| NOTE pattern `Foo::A(_)` is currently uninhabited diff --git a/tests/ui/unknown-unstable-lints/deny-unstable-lint-command-line.rs b/tests/ui/unknown-unstable-lints/deny-unstable-lint-command-line.rs index 9304e20b4290..6005bc96ad6d 100644 --- a/tests/ui/unknown-unstable-lints/deny-unstable-lint-command-line.rs +++ b/tests/ui/unknown-unstable-lints/deny-unstable-lint-command-line.rs @@ -1,6 +1,7 @@ //~ ERROR unknown lint: `test_unstable_lint` +//~^ NOTE the `test_unstable_lint` lint is unstable //@ check-fail //@ compile-flags: -Dunknown_lints -Atest_unstable_lint -//@ error-pattern: the `test_unstable_lint` lint is unstable +//@ dont-require-annotations: NOTE fn main() {} diff --git a/tests/ui/unknown-unstable-lints/warn-unknown-unstable-lint-command-line.rs b/tests/ui/unknown-unstable-lints/warn-unknown-unstable-lint-command-line.rs index 76983419c685..c32a21a01632 100644 --- a/tests/ui/unknown-unstable-lints/warn-unknown-unstable-lint-command-line.rs +++ b/tests/ui/unknown-unstable-lints/warn-unknown-unstable-lint-command-line.rs @@ -1,6 +1,7 @@ //~ WARN unknown lint: `test_unstable_lint` +//~^ NOTE the `test_unstable_lint` lint is unstable //@ check-pass //@ compile-flags: -Wunknown_lints -Atest_unstable_lint -//@ error-pattern: the `test_unstable_lint` lint is unstable +//@ dont-require-annotations: NOTE fn main() {} diff --git a/tests/ui/unpretty/bad-literal.rs b/tests/ui/unpretty/bad-literal.rs index 37377898b14f..0ec1d7b07f1f 100644 --- a/tests/ui/unpretty/bad-literal.rs +++ b/tests/ui/unpretty/bad-literal.rs @@ -1,5 +1,6 @@ //@ compile-flags: -Zunpretty=hir //@ check-fail +//@ edition: 2015 // In #100948 this caused an ICE with -Zunpretty=hir. fn main() { diff --git a/tests/ui/unpretty/bad-literal.stderr b/tests/ui/unpretty/bad-literal.stderr index b6259484f67d..fd1801a87f20 100644 --- a/tests/ui/unpretty/bad-literal.stderr +++ b/tests/ui/unpretty/bad-literal.stderr @@ -1,5 +1,5 @@ error: invalid suffix `u` for number literal - --> $DIR/bad-literal.rs:6:5 + --> $DIR/bad-literal.rs:7:5 | LL | 1u; | ^^ invalid suffix `u` diff --git a/tests/ui/unpretty/bad-literal.stdout b/tests/ui/unpretty/bad-literal.stdout index c5272711d6e9..06116a4ab553 100644 --- a/tests/ui/unpretty/bad-literal.stdout +++ b/tests/ui/unpretty/bad-literal.stdout @@ -4,6 +4,7 @@ use ::std::prelude::rust_2015::*; extern crate std; //@ compile-flags: -Zunpretty=hir //@ check-fail +//@ edition: 2015 // In #100948 this caused an ICE with -Zunpretty=hir. fn main() { diff --git a/tests/ui/unpretty/debug-fmt-hir.rs b/tests/ui/unpretty/debug-fmt-hir.rs index c19f3c4c0c57..c79349de4442 100644 --- a/tests/ui/unpretty/debug-fmt-hir.rs +++ b/tests/ui/unpretty/debug-fmt-hir.rs @@ -1,5 +1,6 @@ //@ compile-flags: -Zunpretty=hir //@ check-pass +//@ edition: 2015 use std::fmt; diff --git a/tests/ui/unpretty/debug-fmt-hir.stdout b/tests/ui/unpretty/debug-fmt-hir.stdout index 2c9c96de9d14..dc18675ea803 100644 --- a/tests/ui/unpretty/debug-fmt-hir.stdout +++ b/tests/ui/unpretty/debug-fmt-hir.stdout @@ -4,6 +4,7 @@ use ::std::prelude::rust_2015::*; extern crate std; //@ compile-flags: -Zunpretty=hir //@ check-pass +//@ edition: 2015 use std::fmt; diff --git a/tests/ui/unpretty/deprecated-attr.rs b/tests/ui/unpretty/deprecated-attr.rs index dda362a595e2..0c80203e9652 100644 --- a/tests/ui/unpretty/deprecated-attr.rs +++ b/tests/ui/unpretty/deprecated-attr.rs @@ -1,5 +1,6 @@ //@ compile-flags: -Zunpretty=hir //@ check-pass +//@ edition: 2015 #[deprecated] pub struct PlainDeprecated; diff --git a/tests/ui/unpretty/deprecated-attr.stdout b/tests/ui/unpretty/deprecated-attr.stdout index 42de7b4533e5..97d863b2e943 100644 --- a/tests/ui/unpretty/deprecated-attr.stdout +++ b/tests/ui/unpretty/deprecated-attr.stdout @@ -4,6 +4,7 @@ use ::std::prelude::rust_2015::*; extern crate std; //@ compile-flags: -Zunpretty=hir //@ check-pass +//@ edition: 2015 #[attr = Deprecation {deprecation: Deprecation {since: Unspecified}}] struct PlainDeprecated; diff --git a/tests/ui/unpretty/diagnostic-attr.rs b/tests/ui/unpretty/diagnostic-attr.rs index 27f5b693e691..4ef85c71f90e 100644 --- a/tests/ui/unpretty/diagnostic-attr.rs +++ b/tests/ui/unpretty/diagnostic-attr.rs @@ -1,5 +1,6 @@ //@ compile-flags: -Zunpretty=hir //@ check-pass +//@ edition: 2015 #[diagnostic::on_unimplemented( message = "My Message for `ImportantTrait<{A}>` implemented for `{Self}`", diff --git a/tests/ui/unpretty/diagnostic-attr.stdout b/tests/ui/unpretty/diagnostic-attr.stdout index e8696d04d38a..81d71b91d815 100644 --- a/tests/ui/unpretty/diagnostic-attr.stdout +++ b/tests/ui/unpretty/diagnostic-attr.stdout @@ -4,6 +4,7 @@ use ::std::prelude::rust_2015::*; extern crate std; //@ compile-flags: -Zunpretty=hir //@ check-pass +//@ edition: 2015 #[diagnostic::on_unimplemented(message = "My Message for `ImportantTrait<{A}>` implemented for `{Self}`", label = diff --git a/tests/ui/unpretty/expanded-exhaustive.rs b/tests/ui/unpretty/expanded-exhaustive.rs index 31af323ecdab..4d1f12e34900 100644 --- a/tests/ui/unpretty/expanded-exhaustive.rs +++ b/tests/ui/unpretty/expanded-exhaustive.rs @@ -574,6 +574,11 @@ mod items { } mod patterns { + /// PatKind::Missing + fn pat_missing() { + let _: fn(u32, T, &str); + } + /// PatKind::Wild fn pat_wild() { let _; diff --git a/tests/ui/unpretty/expanded-exhaustive.stdout b/tests/ui/unpretty/expanded-exhaustive.stdout index 19ae66f7a07a..d8da941a3407 100644 --- a/tests/ui/unpretty/expanded-exhaustive.stdout +++ b/tests/ui/unpretty/expanded-exhaustive.stdout @@ -361,6 +361,7 @@ mod expressions { + { builtin # offset_of(T, field) }; @@ -517,6 +518,8 @@ mod items { } } mod patterns { + /// PatKind::Missing + fn pat_missing() { let _: fn(u32, T, &str); } /// PatKind::Wild fn pat_wild() { let _; } /// PatKind::Ident diff --git a/tests/ui/unpretty/expanded-interpolation.rs b/tests/ui/unpretty/expanded-interpolation.rs index 1dc72c67f511..0c447ae669dd 100644 --- a/tests/ui/unpretty/expanded-interpolation.rs +++ b/tests/ui/unpretty/expanded-interpolation.rs @@ -1,5 +1,6 @@ //@ compile-flags: -Zunpretty=expanded //@ check-pass +//@ edition: 2015 // This test covers the AST pretty-printer's insertion of parentheses in some // macro metavariable edge cases. Synthetic parentheses (i.e. not appearing in diff --git a/tests/ui/unpretty/expanded-interpolation.stdout b/tests/ui/unpretty/expanded-interpolation.stdout index 556e57dbd921..10729a96ef59 100644 --- a/tests/ui/unpretty/expanded-interpolation.stdout +++ b/tests/ui/unpretty/expanded-interpolation.stdout @@ -2,6 +2,7 @@ #![no_std] //@ compile-flags: -Zunpretty=expanded //@ check-pass +//@ edition: 2015 // This test covers the AST pretty-printer's insertion of parentheses in some // macro metavariable edge cases. Synthetic parentheses (i.e. not appearing in diff --git a/tests/ui/unpretty/flattened-format-args.rs b/tests/ui/unpretty/flattened-format-args.rs index 772f44cc268e..ab065f494dc0 100644 --- a/tests/ui/unpretty/flattened-format-args.rs +++ b/tests/ui/unpretty/flattened-format-args.rs @@ -1,5 +1,6 @@ //@ compile-flags: -Zunpretty=hir -Zflatten-format-args=yes //@ check-pass +//@ edition: 2015 fn main() { let x = 1; diff --git a/tests/ui/unpretty/flattened-format-args.stdout b/tests/ui/unpretty/flattened-format-args.stdout index 2de1cdd96b5b..a5d943281ad8 100644 --- a/tests/ui/unpretty/flattened-format-args.stdout +++ b/tests/ui/unpretty/flattened-format-args.stdout @@ -4,6 +4,7 @@ use ::std::prelude::rust_2015::*; extern crate std; //@ compile-flags: -Zunpretty=hir -Zflatten-format-args=yes //@ check-pass +//@ edition: 2015 fn main() { let x = 1; diff --git a/tests/ui/unpretty/let-else-hir.rs b/tests/ui/unpretty/let-else-hir.rs index 9c231189659a..786c84a09ddd 100644 --- a/tests/ui/unpretty/let-else-hir.rs +++ b/tests/ui/unpretty/let-else-hir.rs @@ -1,5 +1,6 @@ //@ compile-flags: -Zunpretty=hir //@ check-pass +//@ edition: 2015 diff --git a/tests/ui/unpretty/let-else-hir.stdout b/tests/ui/unpretty/let-else-hir.stdout index a2ffa5de5673..a6dd943ec1b7 100644 --- a/tests/ui/unpretty/let-else-hir.stdout +++ b/tests/ui/unpretty/let-else-hir.stdout @@ -4,6 +4,7 @@ use ::std::prelude::rust_2015::*; extern crate std; //@ compile-flags: -Zunpretty=hir //@ check-pass +//@ edition: 2015 diff --git a/tests/ui/unpretty/self-hir.rs b/tests/ui/unpretty/self-hir.rs index 448d828d4446..70e0ba589fb8 100644 --- a/tests/ui/unpretty/self-hir.rs +++ b/tests/ui/unpretty/self-hir.rs @@ -1,5 +1,6 @@ //@ compile-flags: -Zunpretty=hir //@ check-pass +//@ edition: 2015 pub struct Bar { a: String, diff --git a/tests/ui/unpretty/self-hir.stdout b/tests/ui/unpretty/self-hir.stdout index 4da080dc611e..a9e80b1f5920 100644 --- a/tests/ui/unpretty/self-hir.stdout +++ b/tests/ui/unpretty/self-hir.stdout @@ -4,6 +4,7 @@ use ::std::prelude::rust_2015::*; extern crate std; //@ compile-flags: -Zunpretty=hir //@ check-pass +//@ edition: 2015 struct Bar { a: String, diff --git a/tests/ui/unpretty/unpretty-expr-fn-arg.rs b/tests/ui/unpretty/unpretty-expr-fn-arg.rs index 7f496e773c28..b2ab2e0911e5 100644 --- a/tests/ui/unpretty/unpretty-expr-fn-arg.rs +++ b/tests/ui/unpretty/unpretty-expr-fn-arg.rs @@ -6,6 +6,7 @@ //@ check-pass //@ compile-flags: -Zunpretty=hir,typed +//@ edition: 2015 #![allow(dead_code)] fn main() {} diff --git a/tests/ui/unpretty/unpretty-expr-fn-arg.stdout b/tests/ui/unpretty/unpretty-expr-fn-arg.stdout index 43aa93c83bd3..fd2e794fcac8 100644 --- a/tests/ui/unpretty/unpretty-expr-fn-arg.stdout +++ b/tests/ui/unpretty/unpretty-expr-fn-arg.stdout @@ -6,6 +6,7 @@ //@ check-pass //@ compile-flags: -Zunpretty=hir,typed +//@ edition: 2015 #![allow(dead_code)] #[prelude_import] use ::std::prelude::rust_2015::*; diff --git a/tests/ui/unsafe-binders/lifetime-resolution.rs b/tests/ui/unsafe-binders/lifetime-resolution.rs index b352acfadf28..d24315401194 100644 --- a/tests/ui/unsafe-binders/lifetime-resolution.rs +++ b/tests/ui/unsafe-binders/lifetime-resolution.rs @@ -9,7 +9,7 @@ fn foo<'a>() { fn inner<'b>() { let outer: unsafe<> &'a &'b (); - //~^ can't use generic parameters from outer item + //~^ ERROR can't use generic parameters from outer item } } diff --git a/tests/ui/unsafe/unsafe-unstable-const-fn.rs b/tests/ui/unsafe/unsafe-unstable-const-fn.rs index 5398721484a0..dd1fd8463773 100644 --- a/tests/ui/unsafe/unsafe-unstable-const-fn.rs +++ b/tests/ui/unsafe/unsafe-unstable-const-fn.rs @@ -5,7 +5,7 @@ #[rustc_const_unstable(feature = "const_foo", issue = "none")] const fn unstable(a: *const i32, b: i32) -> bool { *a == b - //~^ dereference of raw pointer is unsafe + //~^ ERROR dereference of raw pointer is unsafe } fn main() {} diff --git a/tests/ui/unsized-locals/issue-30276-feature-flagged.rs b/tests/ui/unsized-locals/issue-30276-feature-flagged.rs index 635d34f82291..8b5b321ec498 100644 --- a/tests/ui/unsized-locals/issue-30276-feature-flagged.rs +++ b/tests/ui/unsized-locals/issue-30276-feature-flagged.rs @@ -5,4 +5,5 @@ struct Test([i32]); fn main() { let _x: fn(_) -> Test = Test; -} //~^the size for values of type `[i32]` cannot be known at compilation time + //~^ ERROR the size for values of type `[i32]` cannot be known at compilation time +} diff --git a/tests/ui/unsized-locals/issue-30276.rs b/tests/ui/unsized-locals/issue-30276.rs index 9c4bf062a40e..6b67ebbec1c0 100644 --- a/tests/ui/unsized-locals/issue-30276.rs +++ b/tests/ui/unsized-locals/issue-30276.rs @@ -2,4 +2,5 @@ struct Test([i32]); fn main() { let _x: fn(_) -> Test = Test; -} //~^the size for values of type `[i32]` cannot be known at compilation time + //~^ ERROR the size for values of type `[i32]` cannot be known at compilation time +} diff --git a/tests/ui/use/auxiliary/extern-use-primitive-type-lib.rs b/tests/ui/use/auxiliary/extern-use-primitive-type-lib.rs index 18aa329ae36b..c21eea743e92 100644 --- a/tests/ui/use/auxiliary/extern-use-primitive-type-lib.rs +++ b/tests/ui/use/auxiliary/extern-use-primitive-type-lib.rs @@ -1,3 +1,3 @@ -//@ compile-flags: --edition=2018 +//@ edition: 2018 pub use u32; diff --git a/tests/ui/use/use-keyword.rs b/tests/ui/use/use-keyword.rs index 840cddcb907c..95f303651676 100644 --- a/tests/ui/use/use-keyword.rs +++ b/tests/ui/use/use-keyword.rs @@ -7,10 +7,10 @@ mod a { //~^ ERROR `self` imports are only allowed within a { } list use super as B; //~^ ERROR unresolved import `super` [E0432] - //~| no `super` in the root + //~| NOTE no `super` in the root use super::{self as C}; //~^ ERROR unresolved import `super` [E0432] - //~| no `super` in the root + //~| NOTE no `super` in the root } } diff --git a/tests/ui/use/use-mod/use-mod-2.rs b/tests/ui/use/use-mod/use-mod-2.rs index 9373a62ba36e..57ff135c4d85 100644 --- a/tests/ui/use/use-mod/use-mod-2.rs +++ b/tests/ui/use/use-mod/use-mod-2.rs @@ -1,11 +1,11 @@ mod foo { use self::{self}; //~^ ERROR unresolved import `self` [E0432] - //~| no `self` in the root + //~| NOTE no `self` in the root use super::{self}; //~^ ERROR unresolved import `super` [E0432] - //~| no `super` in the root + //~| NOTE no `super` in the root } fn main() {} diff --git a/tests/ui/variance/variance-btree-invariant-types.rs b/tests/ui/variance/variance-btree-invariant-types.rs index 09c93d0013cc..9e457c7fae80 100644 --- a/tests/ui/variance/variance-btree-invariant-types.rs +++ b/tests/ui/variance/variance-btree-invariant-types.rs @@ -2,78 +2,78 @@ use std::collections::btree_map::{IterMut, OccupiedEntry, RangeMut, VacantEntry} fn iter_cov_key<'a, 'new>(v: IterMut<'a, &'static (), ()>) -> IterMut<'a, &'new (), ()> { v - //~^ lifetime may not live long enough + //~^ ERROR lifetime may not live long enough } fn iter_cov_val<'a, 'new>(v: IterMut<'a, (), &'static ()>) -> IterMut<'a, (), &'new ()> { v - //~^ lifetime may not live long enough + //~^ ERROR lifetime may not live long enough } fn iter_contra_key<'a, 'new>(v: IterMut<'a, &'new (), ()>) -> IterMut<'a, &'static (), ()> { v - //~^ lifetime may not live long enough + //~^ ERROR lifetime may not live long enough } fn iter_contra_val<'a, 'new>(v: IterMut<'a, (), &'new ()>) -> IterMut<'a, (), &'static ()> { v - //~^ lifetime may not live long enough + //~^ ERROR lifetime may not live long enough } fn range_cov_key<'a, 'new>(v: RangeMut<'a, &'static (), ()>) -> RangeMut<'a, &'new (), ()> { v - //~^ lifetime may not live long enough + //~^ ERROR lifetime may not live long enough } fn range_cov_val<'a, 'new>(v: RangeMut<'a, (), &'static ()>) -> RangeMut<'a, (), &'new ()> { v - //~^ lifetime may not live long enough + //~^ ERROR lifetime may not live long enough } fn range_contra_key<'a, 'new>(v: RangeMut<'a, &'new (), ()>) -> RangeMut<'a, &'static (), ()> { v - //~^ lifetime may not live long enough + //~^ ERROR lifetime may not live long enough } fn range_contra_val<'a, 'new>(v: RangeMut<'a, (), &'new ()>) -> RangeMut<'a, (), &'static ()> { v - //~^ lifetime may not live long enough + //~^ ERROR lifetime may not live long enough } fn occ_cov_key<'a, 'new>(v: OccupiedEntry<'a, &'static (), ()>) -> OccupiedEntry<'a, &'new (), ()> { v - //~^ lifetime may not live long enough + //~^ ERROR lifetime may not live long enough } fn occ_cov_val<'a, 'new>(v: OccupiedEntry<'a, (), &'static ()>) -> OccupiedEntry<'a, (), &'new ()> { v - //~^ lifetime may not live long enough + //~^ ERROR lifetime may not live long enough } fn occ_contra_key<'a, 'new>(v: OccupiedEntry<'a, &'new (), ()>) -> OccupiedEntry<'a, &'static (), ()> { v - //~^ lifetime may not live long enough + //~^ ERROR lifetime may not live long enough } fn occ_contra_val<'a, 'new>(v: OccupiedEntry<'a, (), &'new ()>) -> OccupiedEntry<'a, (), &'static ()> { v - //~^ lifetime may not live long enough + //~^ ERROR lifetime may not live long enough } fn vac_cov_key<'a, 'new>(v: VacantEntry<'a, &'static (), ()>) -> VacantEntry<'a, &'new (), ()> { v - //~^ lifetime may not live long enough + //~^ ERROR lifetime may not live long enough } fn vac_cov_val<'a, 'new>(v: VacantEntry<'a, (), &'static ()>) -> VacantEntry<'a, (), &'new ()> { v - //~^ lifetime may not live long enough + //~^ ERROR lifetime may not live long enough } fn vac_contra_key<'a, 'new>(v: VacantEntry<'a, &'new (), ()>) -> VacantEntry<'a, &'static (), ()> { v - //~^ lifetime may not live long enough + //~^ ERROR lifetime may not live long enough } fn vac_contra_val<'a, 'new>(v: VacantEntry<'a, (), &'new ()>) -> VacantEntry<'a, (), &'static ()> { v - //~^ lifetime may not live long enough + //~^ ERROR lifetime may not live long enough } diff --git a/tests/ui/wasm/wasm-import-module.rs b/tests/ui/wasm/wasm-import-module.rs index bff08847d37d..2b3bca9a411b 100644 --- a/tests/ui/wasm/wasm-import-module.rs +++ b/tests/ui/wasm/wasm-import-module.rs @@ -15,7 +15,7 @@ extern "C" {} #[link(wasm_import_module = "foo", kind = "dylib")] //~ ERROR: `wasm_import_module` is incompatible with other arguments extern "C" {} -#[link(wasm_import_module = "foo", cfg(FALSE))] //~ ERROR: `wasm_import_module` is incompatible with other arguments +#[link(wasm_import_module = "foo", cfg(false))] //~ ERROR: `wasm_import_module` is incompatible with other arguments extern "C" {} fn main() {} diff --git a/tests/ui/wasm/wasm-import-module.stderr b/tests/ui/wasm/wasm-import-module.stderr index e792c33e91a9..84f437941a79 100644 --- a/tests/ui/wasm/wasm-import-module.stderr +++ b/tests/ui/wasm/wasm-import-module.stderr @@ -31,7 +31,7 @@ LL | #[link(wasm_import_module = "foo", kind = "dylib")] error: `wasm_import_module` is incompatible with other arguments in `#[link]` attributes --> $DIR/wasm-import-module.rs:18:8 | -LL | #[link(wasm_import_module = "foo", cfg(FALSE))] +LL | #[link(wasm_import_module = "foo", cfg(false))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 6 previous errors diff --git a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.stderr b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.stderr index 3b4de0753af0..59eef0c63278 100644 --- a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.stderr +++ b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.stderr @@ -53,6 +53,12 @@ LL | trait Trait { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information +error: defaults for const parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions + --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:6:12 + | +LL | fn fnc(&self) -> Trait { + | ^^^^^^^^^^^^^^^^^^^^ + warning: trait objects without an explicit `dyn` are deprecated --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:6:44 | @@ -66,12 +72,6 @@ help: if this is a dyn-compatible trait, use `dyn` LL | fn fnc(&self) -> dyn Trait { | +++ -error: defaults for const parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions - --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:6:12 - | -LL | fn fnc(&self) -> Trait { - | ^^^^^^^^^^^^^^^^^^^^ - warning: trait objects without an explicit `dyn` are deprecated --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:6:21 | diff --git a/tests/ui/wf/issue-95665.rs b/tests/ui/wf/issue-95665.rs index 67923cbb2d6b..422ffd11ee3f 100644 --- a/tests/ui/wf/issue-95665.rs +++ b/tests/ui/wf/issue-95665.rs @@ -12,7 +12,7 @@ pub struct Struct { extern "C" { static VAR: Struct; - //~^ 14:17: 14:27: the trait bound `u8: Trait` is not satisfied [E0277] + //~^ ERROR the trait bound `u8: Trait` is not satisfied [E0277] } fn main() {} diff --git a/tests/ui/wf/wf-normalization-sized.rs b/tests/ui/wf/wf-normalization-sized.rs index 80b2c8803ff1..5396cc8b32a8 100644 --- a/tests/ui/wf/wf-normalization-sized.rs +++ b/tests/ui/wf/wf-normalization-sized.rs @@ -17,10 +17,10 @@ impl WellUnformed for T { } const _: <[[[[[[u8]]]]]] as WellUnformed>::RequestNormalize = (); -//[next]~^ the size for values of type `[[[[[u8]]]]]` cannot be known at compilation time -//[next]~| the size for values of type `[[[[[u8]]]]]` cannot be known at compilation time +//[next]~^ ERROR the size for values of type `[[[[[u8]]]]]` cannot be known at compilation time +//[next]~| ERROR the size for values of type `[[[[[u8]]]]]` cannot be known at compilation time const _: as WellUnformed>::RequestNormalize = (); -//[next]~^ the size for values of type `str` cannot be known at compilation time -//[next]~| the size for values of type `str` cannot be known at compilation time +//[next]~^ ERROR the size for values of type `str` cannot be known at compilation time +//[next]~| ERROR the size for values of type `str` cannot be known at compilation time fn main() {} diff --git a/triagebot.toml b/triagebot.toml index 756536dc2e7b..226f024c156b 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1123,9 +1123,10 @@ cc = ["@ZuseZ4"] warn_non_default_branch.enable = true contributing_url = "https://rustc-dev-guide.rust-lang.org/getting-started.html" users_on_vacation = [ + "fmease", "jyn514", - "saethlin", "Noratrieb", + "spastorino", ] [[assign.warn_non_default_branch.exceptions]] @@ -1338,9 +1339,11 @@ compiletest = [ "/src/doc/nomicon" = ["@ehuss"] "/src/doc/reference" = ["@ehuss"] "/src/doc/rust-by-example" = ["@ehuss"] +"/src/doc/rustc" = ["compiler", "@ehuss"] "/src/doc/rustc-dev-guide" = ["compiler"] "/src/doc/rustdoc" = ["rustdoc"] "/src/doc/style-guide" = ["style-team"] +"/src/doc/unstable-book" = ["compiler"] "/src/etc" = ["@Mark-Simulacrum"] "/src/librustdoc" = ["rustdoc"] "/src/llvm-project" = ["@cuviper"]