diff options
665 files changed, 13919 insertions, 10838 deletions
diff --git a/Cargo.lock b/Cargo.lock index 0369442f11c..e7aa317ad75 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -272,17 +272,6 @@ dependencies = [ [[package]] name = "bstr" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" -dependencies = [ - "lazy_static", - "memchr", - "regex-automata 0.1.10", -] - -[[package]] -name = "bstr" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ffdb39cb703212f3c11973452c2861b972f757b021158f3516ba10f2fa8b2c1" @@ -417,9 +406,9 @@ version = "0.1.0" [[package]] name = "cc" -version = "1.0.77" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9f73505338f7d905b19d18738976aae232eb46b8efc15554ffc56deb5d9ebe4" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" [[package]] name = "cfg-if" @@ -667,16 +656,6 @@ dependencies = [ ] [[package]] -name = "codespan-reporting" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" -dependencies = [ - "termcolor", - "unicode-width", -] - -[[package]] name = "collect-license-metadata" version = "0.1.0" dependencies = [ @@ -842,9 +821,9 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.6" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521" +checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" dependencies = [ "cfg-if", "crossbeam-utils", @@ -863,14 +842,14 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.13" +version = "0.9.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01a9af1f4c2ef74bb8aa1f7e19706bc72d03598c8a570bb5de72243c7a9d9d5a" +checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695" dependencies = [ "autocfg", "cfg-if", "crossbeam-utils", - "memoffset 0.7.1", + "memoffset", "scopeguard", ] @@ -944,50 +923,6 @@ dependencies = [ ] [[package]] -name = "cxx" -version = "1.0.94" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f61f1b6389c3fe1c316bf8a4dccc90a38208354b330925bce1f74a6c4756eb93" -dependencies = [ - "cc", - "cxxbridge-flags", - "cxxbridge-macro", - "link-cplusplus", -] - -[[package]] -name = "cxx-build" -version = "1.0.94" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12cee708e8962df2aeb38f594aae5d827c022b6460ac71a7a3e2c3c2aae5a07b" -dependencies = [ - "cc", - "codespan-reporting", - "once_cell", - "proc-macro2", - "quote", - "scratch", - "syn 2.0.8", -] - -[[package]] -name = "cxxbridge-flags" -version = "1.0.94" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7944172ae7e4068c533afbb984114a56c46e9ccddda550499caa222902c7f7bb" - -[[package]] -name = "cxxbridge-macro" -version = "1.0.94" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2345488264226bf682893e25de0769f3360aac9957980ec49361b083ddaa5bc5" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.8", -] - -[[package]] name = "datafrog" version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1273,7 +1208,7 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3cf3a800ff6e860c863ca6d4b16fd999db8b752819c1606884047b73e468535" dependencies = [ - "memoffset 0.8.0", + "memoffset", "rustc_version", ] @@ -1548,12 +1483,12 @@ checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" [[package]] name = "globset" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a1e17342619edbc21a964c2afbeb6c820c6a2560032872f397bb97ea127bd0a" +checksum = "029d74589adefde59de1a0c4f4732695c32805624aec7b68d91503d4dba79afc" dependencies = [ "aho-corasick", - "bstr 0.2.17", + "bstr", "fnv", "log", "regex", @@ -1688,12 +1623,11 @@ dependencies = [ [[package]] name = "iana-time-zone-haiku" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" dependencies = [ - "cxx", - "cxx-build", + "cc", ] [[package]] @@ -1780,11 +1714,10 @@ checksum = "c3360c7b59e5ffa2653671fb74b4741a5d343c03f331c0a4aeda42b5c2b0ec7d" [[package]] name = "ignore" -version = "0.4.18" +version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "713f1b139373f96a2e0ce3ac931cd01ee973c3c5dd7c40c0c2efe96ad2b6751d" +checksum = "dbe7873dab538a9a44ad79ede1faf5f30d49f9a5c883ddbab48bce81b64b7492" dependencies = [ - "crossbeam-utils", "globset", "lazy_static", "log", @@ -2036,15 +1969,6 @@ dependencies = [ ] [[package]] -name = "link-cplusplus" -version = "1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5" -dependencies = [ - "cc", -] - -[[package]] name = "linkchecker" version = "0.1.0" dependencies = [ @@ -2226,24 +2150,6 @@ dependencies = [ [[package]] name = "memoffset" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" -dependencies = [ - "autocfg", -] - -[[package]] -name = "memoffset" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" -dependencies = [ - "autocfg", -] - -[[package]] -name = "memoffset" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1" @@ -2439,11 +2345,11 @@ checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" [[package]] name = "opener" -version = "0.5.0" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ea3ebcd72a54701f56345f16785a6d3ac2df7e986d273eb4395c0b01db17952" +checksum = "293c15678e37254c15bd2f092314abb4e51d7fdde05c2021279c12631b54f005" dependencies = [ - "bstr 0.2.17", + "bstr", "winapi", ] @@ -4082,7 +3988,7 @@ version = "0.0.0" dependencies = [ "field-offset", "measureme", - "memoffset 0.6.5", + "memoffset", "rustc-rayon-core", "rustc_ast", "rustc_data_structures", @@ -4380,6 +4286,16 @@ dependencies = [ ] [[package]] +name = "rustdoc-gui-test" +version = "0.1.0" +dependencies = [ + "build_helper", + "compiletest", + "getopts", + "walkdir", +] + +[[package]] name = "rustdoc-json-types" version = "0.1.0" dependencies = [ @@ -4522,12 +4438,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] -name = "scratch" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1792db035ce95be60c3f8853017b3999209281c24e2ba5bc8e59bf97a0c590c1" - -[[package]] name = "self_cell" version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -4972,22 +4882,22 @@ checksum = "aac81b6fd6beb5884b0cf3321b8117e6e5d47ecb6fc89f414cfdcca8b2fe2dd8" [[package]] name = "thiserror" -version = "1.0.38" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" +checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.38" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" +checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", - "syn 1.0.102", + "syn 2.0.8", ] [[package]] @@ -5225,7 +5135,7 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "191a442639ea102fa62671026047e51d574bfda44b7fdf32151d7314624c1cd2" dependencies = [ - "bstr 1.3.0", + "bstr", "cargo-platform", "cargo_metadata 0.15.3", "color-eyre", diff --git a/Cargo.toml b/Cargo.toml index 53331e2869f..6e84df5c693 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,4 +1,5 @@ [workspace] +resolver = "1" members = [ "compiler/rustc", "library/std", @@ -40,6 +41,7 @@ members = [ "src/tools/generate-copyright", "src/tools/suggest-tests", "src/tools/generate-windows-sys", + "src/tools/rustdoc-gui-test", ] exclude = [ diff --git a/RELEASES.md b/RELEASES.md index 85266a17550..fa95df685aa 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,139 @@ +Version 1.70.0 (2023-06-01) +========================== + +<a id="1.70.0-Language"></a> + +Language +-------- +- [Relax ordering rules for `asm!` operands](https://github.com/rust-lang/rust/pull/105798/) +- [Properly allow macro expanded `format_args` invocations to uses captures](https://github.com/rust-lang/rust/pull/106505/) +- [Lint ambiguous glob re-exports](https://github.com/rust-lang/rust/pull/107880/) +- [Perform const and unsafe checking for expressions in `let _ = expr` position.](https://github.com/rust-lang/rust/pull/102256/) + +<a id="1.70.0-Compiler"></a> + +Compiler +-------- +- [Extend -Cdebuginfo with new options and named aliases](https://github.com/rust-lang/rust/pull/109808/) + This provides a smaller version of debuginfo for cases that only need line number information + (`-Cdebuginfo=line-tables-only`), which may eventually become the default for `-Cdebuginfo=1`. +- [Make `unused_allocation` lint against `Box::new` too](https://github.com/rust-lang/rust/pull/104363/) +- [Detect uninhabited types early in const eval](https://github.com/rust-lang/rust/pull/109435/) +- [Switch to LLD as default linker for {arm,thumb}v4t-none-eabi](https://github.com/rust-lang/rust/pull/109721/) +- [Add tier 3 target `loongarch64-unknown-linux-gnu`](https://github.com/rust-lang/rust/pull/96971) +- [Add tier 3 target for `i586-pc-nto-qnx700` (QNX Neutrino RTOS, version 7.0)](https://github.com/rust-lang/rust/pull/109173/), +- [Insert alignment checks for pointer dereferences as debug assertions](https://github.com/rust-lang/rust/pull/98112) + This catches undefined behavior at runtime, and may cause existing code to fail. + +Refer to Rust's [platform support page][platform-support-doc] +for more information on Rust's tiered platform support. + +<a id="1.70.0-Libraries"></a> + +Libraries +--------- +- [Document NonZeroXxx layout guarantees](https://github.com/rust-lang/rust/pull/94786/) +- [Windows: make `Command` prefer non-verbatim paths](https://github.com/rust-lang/rust/pull/96391/) +- [Implement Default for some alloc/core iterators](https://github.com/rust-lang/rust/pull/99929/) +- [Fix handling of trailing bare CR in str::lines](https://github.com/rust-lang/rust/pull/100311/) +- [allow negative numeric literals in `concat!`](https://github.com/rust-lang/rust/pull/106844/) +- [Add documentation about the memory layout of `Cell`](https://github.com/rust-lang/rust/pull/106921/) +- [Use `partial_cmp` to implement tuple `lt`/`le`/`ge`/`gt`](https://github.com/rust-lang/rust/pull/108157/) +- [Stabilize `atomic_as_ptr`](https://github.com/rust-lang/rust/pull/108419/) +- [Stabilize `nonnull_slice_from_raw_parts`](https://github.com/rust-lang/rust/pull/97506/) +- [Partial stabilization of `once_cell`](https://github.com/rust-lang/rust/pull/105587/) +- [Stabilize `nonzero_min_max`](https://github.com/rust-lang/rust/pull/106633/) +- [Flatten/inline format_args!() and (string and int) literal arguments into format_args!()](https://github.com/rust-lang/rust/pull/106824/) +- [Stabilize movbe target feature](https://github.com/rust-lang/rust/pull/107711/) +- [don't splice from files into pipes in io::copy](https://github.com/rust-lang/rust/pull/108283/) +- [Add a builtin unstable `FnPtr` trait that is implemented for all function pointers](https://github.com/rust-lang/rust/pull/108080/) + This extends `Debug`, `Pointer`, `Hash`, `PartialEq`, `Eq`, `PartialOrd`, and `Ord` + implementations for function pointers with all ABIs. + +<a id="1.70.0-Stabilized-APIs"></a> + +Stabilized APIs +--------------- + +- [`NonZero*::MIN/MAX`](https://doc.rust-lang.org/stable/std/num/struct.NonZeroI8.html#associatedconstant.MIN) +- [`BinaryHeap::retain`](https://doc.rust-lang.org/stable/std/collections/struct.BinaryHeap.html#method.retain) +- [`Default for std::collections::binary_heap::IntoIter`](https://doc.rust-lang.org/stable/std/collections/binary_heap/struct.IntoIter.html) +- [`Default for std::collections::btree_map::{IntoIter, Iter, IterMut}`](https://doc.rust-lang.org/stable/std/collections/btree_map/struct.IntoIter.html) +- [`Default for std::collections::btree_map::{IntoKeys, Keys}`](https://doc.rust-lang.org/stable/std/collections/btree_map/struct.IntoKeys.html) +- [`Default for std::collections::btree_map::{IntoValues, Values}`](https://doc.rust-lang.org/stable/std/collections/btree_map/struct.IntoKeys.html) +- [`Default for std::collections::btree_map::Range`](https://doc.rust-lang.org/stable/std/collections/btree_map/struct.Range.html) +- [`Default for std::collections::btree_set::{IntoIter, Iter}`](https://doc.rust-lang.org/stable/std/collections/btree_set/struct.IntoIter.html) +- [`Default for std::collections::btree_set::Range`](https://doc.rust-lang.org/stable/std/collections/btree_set/struct.Range.html) +- [`Default for std::collections::linked_list::{IntoIter, Iter, IterMut}`](https://doc.rust-lang.org/stable/alloc/collections/linked_list/struct.IntoIter.html) +- [`Default for std::vec::IntoIter`](https://doc.rust-lang.org/stable/alloc/vec/struct.IntoIter.html#impl-Default-for-IntoIter%3CT,+A%3E) +- [`Default for std::iter::Chain`](https://doc.rust-lang.org/stable/std/iter/struct.Chain.html) +- [`Default for std::iter::Cloned`](https://doc.rust-lang.org/stable/std/iter/struct.Cloned.html) +- [`Default for std::iter::Copied`](https://doc.rust-lang.org/stable/std/iter/struct.Copied.html) +- [`Default for std::iter::Enumerate`](https://doc.rust-lang.org/stable/std/iter/struct.Enumerate.html) +- [`Default for std::iter::Flatten`](https://doc.rust-lang.org/stable/std/iter/struct.Flatten.html) +- [`Default for std::iter::Fuse`](https://doc.rust-lang.org/stable/std/iter/struct.Fuse.html) +- [`Default for std::iter::Rev`](https://doc.rust-lang.org/stable/std/iter/struct.Rev.html) +- [`Default for std::slice::Iter`](https://doc.rust-lang.org/stable/std/slice/struct.Iter.html) +- [`Default for std::slice::IterMut`](https://doc.rust-lang.org/stable/std/slice/struct.IterMut.html) +- [`Rc::into_inner`](https://doc.rust-lang.org/stable/alloc/rc/struct.Rc.html#method.into_inner) +- [`Arc::into_inner`](https://doc.rust-lang.org/stable/alloc/sync/struct.Arc.html#method.into_inner) +- [`std::cell::OnceCell`](https://doc.rust-lang.org/stable/std/cell/struct.OnceCell.html) +- [`Option::is_some_and`](https://doc.rust-lang.org/stable/std/option/enum.Option.html#method.is_some_and) +- [`NonNull::slice_from_raw_parts`](https://doc.rust-lang.org/stable/std/ptr/struct.NonNull.html#method.slice_from_raw_parts) +- [`Result::is_ok_and`](https://doc.rust-lang.org/stable/std/result/enum.Result.html#method.is_ok_and) +- [`Result::is_err_and`](https://doc.rust-lang.org/stable/std/result/enum.Result.html#method.is_err_and) +- [`std::sync::atomic::Atomic*::as_ptr`](https://doc.rust-lang.org/stable/std/sync/atomic/struct.AtomicU8.html#method.as_ptr) +- [`std::io::IsTerminal`](https://doc.rust-lang.org/stable/std/io/trait.IsTerminal.html) +- [`std::os::linux::net::SocketAddrExt`](https://doc.rust-lang.org/stable/std/os/linux/net/trait.SocketAddrExt.html) +- [`std::os::unix::net::UnixDatagram::bind_addr`](https://doc.rust-lang.org/stable/std/os/unix/net/struct.UnixDatagram.html#method.bind_addr) +- [`std::os::unix::net::UnixDatagram::connect_addr`](https://doc.rust-lang.org/stable/std/os/unix/net/struct.UnixDatagram.html#method.connect_addr) +- [`std::os::unix::net::UnixDatagram::send_to_addr`](https://doc.rust-lang.org/stable/std/os/unix/net/struct.UnixDatagram.html#method.send_to_addr) +- [`std::os::unix::net::UnixListener::bind_addr`](https://doc.rust-lang.org/stable/std/os/unix/net/struct.UnixListener.html#method.bind_addr) +- [`std::path::Path::as_mut_os_str`](https://doc.rust-lang.org/stable/std/path/struct.Path.html#method.as_mut_os_str) +- [`std::sync::OnceLock`](https://doc.rust-lang.org/stable/std/sync/struct.OnceLock.html) + +<a id="1.70.0-Cargo"></a> + +Cargo +----- + +- [Add `CARGO_PKG_README`](https://github.com/rust-lang/cargo/pull/11645/) +- [Make `sparse` the default protocol for crates.io](https://github.com/rust-lang/cargo/pull/11791/) +- [Accurately show status when downgrading dependencies](https://github.com/rust-lang/cargo/pull/11839/) +- [Use registry.default for login/logout](https://github.com/rust-lang/cargo/pull/11949/) +- [Stabilize `cargo logout`](https://github.com/rust-lang/cargo/pull/11950/) + +<a id="1.70.0-Misc"></a> + +Misc +---- + +- [Stabilize rustdoc `--test-run-directory`](https://github.com/rust-lang/rust/pull/103682/) + +<a id="1.70.0-Compatibility-Notes"></a> + +Compatibility Notes +------------------- + +- [Prevent stable `libtest` from supporting `-Zunstable-options`](https://github.com/rust-lang/rust/pull/109044/) +- [Perform const and unsafe checking for expressions in `let _ = expr` position.](https://github.com/rust-lang/rust/pull/102256/) +- [WebAssembly targets enable `sign-ext` and `mutable-globals` features in codegen](https://github.com/rust-lang/rust/issues/109807) + This may cause incompatibility with older execution environments. +- [Insert alignment checks for pointer dereferences as debug assertions](https://github.com/rust-lang/rust/pull/98112) + This catches undefined behavior at runtime, and may cause existing code to fail. + +<a id="1.70.0-Internal-Changes"></a> + +Internal Changes +---------------- + +These changes do not affect any public interfaces of Rust, but they represent +significant improvements to the performance or internals of rustc and related +tools. + +- [Upgrade to LLVM 16](https://github.com/rust-lang/rust/pull/109474/) +- [Use SipHash-1-3 instead of SipHash-2-4 for StableHasher](https://github.com/rust-lang/rust/pull/107925/) + Version 1.69.0 (2023-04-20) ========================== diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index 7ef39f8026b..6646fa9446f 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -11,6 +11,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::sync::Lrc; use rustc_macros::HashStable_Generic; use rustc_span::symbol::{kw, sym}; +#[cfg_attr(not(bootstrap), allow(hidden_glob_reexports))] use rustc_span::symbol::{Ident, Symbol}; use rustc_span::{self, edition::Edition, Span, DUMMY_SP}; use std::borrow::Cow; diff --git a/compiler/rustc_ast_lowering/messages.ftl b/compiler/rustc_ast_lowering/messages.ftl index 21b2a3c22fa..f63a9bfcd70 100644 --- a/compiler/rustc_ast_lowering/messages.ftl +++ b/compiler/rustc_ast_lowering/messages.ftl @@ -1,99 +1,121 @@ -ast_lowering_generic_type_with_parentheses = - parenthesized type parameters may only be used with a `Fn` trait - .label = only `Fn` traits may use parentheses - -ast_lowering_use_angle_brackets = use angle brackets instead +ast_lowering_abi_specified_multiple_times = + `{$prev_name}` ABI specified multiple times + .label = previously specified here + .note = these ABIs are equivalent on the current target -ast_lowering_invalid_abi = - invalid ABI: found `{$abi}` - .label = invalid ABI - .note = invoke `{$command}` for a full list of supported calling conventions. +ast_lowering_arbitrary_expression_in_pattern = + arbitrary expressions aren't allowed in patterns -ast_lowering_invalid_abi_suggestion = did you mean +ast_lowering_argument = argument ast_lowering_assoc_ty_parentheses = parenthesized generic arguments cannot be used in associated type constraints -ast_lowering_remove_parentheses = remove these parentheses - -ast_lowering_misplaced_impl_trait = - `impl Trait` only allowed in function and inherent method return types, not in {$position} - -ast_lowering_misplaced_assoc_ty_binding = - associated type bounds are only allowed in where clauses and function signatures, not in {$position} +ast_lowering_async_generators_not_supported = + `async` generators are not yet supported -ast_lowering_underscore_expr_lhs_assign = - in expressions, `_` can only be used on the left-hand side of an assignment - .label = `_` not allowed here +ast_lowering_async_non_move_closure_not_supported = + `async` non-`move` closures with parameters are not currently supported + .help = consider using `let` statements to manually capture variables by reference before entering an `async move` closure -ast_lowering_base_expression_double_dot = - base expression required after `..` - .label = add a base expression here +ast_lowering_att_syntax_only_x86 = + the `att_syntax` option is only supported on x86 ast_lowering_await_only_in_async_fn_and_blocks = `await` is only allowed inside `async` functions and blocks .label = only allowed inside `async` functions and blocks -ast_lowering_this_not_async = this is not `async` +ast_lowering_bad_return_type_notation_inputs = + argument types not allowed with return type notation + .suggestion = remove the input types -ast_lowering_generator_too_many_parameters = - too many parameters for a generator (expected 0 or 1 parameters) +ast_lowering_bad_return_type_notation_needs_dots = + return type notation arguments must be elided with `..` + .suggestion = add `..` + +ast_lowering_bad_return_type_notation_output = + return type not allowed with return type notation + .suggestion = remove the return type + +ast_lowering_base_expression_double_dot = + base expression required after `..` + .label = add a base expression here + +ast_lowering_clobber_abi_not_supported = + `clobber_abi` is not supported on this target ast_lowering_closure_cannot_be_static = closures cannot be static -ast_lowering_async_non_move_closure_not_supported = - `async` non-`move` closures with parameters are not currently supported - .help = consider using `let` statements to manually capture variables by reference before entering an `async move` closure +ast_lowering_does_not_support_modifiers = + the `{$class_name}` register class does not support template modifiers + +ast_lowering_extra_double_dot = + `..` can only be used once per {$ctx} pattern + .label = can only be used once per {$ctx} pattern ast_lowering_functional_record_update_destructuring_assignment = functional record updates are not allowed in destructuring assignments .suggestion = consider removing the trailing pattern -ast_lowering_async_generators_not_supported = - `async` generators are not yet supported +ast_lowering_generator_too_many_parameters = + too many parameters for a generator (expected 0 or 1 parameters) -ast_lowering_inline_asm_unsupported_target = - inline assembly is unsupported on this target +ast_lowering_generic_type_with_parentheses = + parenthesized type parameters may only be used with a `Fn` trait + .label = only `Fn` traits may use parentheses -ast_lowering_att_syntax_only_x86 = - the `att_syntax` option is only supported on x86 +ast_lowering_inclusive_range_with_no_end = inclusive range with no end -ast_lowering_abi_specified_multiple_times = - `{$prev_name}` ABI specified multiple times - .label = previously specified here - .note = these ABIs are equivalent on the current target +ast_lowering_inline_asm_unsupported_target = + inline assembly is unsupported on this target -ast_lowering_clobber_abi_not_supported = - `clobber_abi` is not supported on this target +ast_lowering_invalid_abi = + invalid ABI: found `{$abi}` + .label = invalid ABI + .note = invoke `{$command}` for a full list of supported calling conventions. ast_lowering_invalid_abi_clobber_abi = invalid ABI for `clobber_abi` .note = the following ABIs are supported on this target: {$supported_abis} +ast_lowering_invalid_abi_suggestion = did you mean + +ast_lowering_invalid_asm_template_modifier_const = + asm template modifiers are not allowed for `const` arguments + +ast_lowering_invalid_asm_template_modifier_reg_class = + invalid asm template modifier for this register class + +ast_lowering_invalid_asm_template_modifier_sym = + asm template modifiers are not allowed for `sym` arguments + ast_lowering_invalid_register = invalid register `{$reg}`: {$error} ast_lowering_invalid_register_class = invalid register class `{$reg_class}`: {$error} -ast_lowering_invalid_asm_template_modifier_reg_class = - invalid asm template modifier for this register class +ast_lowering_misplaced_assoc_ty_binding = + associated type bounds are only allowed in where clauses and function signatures, not in {$position} -ast_lowering_argument = argument +ast_lowering_misplaced_double_dot = + `..` patterns are not allowed here + .note = only allowed in tuple, tuple struct, and slice patterns -ast_lowering_template_modifier = template modifier +ast_lowering_misplaced_impl_trait = + `impl Trait` only allowed in function and inherent method return types, not in {$position} -ast_lowering_support_modifiers = - the `{$class_name}` register class supports the following template modifiers: {$modifiers} +ast_lowering_misplaced_relax_trait_bound = + `?Trait` bounds are only permitted at the point where a type parameter is declared -ast_lowering_does_not_support_modifiers = - the `{$class_name}` register class does not support template modifiers +ast_lowering_not_supported_for_lifetime_binder_async_closure = + `for<...>` binders on `async` closures are not currently supported -ast_lowering_invalid_asm_template_modifier_const = - asm template modifiers are not allowed for `const` arguments +ast_lowering_previously_used_here = previously used here -ast_lowering_invalid_asm_template_modifier_sym = - asm template modifiers are not allowed for `sym` arguments +ast_lowering_register1 = register `{$reg1_name}` + +ast_lowering_register2 = register `{$reg2_name}` ast_lowering_register_class_only_clobber = register class `{$reg_class_name}` can only be used as a clobber, not as an input or output @@ -102,9 +124,7 @@ ast_lowering_register_conflict = register `{$reg1_name}` conflicts with register `{$reg2_name}` .help = use `lateout` instead of `out` to avoid conflict -ast_lowering_register1 = register `{$reg1_name}` - -ast_lowering_register2 = register `{$reg2_name}` +ast_lowering_remove_parentheses = remove these parentheses ast_lowering_sub_tuple_binding = `{$ident_name} @` is not allowed in a {$ctx} @@ -113,26 +133,12 @@ ast_lowering_sub_tuple_binding = ast_lowering_sub_tuple_binding_suggestion = if you don't need to use the contents of {$ident}, discard the tuple's remaining fields -ast_lowering_extra_double_dot = - `..` can only be used once per {$ctx} pattern - .label = can only be used once per {$ctx} pattern - -ast_lowering_previously_used_here = previously used here - -ast_lowering_misplaced_double_dot = - `..` patterns are not allowed here - .note = only allowed in tuple, tuple struct, and slice patterns - -ast_lowering_misplaced_relax_trait_bound = - `?Trait` bounds are only permitted at the point where a type parameter is declared - -ast_lowering_not_supported_for_lifetime_binder_async_closure = - `for<...>` binders on `async` closures are not currently supported +ast_lowering_support_modifiers = + the `{$class_name}` register class supports the following template modifiers: {$modifiers} -ast_lowering_arbitrary_expression_in_pattern = - arbitrary expressions aren't allowed in patterns +ast_lowering_template_modifier = template modifier -ast_lowering_inclusive_range_with_no_end = inclusive range with no end +ast_lowering_this_not_async = this is not `async` ast_lowering_trait_fn_async = functions in traits cannot be declared `async` @@ -140,14 +146,8 @@ ast_lowering_trait_fn_async = .note = `async` trait functions are not currently supported .note2 = consider using the `async-trait` crate: https://crates.io/crates/async-trait -ast_lowering_bad_return_type_notation_inputs = - argument types not allowed with return type notation - .suggestion = remove the input types - -ast_lowering_bad_return_type_notation_needs_dots = - return type notation arguments must be elided with `..` - .suggestion = add `..` +ast_lowering_underscore_expr_lhs_assign = + in expressions, `_` can only be used on the left-hand side of an assignment + .label = `_` not allowed here -ast_lowering_bad_return_type_notation_output = - return type not allowed with return type notation - .suggestion = remove the return type +ast_lowering_use_angle_brackets = use angle brackets instead diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs index 941d3179587..d350498bc96 100644 --- a/compiler/rustc_ast_lowering/src/asm.rs +++ b/compiler/rustc_ast_lowering/src/asm.rs @@ -44,6 +44,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { | asm::InlineAsmArch::AArch64 | asm::InlineAsmArch::RiscV32 | asm::InlineAsmArch::RiscV64 + | asm::InlineAsmArch::LoongArch64 ); if !is_stable && !self.tcx.features().asm_experimental_arch { feature_err( diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl index 2f413789e77..2f0ac0c2b19 100644 --- a/compiler/rustc_ast_passes/messages.ftl +++ b/compiler/rustc_ast_passes/messages.ftl @@ -1,64 +1,3 @@ -ast_passes_forbidden_let = - `let` expressions are not supported here - .note = only supported directly in conditions of `if` and `while` expressions - .not_supported_or = `||` operators are not supported in let chain expressions - .not_supported_parentheses = `let`s wrapped in parentheses are not supported in a context with let chains - -ast_passes_forbidden_let_stable = - expected expression, found statement (`let`) - .note = variable declaration using `let` is a statement - -ast_passes_deprecated_where_clause_location = - where clause not allowed here - -ast_passes_keyword_lifetime = - lifetimes cannot use keyword names - -ast_passes_invalid_label = - invalid label name `{$name}` - -ast_passes_visibility_not_permitted = - visibility qualifiers are not permitted here - .enum_variant = enum variants and their fields always share the visibility of the enum they are in - .trait_impl = trait items always share the visibility of their trait - .individual_impl_items = place qualifiers on individual impl items instead - .individual_foreign_items = place qualifiers on individual foreign items instead - -ast_passes_trait_fn_const = - functions in traits cannot be declared const - .label = functions in traits cannot be const - -ast_passes_forbidden_lifetime_bound = - lifetime bounds cannot be used in this context - -ast_passes_forbidden_non_lifetime_param = - only lifetime parameters can be used in this context - -ast_passes_fn_param_too_many = - function can not have more than {$max_num_args} arguments - -ast_passes_fn_param_c_var_args_only = - C-variadic function must be declared with at least one named argument - -ast_passes_fn_param_c_var_args_not_last = - `...` must be the last argument of a C-variadic function - -ast_passes_fn_param_doc_comment = - documentation comments cannot be applied to function parameters - .label = doc comments are not allowed here - -ast_passes_fn_param_forbidden_attr = - allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters - -ast_passes_fn_param_forbidden_self = - `self` parameter is only allowed in associated functions - .label = not semantically valid as function parameter - .note = associated functions are those in `impl` or `trait` definitions - -ast_passes_forbidden_default = - `default` is only allowed on items in trait impls - .label = `default` because of this - ast_passes_assoc_const_without_body = associated constant in `impl` without body .suggestion = provide a definition for the constant @@ -71,36 +10,73 @@ ast_passes_assoc_type_without_body = associated type in `impl` without body .suggestion = provide a definition for the type +ast_passes_at_least_one_trait = at least one trait must be specified + +ast_passes_auto_generic = auto traits cannot have generic parameters + .label = auto trait cannot have generic parameters + .suggestion = remove the parameters + +ast_passes_auto_items = auto traits cannot have associated items + .label = {ast_passes_auto_items} + .suggestion = remove these associated items + +ast_passes_auto_super_lifetime = auto traits cannot have super traits or lifetime bounds + .label = {ast_passes_auto_super_lifetime} + .suggestion = remove the super traits or lifetime bounds + +ast_passes_bad_c_variadic = only foreign or `unsafe extern "C"` functions may be C-variadic + +ast_passes_body_in_extern = incorrect `{$kind}` inside `extern` block + .cannot_have = cannot have a body + .invalid = the invalid body + .existing = `extern` blocks define existing foreign {$kind}s and {$kind}s inside of them cannot have a body + +ast_passes_bound_in_context = bounds on `type`s in {$ctx} have no effect + +ast_passes_const_and_async = functions cannot be both `const` and `async` + .const = `const` because of this + .async = `async` because of this + .label = {""} + ast_passes_const_without_body = free constant item without body .suggestion = provide a definition for the constant -ast_passes_static_without_body = - free static item without body - .suggestion = provide a definition for the static +ast_passes_constraint_on_negative_bound = + associated type constraints not allowed on negative bounds -ast_passes_ty_alias_without_body = - free type alias without body - .suggestion = provide a definition for the type +ast_passes_deprecated_where_clause_location = + where clause not allowed here -ast_passes_fn_without_body = - free function without a body - .suggestion = provide a definition for the function +ast_passes_equality_in_where = equality constraints are not yet supported in `where` clauses + .label = not supported + .suggestion = if `{$ident}` is an associated type you're trying to set, use the associated type binding syntax + .suggestion_path = if `{$trait_segment}::{$potential_assoc}` is an associated type you're trying to set, use the associated type binding syntax + .note = see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information ast_passes_extern_block_suggestion = if you meant to declare an externally defined function, use an `extern` block -ast_passes_bound_in_context = bounds on `type`s in {$ctx} have no effect +ast_passes_extern_fn_qualifiers = functions in `extern` blocks cannot have qualifiers + .label = in this `extern` block + .suggestion = remove the qualifiers + +ast_passes_extern_item_ascii = items in `extern` blocks cannot use non-ascii identifiers + .label = in this `extern` block + .note = this limitation may be lifted in the future; see issue #83942 <https://github.com/rust-lang/rust/issues/83942> for more information + +ast_passes_extern_keyword_link = for more information, visit https://doc.rust-lang.org/std/keyword.extern.html ast_passes_extern_types_cannot = `type`s inside `extern` blocks cannot have {$descr} .suggestion = remove the {$remove_descr} .label = `extern` block begins here -ast_passes_extern_keyword_link = for more information, visit https://doc.rust-lang.org/std/keyword.extern.html +ast_passes_extern_without_abi = extern declarations without an explicit ABI are deprecated -ast_passes_body_in_extern = incorrect `{$kind}` inside `extern` block - .cannot_have = cannot have a body - .invalid = the invalid body - .existing = `extern` blocks define existing foreign {$kind}s and {$kind}s inside of them cannot have a body +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 + +ast_passes_fieldless_union = unions cannot have zero fields ast_passes_fn_body_extern = incorrect function inside `extern` block .cannot_have = cannot have a body @@ -108,35 +84,50 @@ ast_passes_fn_body_extern = incorrect function inside `extern` block .help = you might have meant to write a function accessible through FFI, which can be done by writing `extern fn` outside of the `extern` block .label = `extern` blocks define existing foreign functions and functions inside of them cannot have a body -ast_passes_extern_fn_qualifiers = functions in `extern` blocks cannot have qualifiers - .label = in this `extern` block - .suggestion = remove the qualifiers +ast_passes_fn_param_c_var_args_not_last = + `...` must be the last argument of a C-variadic function -ast_passes_extern_item_ascii = items in `extern` blocks cannot use non-ascii identifiers - .label = in this `extern` block - .note = this limitation may be lifted in the future; see issue #83942 <https://github.com/rust-lang/rust/issues/83942> for more information +ast_passes_fn_param_c_var_args_only = + C-variadic function must be declared with at least one named argument -ast_passes_bad_c_variadic = only foreign or `unsafe extern "C"` functions may be C-variadic +ast_passes_fn_param_doc_comment = + documentation comments cannot be applied to function parameters + .label = doc comments are not allowed here -ast_passes_item_underscore = `{$kind}` items in this context need a name - .label = `_` is not a valid name for this `{$kind}` item +ast_passes_fn_param_forbidden_attr = + allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters -ast_passes_nomangle_ascii = `#[no_mangle]` requires ASCII identifier +ast_passes_fn_param_forbidden_self = + `self` parameter is only allowed in associated functions + .label = not semantically valid as function parameter + .note = associated functions are those in `impl` or `trait` definitions -ast_passes_module_nonascii = trying to load file for module `{$name}` with non-ascii identifier name - .help = consider using the `#[path]` attribute to specify filesystem path +ast_passes_fn_param_too_many = + function can not have more than {$max_num_args} arguments -ast_passes_auto_generic = auto traits cannot have generic parameters - .label = auto trait cannot have generic parameters - .suggestion = remove the parameters +ast_passes_fn_without_body = + free function without a body + .suggestion = provide a definition for the function -ast_passes_auto_super_lifetime = auto traits cannot have super traits or lifetime bounds - .label = {ast_passes_auto_super_lifetime} - .suggestion = remove the super traits or lifetime bounds +ast_passes_forbidden_default = + `default` is only allowed on items in trait impls + .label = `default` because of this -ast_passes_auto_items = auto traits cannot have associated items - .label = {ast_passes_auto_items} - .suggestion = remove these associated items +ast_passes_forbidden_let = + `let` expressions are not supported here + .note = only supported directly in conditions of `if` and `while` expressions + .not_supported_or = `||` operators are not supported in let chain expressions + .not_supported_parentheses = `let`s wrapped in parentheses are not supported in a context with let chains + +ast_passes_forbidden_let_stable = + expected expression, found statement (`let`) + .note = variable declaration using `let` is a statement + +ast_passes_forbidden_lifetime_bound = + lifetime bounds cannot be used in this context + +ast_passes_forbidden_non_lifetime_param = + only lifetime parameters can be used in this context ast_passes_generic_before_constraints = generic arguments must come before the first constraint .constraints = {$constraint_len -> @@ -156,88 +147,97 @@ ast_passes_generic_before_constraints = generic arguments must come before the f *[other] arguments } -ast_passes_pattern_in_fn_pointer = patterns aren't allowed in function pointer types - -ast_passes_trait_object_single_bound = only a single explicit lifetime bound is permitted +ast_passes_generic_default_trailing = generic parameters with a default must be trailing ast_passes_impl_trait_path = `impl Trait` is not allowed in path parameters +ast_passes_incompatible_features = `{$f1}` and `{$f2}` are incompatible, using them at the same time is not allowed + .help = remove one of these features + +ast_passes_inherent_cannot_be = inherent impls cannot be {$annotation} + .because = {$annotation} because of this + .type = inherent impl for this type + .only_trait = only trait implementations may be annotated with {$annotation} + +ast_passes_invalid_label = + invalid label name `{$name}` + +ast_passes_item_underscore = `{$kind}` items in this context need a name + .label = `_` is not a valid name for this `{$kind}` item + +ast_passes_keyword_lifetime = + lifetimes cannot use keyword names + +ast_passes_module_nonascii = trying to load file for module `{$name}` with non-ascii identifier name + .help = consider using the `#[path]` attribute to specify filesystem path + +ast_passes_negative_bound_not_supported = + negative bounds are not supported + ast_passes_nested_impl_trait = nested `impl Trait` is not allowed .outer = outer `impl Trait` .inner = nested `impl Trait` here -ast_passes_at_least_one_trait = at least one trait must be specified - -ast_passes_extern_without_abi = extern declarations without an explicit ABI are deprecated +ast_passes_nested_lifetimes = nested quantification of lifetimes -ast_passes_out_of_order_params = {$param_ord} parameters must be declared prior to {$max_param} parameters - .suggestion = reorder the parameters: lifetimes, then consts and types +ast_passes_nomangle_ascii = `#[no_mangle]` requires ASCII identifier ast_passes_obsolete_auto = `impl Trait for .. {"{}"}` is an obsolete syntax .help = use `auto trait Trait {"{}"}` instead -ast_passes_unsafe_negative_impl = negative impls cannot be unsafe - .negative = negative because of this - .unsafe = unsafe because of this +ast_passes_optional_const_exclusive = `~const` and `{$modifier}` are mutually exclusive -ast_passes_inherent_cannot_be = inherent impls cannot be {$annotation} - .because = {$annotation} because of this - .type = inherent impl for this type - .only_trait = only trait implementations may be annotated with {$annotation} +ast_passes_optional_trait_object = `?Trait` is not permitted in trait object types -ast_passes_unsafe_item = {$kind} cannot be declared unsafe +ast_passes_optional_trait_supertrait = `?Trait` is not permitted in supertraits + .note = traits are `?{$path_str}` by default -ast_passes_fieldless_union = unions cannot have zero fields +ast_passes_out_of_order_params = {$param_ord} parameters must be declared prior to {$max_param} parameters + .suggestion = reorder the parameters: lifetimes, then consts and types -ast_passes_where_after_type_alias = where clauses are not allowed after the type for type aliases - .note = see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information +ast_passes_pattern_in_bodiless = patterns aren't allowed in functions without bodies + .label = pattern not allowed in function without body -ast_passes_generic_default_trailing = generic parameters with a default must be trailing +ast_passes_pattern_in_fn_pointer = patterns aren't allowed in function pointer types -ast_passes_nested_lifetimes = nested quantification of lifetimes +ast_passes_pattern_in_foreign = patterns aren't allowed in foreign function declarations + .label = pattern not allowed in foreign function -ast_passes_optional_trait_supertrait = `?Trait` is not permitted in supertraits - .note = traits are `?{$path_str}` by default +ast_passes_show_span = {$msg} -ast_passes_optional_trait_object = `?Trait` is not permitted in trait object types +ast_passes_stability_outside_std = stability attributes may not be used outside of the standard library + +ast_passes_static_without_body = + free static item without body + .suggestion = provide a definition for the static ast_passes_tilde_const_disallowed = `~const` is not allowed here .trait = trait objects cannot have `~const` trait bounds .closure = closures cannot have `~const` trait bounds .function = this function is not `const`, so it cannot have `~const` trait bounds -ast_passes_optional_const_exclusive = `~const` and `{$modifier}` are mutually exclusive - -ast_passes_const_and_async = functions cannot be both `const` and `async` - .const = `const` because of this - .async = `async` because of this - .label = {""} - -ast_passes_pattern_in_foreign = patterns aren't allowed in foreign function declarations - .label = pattern not allowed in foreign function - -ast_passes_pattern_in_bodiless = patterns aren't allowed in functions without bodies - .label = pattern not allowed in function without body - -ast_passes_equality_in_where = equality constraints are not yet supported in `where` clauses - .label = not supported - .suggestion = if `{$ident}` is an associated type you're trying to set, use the associated type binding syntax - .suggestion_path = if `{$trait_segment}::{$potential_assoc}` is an associated type you're trying to set, use the associated type binding syntax - .note = see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information +ast_passes_trait_fn_const = + functions in traits cannot be declared const + .label = functions in traits cannot be const -ast_passes_stability_outside_std = stability attributes may not be used outside of the standard library +ast_passes_trait_object_single_bound = only a single explicit lifetime bound is permitted -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 +ast_passes_ty_alias_without_body = + free type alias without body + .suggestion = provide a definition for the type -ast_passes_incompatible_features = `{$f1}` and `{$f2}` are incompatible, using them at the same time is not allowed - .help = remove one of these features +ast_passes_unsafe_item = {$kind} cannot be declared unsafe -ast_passes_show_span = {$msg} +ast_passes_unsafe_negative_impl = negative impls cannot be unsafe + .negative = negative because of this + .unsafe = unsafe because of this -ast_passes_negative_bound_not_supported = - negative bounds are not supported +ast_passes_visibility_not_permitted = + visibility qualifiers are not permitted here + .enum_variant = enum variants and their fields always share the visibility of the enum they are in + .trait_impl = trait items always share the visibility of their trait + .individual_impl_items = place qualifiers on individual impl items instead + .individual_foreign_items = place qualifiers on individual foreign items instead -ast_passes_constraint_on_negative_bound = - associated type constraints not allowed on negative bounds +ast_passes_where_after_type_alias = where clauses are not allowed after the type for type aliases + .note = see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information diff --git a/compiler/rustc_attr/messages.ftl b/compiler/rustc_attr/messages.ftl index a7f8c993d42..e6cbbaf3704 100644 --- a/compiler/rustc_attr/messages.ftl +++ b/compiler/rustc_attr/messages.ftl @@ -1,27 +1,38 @@ +attr_cfg_predicate_identifier = + `cfg` predicate key must be an identifier + +attr_deprecated_item_suggestion = + suggestions on deprecated items are unstable + .help = add `#![feature(deprecated_suggestion)]` to the crate root + .note = see #94785 for more details + attr_expected_one_cfg_pattern = expected 1 cfg-pattern -attr_invalid_predicate = - invalid predicate `{$predicate}` +attr_expected_single_version_literal = + expected single version literal -attr_multiple_item = - multiple '{$item}' items +attr_expected_version_literal = + expected a version literal + +attr_expects_feature_list = + `{$name}` expects a list of feature names + +attr_expects_features = + `{$name}` expects feature names attr_incorrect_meta_item = incorrect meta item -attr_unknown_meta_item = - unknown meta item '{$item}' - .label = expected one of {$expected} - -attr_missing_since = - missing 'since' +attr_incorrect_repr_format_align_one_arg = + incorrect `repr(align)` attribute format: `align` takes exactly one argument in parentheses -attr_missing_note = - missing 'note' +attr_incorrect_repr_format_generic = + incorrect `repr({$repr_arg})` attribute format + .suggestion = use parentheses instead -attr_multiple_stability_levels = - multiple stability levels +attr_incorrect_repr_format_packed_one_or_zero_arg = + incorrect `repr(packed)` attribute format: `packed` takes exactly one parenthesized argument, or no parentheses at all attr_invalid_issue_string = `issue` must be a non-zero numeric string or "none" @@ -31,17 +42,15 @@ attr_invalid_issue_string = .pos_overflow = number too large to fit in target type .neg_overflow = number too small to fit in target type -attr_missing_feature = - missing 'feature' - -attr_non_ident_feature = - 'feature' is not an identifier +attr_invalid_predicate = + invalid predicate `{$predicate}` -attr_missing_issue = - missing 'issue' +attr_invalid_repr_align_need_arg = + invalid `repr(align)` attribute: `align` needs an argument + .suggestion = supply an argument here -attr_incorrect_repr_format_packed_one_or_zero_arg = - incorrect `repr(packed)` attribute format: `packed` takes exactly one parenthesized argument, or no parentheses at all +attr_invalid_repr_generic = + invalid `repr({$repr_arg})` attribute: {$error_part} attr_invalid_repr_hint_no_paren = invalid representation hint: `{$name}` does not take a parenthesized argument list @@ -49,59 +58,50 @@ attr_invalid_repr_hint_no_paren = attr_invalid_repr_hint_no_value = invalid representation hint: `{$name}` does not take a value -attr_unsupported_literal_generic = - unsupported literal -attr_unsupported_literal_cfg_string = - literal in `cfg` predicate value must be a string -attr_unsupported_literal_deprecated_string = - literal in `deprecated` value must be a string -attr_unsupported_literal_deprecated_kv_pair = - item in `deprecated` must be a key/value pair -attr_unsupported_literal_suggestion = - consider removing the prefix +attr_missing_feature = + missing 'feature' -attr_invalid_repr_align_need_arg = - invalid `repr(align)` attribute: `align` needs an argument - .suggestion = supply an argument here +attr_missing_issue = + missing 'issue' -attr_invalid_repr_generic = - invalid `repr({$repr_arg})` attribute: {$error_part} +attr_missing_note = + missing 'note' -attr_incorrect_repr_format_align_one_arg = - incorrect `repr(align)` attribute format: `align` takes exactly one argument in parentheses +attr_missing_since = + missing 'since' -attr_incorrect_repr_format_generic = - incorrect `repr({$repr_arg})` attribute format - .suggestion = use parentheses instead +attr_multiple_item = + multiple '{$item}' items -attr_rustc_promotable_pairing = - `rustc_promotable` attribute must be paired with either a `rustc_const_unstable` or a `rustc_const_stable` attribute +attr_multiple_stability_levels = + multiple stability levels + +attr_non_ident_feature = + 'feature' is not an identifier attr_rustc_allowed_unstable_pairing = `rustc_allowed_through_unstable_modules` attribute must be paired with a `stable` attribute -attr_cfg_predicate_identifier = - `cfg` predicate key must be an identifier - -attr_deprecated_item_suggestion = - suggestions on deprecated items are unstable - .help = add `#![feature(deprecated_suggestion)]` to the crate root - .note = see #94785 for more details - -attr_expected_single_version_literal = - expected single version literal - -attr_expected_version_literal = - expected a version literal - -attr_expects_feature_list = - `{$name}` expects a list of feature names - -attr_expects_features = - `{$name}` expects feature names +attr_rustc_promotable_pairing = + `rustc_promotable` attribute must be paired with either a `rustc_const_unstable` or a `rustc_const_stable` attribute attr_soft_no_args = `soft` should not have any arguments +attr_unknown_meta_item = + unknown meta item '{$item}' + .label = expected one of {$expected} + attr_unknown_version_literal = unknown version literal format, assuming it refers to a future version + +attr_unsupported_literal_cfg_string = + literal in `cfg` predicate value must be a string +attr_unsupported_literal_deprecated_kv_pair = + item in `deprecated` must be a key/value pair +attr_unsupported_literal_deprecated_string = + literal in `deprecated` value must be a string +attr_unsupported_literal_generic = + unsupported literal +attr_unsupported_literal_suggestion = + consider removing the prefix diff --git a/compiler/rustc_borrowck/messages.ftl b/compiler/rustc_borrowck/messages.ftl index 4a616dc2464..67fdb671742 100644 --- a/compiler/rustc_borrowck/messages.ftl +++ b/compiler/rustc_borrowck/messages.ftl @@ -1,188 +1,108 @@ -borrowck_move_unsized = - cannot move a value of type `{$ty}` - .label = the size of `{$ty}` cannot be statically determined - -borrowck_higher_ranked_lifetime_error = - higher-ranked lifetime error - -borrowck_could_not_prove = - could not prove `{$predicate}` - -borrowck_could_not_normalize = - could not normalize `{$value}` - -borrowck_higher_ranked_subtype_error = - higher-ranked subtype error - -borrowck_generic_does_not_live_long_enough = - `{$kind}` does not live long enough - -borrowck_move_borrowed = - cannot move out of `{$desc}` because it is borrowed - -borrowck_var_does_not_need_mut = - variable does not need to be mutable - .suggestion = remove this `mut` - -borrowck_var_cannot_escape_closure = - captured variable cannot escape `FnMut` closure body - .note = `FnMut` closures only have access to their captured variables while they are executing... - .cannot_escape = ...therefore, they cannot allow references to captured variables to escape - -borrowck_var_here_defined = variable defined here - -borrowck_var_here_captured = variable captured here - -borrowck_closure_inferred_mut = inferred to be a `FnMut` closure - -borrowck_returned_closure_escaped = - returns a closure that contains a reference to a captured variable, which then escapes the closure body - -borrowck_returned_async_block_escaped = - returns an `async` block that contains a reference to a captured variable, which then escapes the closure body - -borrowck_returned_ref_escaped = - returns a reference to a captured variable which escapes the closure body - -borrowck_lifetime_constraints_error = - lifetime may not live long enough - -borrowck_returned_lifetime_wrong = - {$mir_def_name} was supposed to return data with lifetime `{$outlived_fr_name}` but it is returning data with lifetime `{$fr_name}` - -borrowck_returned_lifetime_short = - {$category_desc}requires that `{$free_region_name}` must outlive `{$outlived_fr_name}` - -borrowck_used_impl_require_static = - the used `impl` has a `'static` requirement - -borrowck_borrow_due_to_use_generator = - borrow occurs due to use in generator - -borrowck_use_due_to_use_generator = - use occurs due to use in generator +borrowck_assign_due_to_use_closure = + assignment occurs due to use in closure borrowck_assign_due_to_use_generator = assign occurs due to use in generator +borrowck_assign_part_due_to_use_closure = + assignment to part occurs due to use in closure + borrowck_assign_part_due_to_use_generator = assign to part occurs due to use in generator borrowck_borrow_due_to_use_closure = borrow occurs due to use in closure -borrowck_use_due_to_use_closure = - use occurs due to use in closure +borrowck_borrow_due_to_use_generator = + borrow occurs due to use in generator -borrowck_assign_due_to_use_closure = - assignment occurs due to use in closure +borrowck_calling_operator_moves_lhs = + calling this operator moves the left-hand side -borrowck_assign_part_due_to_use_closure = - assignment to part occurs due to use in closure +borrowck_cannot_move_when_borrowed = + cannot move out of {$place -> + [value] value + *[other] {$place} + } because it is borrowed + .label = borrow of {$borrow_place -> + [value] value + *[other] {$borrow_place} + } occurs here + .move_label = move out of {$value_place -> + [value] value + *[other] {$value_place} + } occurs here borrowck_capture_immute = capture is immutable because of use here -borrowck_capture_mut = - capture is mutable because of use here - borrowck_capture_move = capture is moved because of use here -borrowck_var_borrow_by_use_place_in_generator = - {$is_single_var -> - *[true] borrow occurs - [false] borrows occur - } due to use of {$place} in generator - -borrowck_var_borrow_by_use_place_in_closure = - {$is_single_var -> - *[true] borrow occurs - [false] borrows occur - } due to use of {$place} in closure +borrowck_capture_mut = + capture is mutable because of use here -borrowck_var_borrow_by_use_in_generator = - borrow occurs due to use in generator +borrowck_closure_inferred_mut = inferred to be a `FnMut` closure -borrowck_var_borrow_by_use_in_closure = - borrow occurs due to use in closure +borrowck_closure_invoked_twice = + closure cannot be invoked more than once because it moves the variable `{$place_name}` out of its environment -borrowck_var_move_by_use_place_in_generator = - move occurs due to use of {$place} in generator +borrowck_closure_moved_twice = + closure cannot be moved more than once as it is not `Copy` due to moving the variable `{$place_name}` out of its environment -borrowck_var_move_by_use_place_in_closure = - move occurs due to use of {$place} in closure +borrowck_consider_borrow_type_contents = + help: consider calling `.as_ref()` or `.as_mut()` to borrow the type's contents -borrowck_var_move_by_use_in_generator = - move occurs due to use in generator +borrowck_could_not_normalize = + could not normalize `{$value}` -borrowck_var_move_by_use_in_closure = - move occurs due to use in closure +borrowck_could_not_prove = + could not prove `{$predicate}` -borrowck_partial_var_move_by_use_in_generator = - variable {$is_partial -> - [true] partially moved - *[false] moved - } due to use in generator +borrowck_func_take_self_moved_place = + `{$func}` takes ownership of the receiver `self`, which moves {$place_name} -borrowck_partial_var_move_by_use_in_closure = - variable {$is_partial -> - [true] partially moved - *[false] moved - } due to use in closure +borrowck_generic_does_not_live_long_enough = + `{$kind}` does not live long enough -borrowck_var_first_borrow_by_use_place_in_generator = - first borrow occurs due to use of {$place} in generator +borrowck_higher_ranked_lifetime_error = + higher-ranked lifetime error -borrowck_var_first_borrow_by_use_place_in_closure = - first borrow occurs due to use of {$place} in closure +borrowck_higher_ranked_subtype_error = + higher-ranked subtype error -borrowck_var_second_borrow_by_use_place_in_generator = - second borrow occurs due to use of {$place} in generator +borrowck_lifetime_constraints_error = + lifetime may not live long enough -borrowck_var_second_borrow_by_use_place_in_closure = - second borrow occurs due to use of {$place} in closure +borrowck_move_borrowed = + cannot move out of `{$desc}` because it is borrowed -borrowck_var_mutable_borrow_by_use_place_in_closure = - mutable borrow occurs due to use of {$place} in closure +borrowck_move_out_place_here = + {$place} is moved here -borrowck_cannot_move_when_borrowed = - cannot move out of {$place -> - [value] value - *[other] {$place} - } because it is borrowed - .label = borrow of {$borrow_place -> - [value] value - *[other] {$borrow_place} - } occurs here - .move_label = move out of {$value_place -> - [value] value - *[other] {$value_place} - } occurs here +borrowck_move_unsized = + cannot move a value of type `{$ty}` + .label = the size of `{$ty}` cannot be statically determined -borrowck_opaque_type_non_generic_param = - expected generic {$kind} parameter, found `{$ty}` - .label = {STREQ($ty, "'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 - } +borrowck_moved_a_fn_once_in_call = + this value implements `FnOnce`, which causes it to be moved when called -borrowck_moved_due_to_call = +borrowck_moved_due_to_await = {$place_name} {$is_partial -> [true] partially moved *[false] moved } due to this {$is_loop_message -> - [true] call, in previous iteration of loop - *[false] call + [true] await, in previous iteration of loop + *[false] await } -borrowck_moved_due_to_usage_in_operator = +borrowck_moved_due_to_call = {$place_name} {$is_partial -> [true] partially moved *[false] moved - } due to usage in {$is_loop_message -> - [true] operator, in previous iteration of loop - *[false] operator + } due to this {$is_loop_message -> + [true] call, in previous iteration of loop + *[false] call } borrowck_moved_due_to_implicit_into_iter_call = @@ -203,13 +123,74 @@ borrowck_moved_due_to_method_call = *[false] call } -borrowck_moved_due_to_await = +borrowck_moved_due_to_usage_in_operator = {$place_name} {$is_partial -> [true] partially moved *[false] moved - } due to this {$is_loop_message -> - [true] await, in previous iteration of loop - *[false] await + } due to usage in {$is_loop_message -> + [true] operator, in previous iteration of loop + *[false] operator + } + +borrowck_opaque_type_non_generic_param = + expected generic {$kind} parameter, found `{$ty}` + .label = {STREQ($ty, "'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 + } + +borrowck_partial_var_move_by_use_in_closure = + variable {$is_partial -> + [true] partially moved + *[false] moved + } due to use in closure + +borrowck_partial_var_move_by_use_in_generator = + variable {$is_partial -> + [true] partially moved + *[false] moved + } due to use in generator + +borrowck_returned_async_block_escaped = + returns an `async` block that contains a reference to a captured variable, which then escapes the closure body + +borrowck_returned_closure_escaped = + returns a closure that contains a reference to a captured variable, which then escapes the closure body + +borrowck_returned_lifetime_short = + {$category_desc}requires that `{$free_region_name}` must outlive `{$outlived_fr_name}` + +borrowck_returned_lifetime_wrong = + {$mir_def_name} was supposed to return data with lifetime `{$outlived_fr_name}` but it is returning data with lifetime `{$fr_name}` + +borrowck_returned_ref_escaped = + returns a reference to a captured variable which escapes the closure body + +borrowck_suggest_create_freash_reborrow = + consider reborrowing the `Pin` instead of moving it + +borrowck_suggest_iterate_over_slice = + consider iterating over a slice of the `{$ty}`'s content to avoid moving into the `for` loop + +borrowck_ty_no_impl_copy = + {$is_partial_move -> + [true] partial move + *[false] move + } occurs because {$place} has type `{$ty}`, which does not implement the `Copy` trait + +borrowck_use_due_to_use_closure = + use occurs due to use in closure + +borrowck_use_due_to_use_generator = + use occurs due to use in generator + +borrowck_used_impl_require_static = + the used `impl` has a `'static` requirement + +borrowck_value_capture_here = + value captured {$is_within -> + [true] here by generator + *[false] here } borrowck_value_moved_here = @@ -224,41 +205,60 @@ borrowck_value_moved_here = *[false] {""} } -borrowck_consider_borrow_type_contents = - help: consider calling `.as_ref()` or `.as_mut()` to borrow the type's contents +borrowck_var_borrow_by_use_in_closure = + borrow occurs due to use in closure -borrowck_moved_a_fn_once_in_call = - this value implements `FnOnce`, which causes it to be moved when called +borrowck_var_borrow_by_use_in_generator = + borrow occurs due to use in generator -borrowck_calling_operator_moves_lhs = - calling this operator moves the left-hand side +borrowck_var_borrow_by_use_place_in_closure = + {$is_single_var -> + *[true] borrow occurs + [false] borrows occur + } due to use of {$place} in closure -borrowck_func_take_self_moved_place = - `{$func}` takes ownership of the receiver `self`, which moves {$place_name} +borrowck_var_borrow_by_use_place_in_generator = + {$is_single_var -> + *[true] borrow occurs + [false] borrows occur + } due to use of {$place} in generator -borrowck_suggest_iterate_over_slice = - consider iterating over a slice of the `{$ty}`'s content to avoid moving into the `for` loop +borrowck_var_cannot_escape_closure = + captured variable cannot escape `FnMut` closure body + .note = `FnMut` closures only have access to their captured variables while they are executing... + .cannot_escape = ...therefore, they cannot allow references to captured variables to escape -borrowck_suggest_create_freash_reborrow = - consider reborrowing the `Pin` instead of moving it +borrowck_var_does_not_need_mut = + variable does not need to be mutable + .suggestion = remove this `mut` -borrowck_value_capture_here = - value captured {$is_within -> - [true] here by generator - *[false] here - } +borrowck_var_first_borrow_by_use_place_in_closure = + first borrow occurs due to use of {$place} in closure -borrowck_move_out_place_here = - {$place} is moved here +borrowck_var_first_borrow_by_use_place_in_generator = + first borrow occurs due to use of {$place} in generator -borrowck_closure_invoked_twice = - closure cannot be invoked more than once because it moves the variable `{$place_name}` out of its environment +borrowck_var_here_captured = variable captured here -borrowck_closure_moved_twice = - closure cannot be moved more than once as it is not `Copy` due to moving the variable `{$place_name}` out of its environment +borrowck_var_here_defined = variable defined here -borrowck_ty_no_impl_copy = - {$is_partial_move -> - [true] partial move - *[false] move - } occurs because {$place} has type `{$ty}`, which does not implement the `Copy` trait +borrowck_var_move_by_use_in_closure = + move occurs due to use in closure + +borrowck_var_move_by_use_in_generator = + move occurs due to use in generator + +borrowck_var_move_by_use_place_in_closure = + move occurs due to use of {$place} in closure + +borrowck_var_move_by_use_place_in_generator = + move occurs due to use of {$place} in generator + +borrowck_var_mutable_borrow_by_use_place_in_closure = + mutable borrow occurs due to use of {$place} in closure + +borrowck_var_second_borrow_by_use_place_in_closure = + second borrow occurs due to use of {$place} in closure + +borrowck_var_second_borrow_by_use_place_in_generator = + second borrow occurs due to use of {$place} in generator diff --git a/compiler/rustc_borrowck/src/def_use.rs b/compiler/rustc_borrowck/src/def_use.rs index b775739fed2..b719a610e07 100644 --- a/compiler/rustc_borrowck/src/def_use.rs +++ b/compiler/rustc_borrowck/src/def_use.rs @@ -50,7 +50,6 @@ pub fn categorize(context: PlaceContext) -> Option<DefUse> { PlaceContext::MutatingUse(MutatingUseContext::Borrow) | PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow) | PlaceContext::NonMutatingUse(NonMutatingUseContext::ShallowBorrow) | - PlaceContext::NonMutatingUse(NonMutatingUseContext::UniqueBorrow) | // `PlaceMention` and `AscribeUserType` both evaluate the place, which must not // contain dangling references. diff --git a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs index f41795d60a0..cfcf31fce32 100644 --- a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs @@ -180,24 +180,25 @@ trait TypeOpInfo<'tcx> { return; }; - let placeholder_region = tcx.mk_re_placeholder(ty::Placeholder { - universe: adjusted_universe.into(), - bound: placeholder.bound, - }); - - let error_region = - if let RegionElement::PlaceholderRegion(error_placeholder) = error_element { - let adjusted_universe = - error_placeholder.universe.as_u32().checked_sub(base_universe.as_u32()); - adjusted_universe.map(|adjusted| { - tcx.mk_re_placeholder(ty::Placeholder { - universe: adjusted.into(), - bound: error_placeholder.bound, - }) - }) - } else { - None - }; + let placeholder_region = ty::Region::new_placeholder( + tcx, + ty::Placeholder { universe: adjusted_universe.into(), bound: placeholder.bound }, + ); + + let error_region = if let RegionElement::PlaceholderRegion(error_placeholder) = + error_element + { + let adjusted_universe = + error_placeholder.universe.as_u32().checked_sub(base_universe.as_u32()); + adjusted_universe.map(|adjusted| { + ty::Region::new_placeholder( + tcx, + ty::Placeholder { universe: adjusted.into(), bound: error_placeholder.bound }, + ) + }) + } else { + None + }; debug!(?placeholder_region); @@ -390,7 +391,7 @@ fn try_extract_error_from_fulfill_cx<'tcx>( error_region, ®ion_constraints, |vid| ocx.infcx.region_var_origin(vid), - |vid| ocx.infcx.universe_of_region(ocx.infcx.tcx.mk_re_var(vid)), + |vid| ocx.infcx.universe_of_region(ty::Region::new_var(ocx.infcx.tcx, vid)), ) } @@ -411,7 +412,7 @@ fn try_extract_error_from_region_constraints<'tcx>( } // FIXME: Should this check the universe of the var? Constraint::VarSubReg(vid, sup) if sup == placeholder_region => { - Some((infcx.tcx.mk_re_var(vid), cause.clone())) + Some((ty::Region::new_var(infcx.tcx, vid), cause.clone())) } _ => None, } diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 04b8174079a..15d73ed732f 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -1635,34 +1635,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { }) } - /// Reports StorageDeadOrDrop of `place` conflicts with `borrow`. - /// - /// Depending on the origin of the StorageDeadOrDrop, this may be - /// reported as either a drop or an illegal mutation of a borrowed value. - /// The latter is preferred when the this is a drop triggered by a - /// reassignment, as it's more user friendly to report a problem with the - /// explicit assignment than the implicit drop. - #[instrument(level = "debug", skip(self))] - pub(crate) fn report_storage_dead_or_drop_of_borrowed( - &mut self, - location: Location, - place_span: (Place<'tcx>, Span), - borrow: &BorrowData<'tcx>, - ) { - // It's sufficient to check the last desugaring as Replace is the last - // one to be applied. - if let Some(DesugaringKind::Replace) = place_span.1.desugaring_kind() { - self.report_illegal_mutation_of_borrowed(location, place_span, borrow) - } else { - self.report_borrowed_value_does_not_live_long_enough( - location, - borrow, - place_span, - Some(WriteKind::StorageDeadOrDrop), - ) - } - } - /// This means that some data referenced by `borrow` needs to live /// past the point where the StorageDeadOrDrop of `place` occurs. /// This is usually interpreted as meaning that `place` has too diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index 4bde372c847..d0e17bf5a08 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -641,13 +641,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let Some(hir::Node::Item(item)) = node else { return; }; let hir::ItemKind::Fn(.., body_id) = item.kind else { return; }; let body = self.infcx.tcx.hir().body(body_id); - let mut assign_span = span; - // Drop desugaring is done at MIR build so it's not in the HIR - if let Some(DesugaringKind::Replace) = span.desugaring_kind() { - assign_span.remove_mark(); - } - let mut v = V { assign_span, err, ty, suggested: false }; + let mut v = V { assign_span: span, err, ty, suggested: false }; v.visit_body(body); if !v.suggested { err.help(format!( diff --git a/compiler/rustc_borrowck/src/invalidation.rs b/compiler/rustc_borrowck/src/invalidation.rs index 036391d074d..b2ff25ecb96 100644 --- a/compiler/rustc_borrowck/src/invalidation.rs +++ b/compiler/rustc_borrowck/src/invalidation.rs @@ -112,11 +112,13 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> { TerminatorKind::SwitchInt { discr, targets: _ } => { self.consume_operand(location, discr); } - TerminatorKind::Drop { place: drop_place, target: _, unwind: _ } => { + TerminatorKind::Drop { place: drop_place, target: _, unwind: _, replace } => { + let write_kind = + if *replace { WriteKind::Replace } else { WriteKind::StorageDeadOrDrop }; self.access_place( location, *drop_place, - (AccessDepth::Drop, Write(WriteKind::StorageDeadOrDrop)), + (AccessDepth::Drop, Write(write_kind)), LocalMutationIsAllowed::Yes, ); } diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 9277a262f97..a53ea100c22 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -685,17 +685,19 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx TerminatorKind::SwitchInt { discr, targets: _ } => { self.consume_operand(loc, (discr, span), flow_state); } - TerminatorKind::Drop { place, target: _, unwind: _ } => { + TerminatorKind::Drop { place, target: _, unwind: _, replace } => { debug!( "visit_terminator_drop \ loc: {:?} term: {:?} place: {:?} span: {:?}", loc, term, place, span ); + let write_kind = + if *replace { WriteKind::Replace } else { WriteKind::StorageDeadOrDrop }; self.access_place( loc, (*place, span), - (AccessDepth::Drop, Write(WriteKind::StorageDeadOrDrop)), + (AccessDepth::Drop, Write(write_kind)), LocalMutationIsAllowed::Yes, flow_state, ); @@ -885,6 +887,7 @@ enum ReadKind { #[derive(Copy, Clone, PartialEq, Eq, Debug)] enum WriteKind { StorageDeadOrDrop, + Replace, MutableBorrow(BorrowKind), Mutate, Move, @@ -1132,13 +1135,21 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { this.buffer_error(err); } WriteKind::StorageDeadOrDrop => this - .report_storage_dead_or_drop_of_borrowed(location, place_span, borrow), + .report_borrowed_value_does_not_live_long_enough( + location, + borrow, + place_span, + Some(WriteKind::StorageDeadOrDrop), + ), WriteKind::Mutate => { this.report_illegal_mutation_of_borrowed(location, place_span, borrow) } WriteKind::Move => { this.report_move_out_while_borrowed(location, place_span, borrow) } + WriteKind::Replace => { + this.report_illegal_mutation_of_borrowed(location, place_span, borrow) + } } Control::Break } @@ -1982,12 +1993,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { Reservation( WriteKind::Move + | WriteKind::Replace | WriteKind::StorageDeadOrDrop | WriteKind::MutableBorrow(BorrowKind::Shared) | WriteKind::MutableBorrow(BorrowKind::Shallow), ) | Write( WriteKind::Move + | WriteKind::Replace | WriteKind::StorageDeadOrDrop | WriteKind::MutableBorrow(BorrowKind::Shared) | WriteKind::MutableBorrow(BorrowKind::Shallow), diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index 889acb3acbe..b5014a3f479 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -441,7 +441,7 @@ fn for_each_region_constraint<'tcx>( let subject = match req.subject { ClosureOutlivesSubject::Region(subject) => format!("{:?}", subject), ClosureOutlivesSubject::Ty(ty) => { - format!("{:?}", ty.instantiate(tcx, |vid| tcx.mk_re_var(vid))) + format!("{:?}", ty.instantiate(tcx, |vid| ty::Region::new_var(tcx, vid))) } }; with_msg(format!("where {}: {:?}", subject, req.outlived_free_region,))?; diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 50b246b1478..2a0cb49672b 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -1158,7 +1158,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { .universal_regions_outlived_by(r_scc) .filter(|&u_r| !self.universal_regions.is_local_free_region(u_r)) .find(|&u_r| self.eval_equal(u_r, r_vid)) - .map(|u_r| tcx.mk_re_var(u_r)) + .map(|u_r| ty::Region::new_var(tcx, u_r)) // In the case of a failure, use `ReErased`. We will eventually // return `None` in this case. .unwrap_or(tcx.lifetimes.re_erased) @@ -1355,7 +1355,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { let vid = self.to_region_vid(r); let scc = self.constraint_sccs.scc(vid); let repr = self.scc_representatives[scc]; - tcx.mk_re_var(repr) + ty::Region::new_var(tcx, repr) }) } @@ -1779,7 +1779,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { } // If not, report an error. - let member_region = infcx.tcx.mk_re_var(member_region_vid); + let member_region = ty::Region::new_var(infcx.tcx, member_region_vid); errors_buffer.push(RegionErrorKind::UnexpectedHiddenRegion { span: m_c.definition_span, hidden_ty: m_c.hidden_ty, diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index 7fc89e89a35..33f07c1d8fc 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -92,7 +92,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { } None => { subst_regions.push(vid); - infcx.tcx.mk_re_error_with_message( + ty::Region::new_error_with_message( + infcx.tcx, concrete_type.span, "opaque type with non-universal region substs", ) diff --git a/compiler/rustc_borrowck/src/type_check/canonical.rs b/compiler/rustc_borrowck/src/type_check/canonical.rs index 95dcc8d4b19..f527eee7bda 100644 --- a/compiler/rustc_borrowck/src/type_check/canonical.rs +++ b/compiler/rustc_borrowck/src/type_check/canonical.rs @@ -1,12 +1,12 @@ use std::fmt; +use rustc_errors::ErrorGuaranteed; use rustc_infer::infer::canonical::Canonical; use rustc_middle::mir::ConstraintCategory; use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable}; use rustc_span::def_id::DefId; use rustc_span::Span; use rustc_trait_selection::traits::query::type_op::{self, TypeOpOutput}; -use rustc_trait_selection::traits::query::{Fallible, NoSolution}; use rustc_trait_selection::traits::ObligationCause; use crate::diagnostics::{ToUniverseInfo, UniverseInfo}; @@ -30,14 +30,15 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { locations: Locations, category: ConstraintCategory<'tcx>, op: Op, - ) -> Fallible<R> + ) -> Result<R, ErrorGuaranteed> where Op: type_op::TypeOp<'tcx, Output = R>, Op::ErrorInfo: ToUniverseInfo<'tcx>, { let old_universe = self.infcx.universe(); - let TypeOpOutput { output, constraints, error_info } = op.fully_perform(self.infcx)?; + let TypeOpOutput { output, constraints, error_info } = + op.fully_perform(self.infcx, locations.span(self.body))?; debug!(?output, ?constraints); @@ -135,14 +136,11 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ) { let param_env = self.param_env; let predicate = predicate.to_predicate(self.tcx()); - self.fully_perform_op( + let _: Result<_, ErrorGuaranteed> = self.fully_perform_op( locations, category, param_env.and(type_op::prove_predicate::ProvePredicate::new(predicate)), - ) - .unwrap_or_else(|NoSolution| { - span_mirbug!(self, NoSolution, "could not prove {:?}", predicate); - }) + ); } pub(super) fn normalize<T>(&mut self, value: T, location: impl NormalizeLocation) -> T @@ -163,15 +161,12 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { T: type_op::normalize::Normalizable<'tcx> + fmt::Display + Copy + 'tcx, { let param_env = self.param_env; - self.fully_perform_op( + let result: Result<_, ErrorGuaranteed> = self.fully_perform_op( location.to_locations(), category, param_env.and(type_op::normalize::Normalize::new(value)), - ) - .unwrap_or_else(|NoSolution| { - span_mirbug!(self, NoSolution, "failed to normalize `{:?}`", value); - value - }) + ); + result.unwrap_or(value) } #[instrument(skip(self), level = "debug")] @@ -181,18 +176,11 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { user_ty: ty::UserType<'tcx>, span: Span, ) { - self.fully_perform_op( + let _: Result<_, ErrorGuaranteed> = self.fully_perform_op( Locations::All(span), ConstraintCategory::Boring, self.param_env.and(type_op::ascribe_user_type::AscribeUserType::new(mir_ty, user_ty)), - ) - .unwrap_or_else(|err| { - span_mirbug!( - self, - span, - "ascribe_user_type `{mir_ty:?}=={user_ty:?}` failed with `{err:?}`", - ); - }); + ); } /// *Incorrectly* skips the WF checks we normally do in `ascribe_user_type`. @@ -219,7 +207,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let cause = ObligationCause::dummy_with_span(span); let param_env = self.param_env; - self.fully_perform_op( + let _: Result<_, ErrorGuaranteed> = self.fully_perform_op( Locations::All(span), ConstraintCategory::Boring, type_op::custom::CustomTypeOp::new( @@ -230,13 +218,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { }, "ascribe_user_type_skip_wf", ), - ) - .unwrap_or_else(|err| { - span_mirbug!( - self, - span, - "ascribe_user_type_skip_wf `{mir_ty:?}=={user_ty:?}` failed with `{err:?}`", - ); - }); + ); } } 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 bd01c0b504c..c8ec1257d37 100644 --- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs +++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs @@ -8,7 +8,7 @@ use rustc_infer::infer::InferCtxt; use rustc_middle::mir::ConstraintCategory; use rustc_middle::traits::query::OutlivesBound; use rustc_middle::ty::{self, RegionVid, Ty}; -use rustc_span::Span; +use rustc_span::{Span, DUMMY_SP}; use rustc_trait_selection::traits::query::type_op::{self, TypeOp}; use std::rc::Rc; use type_op::TypeOpOutput; @@ -243,18 +243,11 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { let TypeOpOutput { output: norm_ty, constraints: constraints_normalize, .. } = self .param_env .and(type_op::normalize::Normalize::new(ty)) - .fully_perform(self.infcx) - .unwrap_or_else(|_| { - let guar = self - .infcx - .tcx - .sess - .delay_span_bug(span, format!("failed to normalize {:?}", ty)); - TypeOpOutput { - output: self.infcx.tcx.ty_error(guar), - constraints: None, - error_info: None, - } + .fully_perform(self.infcx, span) + .unwrap_or_else(|guar| TypeOpOutput { + output: self.infcx.tcx.ty_error(guar), + constraints: None, + error_info: None, }); if let Some(c) = constraints_normalize { constraints.push(c) @@ -324,7 +317,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { let TypeOpOutput { output: bounds, constraints, .. } = self .param_env .and(type_op::implied_outlives_bounds::ImpliedOutlivesBounds { ty }) - .fully_perform(self.infcx) + .fully_perform(self.infcx, DUMMY_SP) .unwrap_or_else(|_| bug!("failed to compute implied bounds {:?}", ty)); debug!(?bounds, ?constraints); self.add_outlives_bounds(bounds); diff --git a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs index 9731b10aa99..eb02604b9d9 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs @@ -3,8 +3,9 @@ use rustc_index::bit_set::HybridBitSet; use rustc_index::interval::IntervalSet; use rustc_infer::infer::canonical::QueryRegionConstraints; use rustc_middle::mir::{BasicBlock, Body, ConstraintCategory, Local, Location}; +use rustc_middle::traits::query::DropckOutlivesResult; use rustc_middle::ty::{Ty, TyCtxt, TypeVisitable, TypeVisitableExt}; -use rustc_trait_selection::traits::query::dropck_outlives::DropckOutlivesResult; +use rustc_span::DUMMY_SP; use rustc_trait_selection::traits::query::type_op::outlives::DropckOutlives; use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput}; use std::rc::Rc; @@ -568,10 +569,15 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> { ) -> DropData<'tcx> { debug!("compute_drop_data(dropped_ty={:?})", dropped_ty,); - let param_env = typeck.param_env; - let TypeOpOutput { output, constraints, .. } = - param_env.and(DropckOutlives::new(dropped_ty)).fully_perform(typeck.infcx).unwrap(); - - DropData { dropck_result: output, region_constraint_data: constraints } + match typeck + .param_env + .and(DropckOutlives::new(dropped_ty)) + .fully_perform(typeck.infcx, DUMMY_SP) + { + Ok(TypeOpOutput { output, constraints, .. }) => { + DropData { dropck_result: output, region_constraint_data: constraints } + } + Err(_) => DropData { dropck_result: Default::default(), region_constraint_data: None }, + } } } diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index cf204cff6b3..3b896f6540c 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -10,6 +10,7 @@ use either::Either; use hir::OpaqueTyOrigin; use rustc_data_structures::frozen::Frozen; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; +use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; @@ -26,6 +27,7 @@ use rustc_middle::mir::tcx::PlaceTy; use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::AssertKind; use rustc_middle::mir::*; +use rustc_middle::traits::query::NoSolution; use rustc_middle::ty::adjustment::PointerCast; use rustc_middle::ty::cast::CastTy; use rustc_middle::ty::subst::{SubstsRef, UserSubsts}; @@ -41,7 +43,7 @@ use rustc_target::abi::{FieldIdx, FIRST_VARIANT}; use rustc_trait_selection::traits::query::type_op::custom::scrape_region_constraints; use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp; use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput}; -use rustc_trait_selection::traits::query::Fallible; + use rustc_trait_selection::traits::PredicateObligation; use rustc_mir_dataflow::impls::MaybeInitializedPlaces; @@ -137,7 +139,7 @@ pub(crate) fn type_check<'mir, 'tcx>( upvars: &[Upvar<'tcx>], use_polonius: bool, ) -> MirTypeckResults<'tcx> { - let implicit_region_bound = infcx.tcx.mk_re_var(universal_regions.fr_fn_body); + 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(), @@ -216,24 +218,22 @@ pub(crate) fn type_check<'mir, 'tcx>( let opaque_type_values = opaque_type_values .into_iter() .map(|(opaque_type_key, decl)| { - checker - .fully_perform_op( - Locations::All(body.span), - ConstraintCategory::OpaqueType, - CustomTypeOp::new( - |ocx| { - ocx.infcx.register_member_constraints( - param_env, - opaque_type_key, - decl.hidden_type.ty, - decl.hidden_type.span, - ); - Ok(()) - }, - "opaque_type_map", - ), - ) - .unwrap(); + let _: Result<_, ErrorGuaranteed> = checker.fully_perform_op( + Locations::All(body.span), + ConstraintCategory::OpaqueType, + CustomTypeOp::new( + |ocx| { + ocx.infcx.register_member_constraints( + param_env, + opaque_type_key, + decl.hidden_type.ty, + decl.hidden_type.span, + ); + Ok(()) + }, + "opaque_type_map", + ), + ); let mut hidden_type = infcx.resolve_vars_if_possible(decl.hidden_type); trace!("finalized opaque type {:?} to {:#?}", opaque_type_key, hidden_type.ty.kind()); if hidden_type.has_non_region_infer() { @@ -766,8 +766,8 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { PlaceContext::MutatingUse(_) => ty::Invariant, PlaceContext::NonUse(StorageDead | StorageLive | VarDebugInfo) => ty::Invariant, PlaceContext::NonMutatingUse( - Inspect | Copy | Move | PlaceMention | SharedBorrow | ShallowBorrow | UniqueBorrow - | AddressOf | Projection, + Inspect | Copy | Move | PlaceMention | SharedBorrow | ShallowBorrow | AddressOf + | Projection, ) => ty::Covariant, PlaceContext::NonUse(AscribeUserTy(variance)) => variance, } @@ -1134,7 +1134,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { sup: Ty<'tcx>, locations: Locations, category: ConstraintCategory<'tcx>, - ) -> Fallible<()> { + ) -> Result<(), NoSolution> { // Use this order of parameters because the sup type is usually the // "expected" type in diagnostics. self.relate_types(sup, ty::Variance::Contravariant, sub, locations, category) @@ -1147,7 +1147,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { found: Ty<'tcx>, locations: Locations, category: ConstraintCategory<'tcx>, - ) -> Fallible<()> { + ) -> Result<(), NoSolution> { self.relate_types(expected, ty::Variance::Invariant, found, locations, category) } @@ -1159,7 +1159,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { user_ty: &UserTypeProjection, locations: Locations, category: ConstraintCategory<'tcx>, - ) -> Fallible<()> { + ) -> Result<(), NoSolution> { let annotated_type = self.user_type_annotations[user_ty.base].inferred_ty; trace!(?annotated_type); let mut curr_projected_ty = PlaceTy::from_ty(annotated_type); @@ -2755,11 +2755,20 @@ impl<'tcx> TypeOp<'tcx> for InstantiateOpaqueType<'tcx> { /// constraints in our `InferCtxt` type ErrorInfo = InstantiateOpaqueType<'tcx>; - fn fully_perform(mut self, infcx: &InferCtxt<'tcx>) -> Fallible<TypeOpOutput<'tcx, Self>> { - let (mut output, region_constraints) = scrape_region_constraints(infcx, |ocx| { - ocx.register_obligations(self.obligations.clone()); - Ok(()) - })?; + fn fully_perform( + mut self, + infcx: &InferCtxt<'tcx>, + span: Span, + ) -> Result<TypeOpOutput<'tcx, Self>, ErrorGuaranteed> { + let (mut output, region_constraints) = scrape_region_constraints( + infcx, + |ocx| { + ocx.register_obligations(self.obligations.clone()); + Ok(()) + }, + "InstantiateOpaqueType", + span, + )?; self.region_constraints = Some(region_constraints); output.error_info = Some(self); Ok(output) diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs index dd1f89e5b91..8c4bfb2c6e0 100644 --- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs +++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs @@ -1,12 +1,13 @@ +use rustc_errors::ErrorGuaranteed; use rustc_infer::infer::nll_relate::{TypeRelating, TypeRelatingDelegate}; use rustc_infer::infer::NllRegionVariableOrigin; use rustc_infer::traits::PredicateObligations; use rustc_middle::mir::ConstraintCategory; +use rustc_middle::traits::query::NoSolution; use rustc_middle::ty::relate::TypeRelation; use rustc_middle::ty::{self, Ty}; use rustc_span::symbol::sym; use rustc_span::{Span, Symbol}; -use rustc_trait_selection::traits::query::Fallible; use crate::constraints::OutlivesConstraint; use crate::diagnostics::UniverseInfo; @@ -30,7 +31,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { b: Ty<'tcx>, locations: Locations, category: ConstraintCategory<'tcx>, - ) -> Fallible<()> { + ) -> Result<(), NoSolution> { TypeRelating::new( self.infcx, NllTypeRelatingDelegate::new(self, locations, category, UniverseInfo::relate(a, b)), @@ -47,7 +48,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { b: ty::SubstsRef<'tcx>, locations: Locations, category: ConstraintCategory<'tcx>, - ) -> Fallible<()> { + ) -> Result<(), NoSolution> { TypeRelating::new( self.infcx, NllTypeRelatingDelegate::new(self, locations, category, UniverseInfo::other()), @@ -185,7 +186,7 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> } fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) { - match self.type_checker.fully_perform_op( + let _: Result<_, ErrorGuaranteed> = self.type_checker.fully_perform_op( self.locations, self.category, InstantiateOpaqueType { @@ -194,16 +195,6 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> base_universe: None, region_constraints: None, }, - ) { - Ok(()) => {} - Err(_) => { - // It's a bit redundant to delay a bug here, but I'd rather - // delay more bugs than accidentally not delay a bug at all. - self.type_checker.tcx().sess.delay_span_bug( - self.locations.span(self.type_checker.body), - "errors selecting obligation during MIR typeck", - ); - } - }; + ); } } diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index 56f078f2da8..c871703429a 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -500,7 +500,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { .next_nll_region_var(FR, || RegionCtxt::Free(Symbol::intern("c-variadic"))) .as_var(); - let region = self.infcx.tcx.mk_re_var(reg_vid); + let region = ty::Region::new_var(self.infcx.tcx, reg_vid); let va_list_ty = self.infcx.tcx.type_of(va_list_did).subst(self.infcx.tcx, &[region.into()]); @@ -660,7 +660,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind: ty::BrEnv, }; - let env_region = tcx.mk_re_late_bound(ty::INNERMOST, br); + let env_region = ty::Region::new_late_bound(tcx, ty::INNERMOST, br); let closure_ty = tcx.closure_env_ty(def_id, substs, env_region).unwrap(); // The "inputs" of the closure in the @@ -778,7 +778,8 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for BorrowckInferCtxt<'cx, 'tcx> { { let (value, _map) = self.tcx.replace_late_bound_regions(value, |br| { debug!(?br); - let liberated_region = self.tcx.mk_re_free(all_outlive_scope.to_def_id(), br.kind); + let liberated_region = + ty::Region::new_free(self.tcx, all_outlive_scope.to_def_id(), br.kind); let region_vid = { let name = match br.kind.get_name() { Some(name) => name, @@ -889,7 +890,7 @@ impl<'tcx> UniversalRegionIndices<'tcx> { where T: TypeFoldable<TyCtxt<'tcx>>, { - tcx.fold_regions(value, |region, _| tcx.mk_re_var(self.to_region_vid(region))) + tcx.fold_regions(value, |region, _| ty::Region::new_var(tcx, self.to_region_vid(region))) } } @@ -929,7 +930,7 @@ fn for_each_late_bound_region_in_item<'tcx>( for bound_var in tcx.late_bound_vars(tcx.hir().local_def_id_to_hir_id(mir_def_id)) { let ty::BoundVariableKind::Region(bound_region) = bound_var else { continue; }; - let liberated_region = tcx.mk_re_free(mir_def_id.to_def_id(), bound_region); + let liberated_region = ty::Region::new_free(tcx, mir_def_id.to_def_id(), bound_region); f(liberated_region); } } diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl index 3b458b1d30b..f00cd39cbc8 100644 --- a/compiler/rustc_builtin_macros/messages.ftl +++ b/compiler/rustc_builtin_macros/messages.ftl @@ -1,10 +1,50 @@ -builtin_macros_requires_cfg_pattern = - macro requires a cfg-pattern as an argument - .label = cfg-pattern required +builtin_macros_alloc_error_must_be_fn = alloc_error_handler must be a function -builtin_macros_expected_one_cfg_pattern = expected 1 cfg-pattern +builtin_macros_asm_clobber_abi = clobber_abi +builtin_macros_asm_clobber_no_reg = asm with `clobber_abi` must specify explicit registers for outputs +builtin_macros_asm_clobber_outputs = generic outputs -builtin_macros_alloc_error_must_be_fn = alloc_error_handler must be a function +builtin_macros_asm_duplicate_arg = duplicate argument named `{$name}` + .label = previously here + .arg = duplicate argument + +builtin_macros_asm_expected_comma = expected token: `,` + .label = expected `,` + +builtin_macros_asm_expected_other = expected operand, {$is_global_asm -> + [true] options + *[false] clobber_abi, options + }, or additional template string + +builtin_macros_asm_explicit_register_name = explicit register arguments cannot have names + +builtin_macros_asm_modifier_invalid = asm template modifier must be a single character + +builtin_macros_asm_mutually_exclusive = the `{$opt1}` and `{$opt2}` options are mutually exclusive + +builtin_macros_asm_noreturn = asm outputs are not allowed with the `noreturn` option + +builtin_macros_asm_opt_already_provided = the `{$symbol}` option was already provided + .label = this option was already provided + .suggestion = remove this option + +builtin_macros_asm_pos_after = positional arguments cannot follow named arguments or explicit register arguments + .pos = positional argument + .named = named argument + .explicit = explicit register argument + +builtin_macros_asm_pure_combine = the `pure` option must be combined with either `nomem` or `readonly` + +builtin_macros_asm_pure_no_output = asm with the `pure` option must have at least one output + +builtin_macros_asm_requires_template = requires at least a template string argument + +builtin_macros_asm_sym_no_path = expected a path for argument to `sym` + +builtin_macros_asm_underscore_input = _ cannot be used for input operands + +builtin_macros_assert_missing_comma = unexpected string literal + .suggestion = try adding a comma builtin_macros_assert_requires_boolean = macro requires a boolean expression as an argument .label = boolean expression required @@ -12,51 +52,50 @@ builtin_macros_assert_requires_boolean = macro requires a boolean expression as builtin_macros_assert_requires_expression = macro requires an expression as an argument .suggestion = try removing semicolon -builtin_macros_assert_missing_comma = unexpected string literal - .suggestion = try adding a comma +builtin_macros_bad_derive_target = `derive` may only be applied to `struct`s, `enum`s and `union`s + .label = not applicable here + .label2 = not a `struct`, `enum` or `union` + +builtin_macros_cannot_derive_union = this trait cannot be derived for unions -builtin_macros_cfg_accessible_unspecified_path = `cfg_accessible` path is not specified -builtin_macros_cfg_accessible_multiple_paths = multiple `cfg_accessible` paths are specified -builtin_macros_cfg_accessible_literal_path = `cfg_accessible` path cannot be a literal builtin_macros_cfg_accessible_has_args = `cfg_accessible` path cannot accept arguments builtin_macros_cfg_accessible_indeterminate = cannot determine whether the path is accessible or not -builtin_macros_concat_bytestr = cannot concatenate a byte string literal - -builtin_macros_concat_missing_literal = expected a literal - .note = only literals (like `"foo"`, `-42` and `3.14`) can be passed to `concat!()` +builtin_macros_cfg_accessible_literal_path = `cfg_accessible` path cannot be a literal +builtin_macros_cfg_accessible_multiple_paths = multiple `cfg_accessible` paths are specified +builtin_macros_cfg_accessible_unspecified_path = `cfg_accessible` path is not specified +builtin_macros_concat_bytes_array = cannot concatenate doubly nested array + .note = byte strings are treated as arrays of bytes + .help = try flattening the array -builtin_macros_concat_bytes_missing_literal = expected a byte literal - .note = only byte literals (like `b"foo"`, `b's'` and `[3, 4, 5]`) can be passed to `concat_bytes!()` +builtin_macros_concat_bytes_bad_repeat = repeat count is not a positive number builtin_macros_concat_bytes_invalid = cannot concatenate {$lit_kind} literals .byte_char = try using a byte character .byte_str = try using a byte string .number_array = try wrapping the number in an array -builtin_macros_concat_bytes_oob = numeric literal is out of bounds +builtin_macros_concat_bytes_missing_literal = expected a byte literal + .note = only byte literals (like `b"foo"`, `b's'` and `[3, 4, 5]`) can be passed to `concat_bytes!()` builtin_macros_concat_bytes_non_u8 = numeric literal is not a `u8` -builtin_macros_concat_bytes_array = cannot concatenate doubly nested array - .note = byte strings are treated as arrays of bytes - .help = try flattening the array +builtin_macros_concat_bytes_oob = numeric literal is out of bounds -builtin_macros_concat_bytes_bad_repeat = repeat count is not a positive number +builtin_macros_concat_bytestr = cannot concatenate a byte string literal + +builtin_macros_concat_idents_ident_args = `concat_idents!()` requires ident args builtin_macros_concat_idents_missing_args = `concat_idents!()` takes 1 or more arguments builtin_macros_concat_idents_missing_comma = `concat_idents!()` expecting comma -builtin_macros_concat_idents_ident_args = `concat_idents!()` requires ident args +builtin_macros_concat_missing_literal = expected a literal + .note = only literals (like `"foo"`, `-42` and `3.14`) can be passed to `concat!()` -builtin_macros_bad_derive_target = `derive` may only be applied to `struct`s, `enum`s and `union`s - .label = not applicable here - .label2 = not a `struct`, `enum` or `union` +builtin_macros_default_arg = `#[default]` attribute does not accept a value + .suggestion = try using `#[default]` -builtin_macros_unexpected_lit = expected path to a trait, found literal - .label = not a trait - .str_lit = try using `#[derive({$sym})]` - .other = for example, write `#[derive(Debug)]` for `Debug` +builtin_macros_derive_macro_call = `derive` cannot be used on items with type macros builtin_macros_derive_path_args_list = traits in `#[derive(...)]` don't accept arguments .suggestion = remove the arguments @@ -64,66 +103,38 @@ builtin_macros_derive_path_args_list = traits in `#[derive(...)]` don't accept a builtin_macros_derive_path_args_value = traits in `#[derive(...)]` don't accept values .suggestion = remove the value -builtin_macros_derive_macro_call = `derive` cannot be used on items with type macros - -builtin_macros_cannot_derive_union = this trait cannot be derived for unions - -builtin_macros_no_default_variant = no default declared - .help = make a unit variant default by placing `#[default]` above it - .suggestion = make `{$ident}` default - -builtin_macros_multiple_defaults = multiple declared defaults - .label = first default - .additional = additional default - .note = only one variant can be default - .suggestion = make `{$ident}` default - -builtin_macros_non_unit_default = the `#[default]` attribute may only be used on unit enum variants - .help = consider a manual implementation of `Default` - -builtin_macros_non_exhaustive_default = default variant must be exhaustive - .label = declared `#[non_exhaustive]` here - .help = consider a manual implementation of `Default` - -builtin_macros_multiple_default_attrs = multiple `#[default]` attributes - .note = only one `#[default]` attribute is needed - .label = `#[default]` used here - .label_again = `#[default]` used again here - .help = try removing {$only_one -> - [true] this - *[false] these - } - -builtin_macros_default_arg = `#[default]` attribute does not accept a value - .suggestion = try using `#[default]` - -builtin_macros_env_takes_args = `env!()` takes 1 or 2 arguments - builtin_macros_env_not_defined = environment variable `{$var}` not defined at compile time .cargo = Cargo sets build script variables at run time. Use `std::env::var("{$var}")` instead .other = use `std::env::var("{$var}")` to read the variable at run time -builtin_macros_format_requires_string = requires at least a format string argument +builtin_macros_env_takes_args = `env!()` takes 1 or 2 arguments + +builtin_macros_expected_one_cfg_pattern = expected 1 cfg-pattern builtin_macros_format_duplicate_arg = duplicate argument named `{$ident}` .label1 = previously here .label2 = duplicate argument +builtin_macros_format_no_arg_named = there is no argument named `{$name}` + .note = did you intend to capture a variable `{$name}` from the surrounding scope? + .note2 = to avoid ambiguity, `format_args!` cannot capture variables when the format string is expanded from a macro + +builtin_macros_format_pos_mismatch = {$n} positional {$n -> + [one] argument + *[more] arguments + } in format string, but {$desc} + builtin_macros_format_positional_after_named = positional arguments cannot follow named arguments .label = positional arguments must be before named arguments .named_args = named argument +builtin_macros_format_requires_string = requires at least a format string argument + builtin_macros_format_string_invalid = invalid format string: {$desc} .label = {$label1} in format string .note = {$note} .second_label = {$label} -builtin_macros_sugg = consider using a positional formatting argument instead - -builtin_macros_format_no_arg_named = there is no argument named `{$name}` - .note = did you intend to capture a variable `{$name}` from the surrounding scope? - .note2 = to avoid ambiguity, `format_args!` cannot capture variables when the format string is expanded from a macro - builtin_macros_format_unknown_trait = unknown format trait `{$ty}` .note = the only appropriate formatting traits are: - ``, which uses the `Display` trait @@ -145,60 +156,49 @@ builtin_macros_format_unused_arg = {$named -> builtin_macros_format_unused_args = multiple unused formatting arguments .label = multiple missing formatting specifiers -builtin_macros_format_pos_mismatch = {$n} positional {$n -> - [one] argument - *[more] arguments - } in format string, but {$desc} - -builtin_macros_test_case_non_item = `#[test_case]` attribute is only allowed on items - -builtin_macros_test_bad_fn = {$kind} functions cannot be used for tests - .label = `{$kind}` because of this - -builtin_macros_asm_explicit_register_name = explicit register arguments cannot have names - -builtin_macros_asm_mutually_exclusive = the `{$opt1}` and `{$opt2}` options are mutually exclusive - -builtin_macros_asm_pure_combine = the `pure` option must be combined with either `nomem` or `readonly` - -builtin_macros_asm_pure_no_output = asm with the `pure` option must have at least one output - -builtin_macros_asm_modifier_invalid = asm template modifier must be a single character - -builtin_macros_asm_requires_template = requires at least a template string argument - -builtin_macros_asm_expected_comma = expected token: `,` - .label = expected `,` +builtin_macros_global_asm_clobber_abi = `clobber_abi` cannot be used with `global_asm!` -builtin_macros_asm_underscore_input = _ cannot be used for input operands +builtin_macros_multiple_default_attrs = multiple `#[default]` attributes + .note = only one `#[default]` attribute is needed + .label = `#[default]` used here + .label_again = `#[default]` used again here + .help = try removing {$only_one -> + [true] this + *[false] these + } -builtin_macros_asm_sym_no_path = expected a path for argument to `sym` +builtin_macros_multiple_defaults = multiple declared defaults + .label = first default + .additional = additional default + .note = only one variant can be default + .suggestion = make `{$ident}` default -builtin_macros_asm_expected_other = expected operand, {$is_global_asm -> - [true] options - *[false] clobber_abi, options - }, or additional template string +builtin_macros_no_default_variant = no default declared + .help = make a unit variant default by placing `#[default]` above it + .suggestion = make `{$ident}` default -builtin_macros_asm_duplicate_arg = duplicate argument named `{$name}` - .label = previously here - .arg = duplicate argument +builtin_macros_non_exhaustive_default = default variant must be exhaustive + .label = declared `#[non_exhaustive]` here + .help = consider a manual implementation of `Default` -builtin_macros_asm_pos_after = positional arguments cannot follow named arguments or explicit register arguments - .pos = positional argument - .named = named argument - .explicit = explicit register argument +builtin_macros_non_unit_default = the `#[default]` attribute may only be used on unit enum variants + .help = consider a manual implementation of `Default` -builtin_macros_asm_noreturn = asm outputs are not allowed with the `noreturn` option +builtin_macros_requires_cfg_pattern = + macro requires a cfg-pattern as an argument + .label = cfg-pattern required -builtin_macros_global_asm_clobber_abi = `clobber_abi` cannot be used with `global_asm!` +builtin_macros_sugg = consider using a positional formatting argument instead -builtin_macros_asm_clobber_no_reg = asm with `clobber_abi` must specify explicit registers for outputs -builtin_macros_asm_clobber_abi = clobber_abi -builtin_macros_asm_clobber_outputs = generic outputs +builtin_macros_test_bad_fn = {$kind} functions cannot be used for tests + .label = `{$kind}` because of this -builtin_macros_asm_opt_already_provided = the `{$symbol}` option was already provided - .label = this option was already provided - .suggestion = remove this option +builtin_macros_test_case_non_item = `#[test_case]` attribute is only allowed on items builtin_macros_test_runner_invalid = `test_runner` argument must be a path builtin_macros_test_runner_nargs = `#![test_runner(..)]` accepts exactly 1 argument + +builtin_macros_unexpected_lit = expected path to a trait, found literal + .label = not a trait + .str_lit = try using `#[derive({$sym})]` + .other = for example, write `#[derive(Debug)]` for `Debug` diff --git a/compiler/rustc_builtin_macros/src/assert/context.rs b/compiler/rustc_builtin_macros/src/assert/context.rs index ea830a0ce60..b619e80e15f 100644 --- a/compiler/rustc_builtin_macros/src/assert/context.rs +++ b/compiler/rustc_builtin_macros/src/assert/context.rs @@ -233,10 +233,19 @@ impl<'cx, 'a> Context<'cx, 'a> { ExprKind::Cast(local_expr, _) => { self.manage_cond_expr(local_expr); } + ExprKind::If(local_expr, _, _) => { + self.manage_cond_expr(local_expr); + } ExprKind::Index(prefix, suffix) => { self.manage_cond_expr(prefix); self.manage_cond_expr(suffix); } + ExprKind::Let(_, local_expr, _) => { + self.manage_cond_expr(local_expr); + } + ExprKind::Match(local_expr, _) => { + self.manage_cond_expr(local_expr); + } ExprKind::MethodCall(call) => { for arg in &mut call.args { self.manage_cond_expr(arg); @@ -295,17 +304,14 @@ impl<'cx, 'a> Context<'cx, 'a> { | ExprKind::Continue(_) | ExprKind::Err | ExprKind::Field(_, _) - | ExprKind::FormatArgs(_) | ExprKind::ForLoop(_, _, _, _) - | ExprKind::If(_, _, _) + | ExprKind::FormatArgs(_) | ExprKind::IncludedBytes(..) | ExprKind::InlineAsm(_) - | ExprKind::OffsetOf(_, _) - | ExprKind::Let(_, _, _) | ExprKind::Lit(_) | ExprKind::Loop(_, _, _) | ExprKind::MacCall(_) - | ExprKind::Match(_, _) + | ExprKind::OffsetOf(_, _) | ExprKind::Path(_, _) | ExprKind::Ret(_) | ExprKind::Try(_) diff --git a/compiler/rustc_builtin_macros/src/compile_error.rs b/compiler/rustc_builtin_macros/src/compile_error.rs index aeb3bb80045..5efc5a4e3ee 100644 --- a/compiler/rustc_builtin_macros/src/compile_error.rs +++ b/compiler/rustc_builtin_macros/src/compile_error.rs @@ -18,7 +18,7 @@ pub fn expand_compile_error<'cx>( reason = "diagnostic message is specified by user" )] #[expect(rustc::untranslatable_diagnostic, reason = "diagnostic message is specified by user")] - cx.span_err(sp, var.as_str()); + cx.span_err(sp, var.to_string()); DummyResult::any(sp) } diff --git a/compiler/rustc_builtin_macros/src/deriving/clone.rs b/compiler/rustc_builtin_macros/src/deriving/clone.rs index 9883563746e..9ba98d0a5d1 100644 --- a/compiler/rustc_builtin_macros/src/deriving/clone.rs +++ b/compiler/rustc_builtin_macros/src/deriving/clone.rs @@ -68,7 +68,6 @@ pub fn expand_deriving_clone( _ => cx.span_bug(span, "`#[derive(Clone)]` on trait item or impl item"), } - let attrs = thin_vec![cx.attr_word(sym::inline, span)]; let trait_def = TraitDef { span, path: path_std!(clone::Clone), @@ -82,7 +81,7 @@ pub fn expand_deriving_clone( explicit_self: true, nonself_args: Vec::new(), ret_ty: Self_, - attributes: attrs, + attributes: thin_vec![cx.attr_word(sym::inline, span)], fieldless_variants_strategy: FieldlessVariantsStrategy::Default, combine_substructure: substructure, }], diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs index af971958680..c78a0eb04a0 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs @@ -18,11 +18,6 @@ pub fn expand_deriving_eq( is_const: bool, ) { let span = cx.with_def_site_ctxt(span); - let attrs = thin_vec![ - cx.attr_word(sym::inline, span), - cx.attr_nested_word(sym::doc, sym::hidden, span), - cx.attr_word(sym::no_coverage, span) - ]; let trait_def = TraitDef { span, path: path_std!(cmp::Eq), @@ -36,7 +31,11 @@ pub fn expand_deriving_eq( explicit_self: true, nonself_args: vec![], ret_ty: Unit, - attributes: attrs, + attributes: thin_vec![ + cx.attr_word(sym::inline, span), + cx.attr_nested_word(sym::doc, sym::hidden, span), + cx.attr_word(sym::no_coverage, span) + ], fieldless_variants_strategy: FieldlessVariantsStrategy::Unify, combine_substructure: combine_substructure(Box::new(|a, b, c| { cs_total_eq_assert(a, b, c) diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs index cfd36f030a1..4401cf8a9c5 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs @@ -15,7 +15,6 @@ pub fn expand_deriving_ord( push: &mut dyn FnMut(Annotatable), is_const: bool, ) { - let attrs = thin_vec![cx.attr_word(sym::inline, span)]; let trait_def = TraitDef { span, path: path_std!(cmp::Ord), @@ -29,7 +28,7 @@ pub fn expand_deriving_ord( explicit_self: true, nonself_args: vec![(self_ref(), sym::other)], ret_ty: Path(path_std!(cmp::Ordering)), - attributes: attrs, + attributes: thin_vec![cx.attr_word(sym::inline, span)], fieldless_variants_strategy: FieldlessVariantsStrategy::Unify, combine_substructure: combine_substructure(Box::new(|a, b, c| cs_cmp(a, b, c))), }], diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs index bad47db0de1..a71ecc5db7d 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs @@ -82,14 +82,13 @@ pub fn expand_deriving_partial_eq( // No need to generate `ne`, the default suffices, and not generating it is // faster. - let attrs = thin_vec![cx.attr_word(sym::inline, span)]; let methods = vec![MethodDef { name: sym::eq, generics: Bounds::empty(), explicit_self: true, nonself_args: vec![(self_ref(), sym::other)], ret_ty: Path(path_local!(bool)), - attributes: attrs, + attributes: thin_vec![cx.attr_word(sym::inline, span)], fieldless_variants_strategy: FieldlessVariantsStrategy::Unify, combine_substructure: combine_substructure(Box::new(|a, b, c| cs_eq(a, b, c))), }]; diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs index 9f46247908d..54b6cb7d713 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs @@ -19,8 +19,6 @@ pub fn expand_deriving_partial_ord( let ret_ty = Path(Path::new_(pathvec_std!(option::Option), vec![Box::new(ordering_ty)], PathKind::Std)); - let attrs = thin_vec![cx.attr_word(sym::inline, span)]; - // Order in which to perform matching let tag_then_data = if let Annotatable::Item(item) = item && let ItemKind::Enum(def, _) = &item.kind { @@ -48,7 +46,7 @@ pub fn expand_deriving_partial_ord( explicit_self: true, nonself_args: vec![(self_ref(), sym::other)], ret_ty, - attributes: attrs, + attributes: thin_vec![cx.attr_word(sym::inline, span)], fieldless_variants_strategy: FieldlessVariantsStrategy::Unify, combine_substructure: combine_substructure(Box::new(|cx, span, substr| { cs_partial_cmp(cx, span, substr, tag_then_data) diff --git a/compiler/rustc_builtin_macros/src/deriving/default.rs b/compiler/rustc_builtin_macros/src/deriving/default.rs index 33fe98b40e1..07b172bc757 100644 --- a/compiler/rustc_builtin_macros/src/deriving/default.rs +++ b/compiler/rustc_builtin_macros/src/deriving/default.rs @@ -20,7 +20,6 @@ pub fn expand_deriving_default( ) { item.visit_with(&mut DetectNonVariantDefaultAttr { cx }); - let attrs = thin_vec![cx.attr_word(sym::inline, span)]; let trait_def = TraitDef { span, path: Path::new(vec![kw::Default, sym::Default]), @@ -34,7 +33,7 @@ pub fn expand_deriving_default( explicit_self: false, nonself_args: Vec::new(), ret_ty: Self_, - attributes: attrs, + attributes: thin_vec![cx.attr_word(sym::inline, span)], fieldless_variants_strategy: FieldlessVariantsStrategy::Default, combine_substructure: combine_substructure(Box::new(|cx, trait_span, substr| { match substr.fields { diff --git a/compiler/rustc_builtin_macros/src/deriving/hash.rs b/compiler/rustc_builtin_macros/src/deriving/hash.rs index 4eee573db42..101401f9c85 100644 --- a/compiler/rustc_builtin_macros/src/deriving/hash.rs +++ b/compiler/rustc_builtin_macros/src/deriving/hash.rs @@ -1,7 +1,7 @@ use crate::deriving::generic::ty::*; use crate::deriving::generic::*; use crate::deriving::{path_std, pathvec_std}; -use rustc_ast::{AttrVec, MetaItem, Mutability}; +use rustc_ast::{MetaItem, Mutability}; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_span::symbol::sym; use rustc_span::Span; @@ -33,7 +33,7 @@ pub fn expand_deriving_hash( explicit_self: true, nonself_args: vec![(Ref(Box::new(Path(arg)), Mutability::Mut), sym::state)], ret_ty: Unit, - attributes: AttrVec::new(), + attributes: thin_vec![cx.attr_word(sym::inline, span)], fieldless_variants_strategy: FieldlessVariantsStrategy::Unify, combine_substructure: combine_substructure(Box::new(|a, b, c| { hash_substructure(a, b, c) diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs index d0d78646009..f1ab279daba 100644 --- a/compiler/rustc_builtin_macros/src/errors.rs +++ b/compiler/rustc_builtin_macros/src/errors.rs @@ -377,7 +377,7 @@ impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for EnvNotDefined { rustc::untranslatable_diagnostic, reason = "cannot translate user-provided messages" )] - handler.struct_diagnostic(msg.as_str()) + handler.struct_diagnostic(msg.to_string()) } else { handler.struct_diagnostic(crate::fluent_generated::builtin_macros_env_not_defined) }; diff --git a/compiler/rustc_codegen_cranelift/Readme.md b/compiler/rustc_codegen_cranelift/Readme.md index c5222982aa7..26dccf309e1 100644 --- a/compiler/rustc_codegen_cranelift/Readme.md +++ b/compiler/rustc_codegen_cranelift/Readme.md @@ -42,6 +42,32 @@ This will build your project with rustc_codegen_cranelift instead of the usual L For additional ways to use rustc_codegen_cranelift like the JIT mode see [usage.md](docs/usage.md). +## Building and testing with changes in rustc code + +This is useful when changing code in `rustc_codegen_cranelift` as part of changing [main Rust repository](https://github.com/rust-lang/rust/). +This can happen, for example, when you are implementing a new compiler intrinsic. + +Instruction below uses `$RustCheckoutDir` as substitute for any folder where you cloned Rust repository. + +You need to do this steps to successfully compile and use the cranelift backend with your changes in rustc code: + +1. `cd $RustCheckoutDir` +2. Run `python x.py setup` and choose option for compiler (`b`). +3. Build compiler and necessary tools: `python x.py build --stage=2 compiler library/std src/tools/rustdoc src/tools/rustfmt` + * (Optional) You can also build cargo by adding `src/tools/cargo` to previous command. +4. Copy exectutable files from `./build/host/stage2-tools/<your hostname triple>/release` +to `./build/host/stage2/bin/`. Note that you would need to do this every time you rebuilt `rust` repository. +5. Copy cargo from another toolchain: `cp $(rustup which cargo) .build/<your hostname triple>/stage2/bin/cargo` + * Another option is to build it at step 3 and copy with other executables at step 4. +6. Link your new `rustc` to toolchain: `rustup toolchain link stage2 ./build/host/stage2/`. +7. (Windows only) compile y.rs: `rustc +stage2 -O y.rs`. +8. You need to prefix every `./y.rs` (or `y` if you built `y.rs`) command by `rustup run stage2` to make cg_clif use your local changes in rustc. + + * `rustup run stage2 ./y.rs prepare` + * `rustup run stage2 ./y.rs build` + * (Optional) run tests: `rustup run stage2 ./y.rs test` +9. Now you can use your cg_clif build to compile other Rust programs, e.g. you can open any Rust crate and run commands like `$RustCheckoutDir/compiler/rustc_codegen_cranelift/dist/cargo-clif build --release`. + ## Configuration See the documentation on the `BackendConfig` struct in [config.rs](src/config.rs) for all diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index 9c6a0fae327..fcfa0b862d4 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -473,7 +473,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { | TerminatorKind::GeneratorDrop => { bug!("shouldn't exist at codegen {:?}", bb_data.terminator()); } - TerminatorKind::Drop { place, target, unwind: _ } => { + TerminatorKind::Drop { place, target, unwind: _, replace: _ } => { let drop_place = codegen_place(fx, *place); crate::abi::codegen_drop(fx, source_info, drop_place); diff --git a/compiler/rustc_codegen_cranelift/src/common.rs b/compiler/rustc_codegen_cranelift/src/common.rs index 5eaa988dd09..67fd6d793e0 100644 --- a/compiler/rustc_codegen_cranelift/src/common.rs +++ b/compiler/rustc_codegen_cranelift/src/common.rs @@ -361,7 +361,7 @@ impl<'tcx> FunctionCx<'_, '_, 'tcx> { self.instance.subst_mir_and_normalize_erasing_regions( self.tcx, ty::ParamEnv::reveal_all(), - ty::EarlyBinder(value), + ty::EarlyBinder::bind(value), ) } diff --git a/compiler/rustc_codegen_gcc/messages.ftl b/compiler/rustc_codegen_gcc/messages.ftl index 0a94a08f8dc..97bc8ef9d1b 100644 --- a/compiler/rustc_codegen_gcc/messages.ftl +++ b/compiler/rustc_codegen_gcc/messages.ftl @@ -1,68 +1,68 @@ -codegen_gcc_unwinding_inline_asm = - GCC backend does not support unwinding from inline asm - -codegen_gcc_lto_not_supported = - LTO is not supported. You may get a linker error. +codegen_gcc_invalid_minimum_alignment = + invalid minimum global alignment: {$err} codegen_gcc_invalid_monomorphization_basic_integer = invalid monomorphization of `{$name}` intrinsic: expected basic integer type, found `{$ty}` -codegen_gcc_invalid_monomorphization_invalid_float_vector = - invalid monomorphization of `{$name}` intrinsic: unsupported element type `{$elem_ty}` of floating-point vector `{$vec_ty}` - -codegen_gcc_invalid_monomorphization_not_float = - invalid monomorphization of `{$name}` intrinsic: `{$ty}` is not a floating-point type - -codegen_gcc_invalid_monomorphization_unrecognized = - invalid monomorphization of `{$name}` intrinsic: unrecognized intrinsic `{$name}` - codegen_gcc_invalid_monomorphization_expected_signed_unsigned = invalid monomorphization of `{$name}` intrinsic: expected element type `{$elem_ty}` of vector type `{$vec_ty}` to be a signed or unsigned integer type -codegen_gcc_invalid_monomorphization_unsupported_element = - invalid monomorphization of `{$name}` intrinsic: unsupported {$name} from `{$in_ty}` with element `{$elem_ty}` to `{$ret_ty}` +codegen_gcc_invalid_monomorphization_expected_simd = + invalid monomorphization of `{$name}` intrinsic: expected SIMD {$expected_ty} type, found non-SIMD `{$found_ty}` + +codegen_gcc_invalid_monomorphization_inserted_type = + invalid monomorphization of `{$name}` intrinsic: expected inserted type `{$in_elem}` (element of input `{$in_ty}`), found `{$out_ty}` codegen_gcc_invalid_monomorphization_invalid_bitmask = invalid monomorphization of `{$name}` intrinsic: invalid bitmask `{$ty}`, expected `u{$expected_int_bits}` or `[u8; {$expected_bytes}]` -codegen_gcc_invalid_monomorphization_simd_shuffle = - invalid monomorphization of `{$name}` intrinsic: simd_shuffle index must be an array of `u32`, got `{$ty}` - -codegen_gcc_invalid_monomorphization_expected_simd = - invalid monomorphization of `{$name}` intrinsic: expected SIMD {$expected_ty} type, found non-SIMD `{$found_ty}` +codegen_gcc_invalid_monomorphization_invalid_float_vector = + invalid monomorphization of `{$name}` intrinsic: unsupported element type `{$elem_ty}` of floating-point vector `{$vec_ty}` codegen_gcc_invalid_monomorphization_mask_type = invalid monomorphization of `{$name}` intrinsic: mask element type is `{$ty}`, expected `i_` +codegen_gcc_invalid_monomorphization_mismatched_lengths = + invalid monomorphization of `{$name}` intrinsic: mismatched lengths: mask length `{$m_len}` != other vector length `{$v_len}` + +codegen_gcc_invalid_monomorphization_not_float = + invalid monomorphization of `{$name}` intrinsic: `{$ty}` is not a floating-point type + +codegen_gcc_invalid_monomorphization_return_element = + invalid monomorphization of `{$name}` intrinsic: expected return element type `{$in_elem}` (element of input `{$in_ty}`), found `{$ret_ty}` with element type `{$out_ty}` + +codegen_gcc_invalid_monomorphization_return_integer_type = + invalid monomorphization of `{$name}` intrinsic: expected return type with integer elements, found `{$ret_ty}` with non-integer `{$out_ty}` + codegen_gcc_invalid_monomorphization_return_length = invalid monomorphization of `{$name}` intrinsic: expected return type of length {$in_len}, found `{$ret_ty}` with length {$out_len} codegen_gcc_invalid_monomorphization_return_length_input_type = invalid monomorphization of `{$name}` intrinsic: expected return type with length {$in_len} (same as input type `{$in_ty}`), found `{$ret_ty}` with length {$out_len} -codegen_gcc_invalid_monomorphization_return_element = - invalid monomorphization of `{$name}` intrinsic: expected return element type `{$in_elem}` (element of input `{$in_ty}`), found `{$ret_ty}` with element type `{$out_ty}` - codegen_gcc_invalid_monomorphization_return_type = invalid monomorphization of `{$name}` intrinsic: expected return type `{$in_elem}` (element of input `{$in_ty}`), found `{$ret_ty}` -codegen_gcc_invalid_monomorphization_inserted_type = - invalid monomorphization of `{$name}` intrinsic: expected inserted type `{$in_elem}` (element of input `{$in_ty}`), found `{$out_ty}` - -codegen_gcc_invalid_monomorphization_return_integer_type = - invalid monomorphization of `{$name}` intrinsic: expected return type with integer elements, found `{$ret_ty}` with non-integer `{$out_ty}` +codegen_gcc_invalid_monomorphization_simd_shuffle = + invalid monomorphization of `{$name}` intrinsic: simd_shuffle index must be an array of `u32`, got `{$ty}` -codegen_gcc_invalid_monomorphization_mismatched_lengths = - invalid monomorphization of `{$name}` intrinsic: mismatched lengths: mask length `{$m_len}` != other vector length `{$v_len}` +codegen_gcc_invalid_monomorphization_unrecognized = + invalid monomorphization of `{$name}` intrinsic: unrecognized intrinsic `{$name}` codegen_gcc_invalid_monomorphization_unsupported_cast = invalid monomorphization of `{$name}` intrinsic: unsupported cast from `{$in_ty}` with element `{$in_elem}` to `{$ret_ty}` with element `{$out_elem}` +codegen_gcc_invalid_monomorphization_unsupported_element = + invalid monomorphization of `{$name}` intrinsic: unsupported {$name} from `{$in_ty}` with element `{$elem_ty}` to `{$ret_ty}` + codegen_gcc_invalid_monomorphization_unsupported_operation = invalid monomorphization of `{$name}` intrinsic: unsupported operation on `{$in_ty}` with element `{$in_elem}` -codegen_gcc_invalid_minimum_alignment = - invalid minimum global alignment: {$err} +codegen_gcc_lto_not_supported = + LTO is not supported. You may get a linker error. codegen_gcc_tied_target_features = the target features {$features} must all be either enabled or disabled together .help = add the missing features in a `target_feature` attribute + +codegen_gcc_unwinding_inline_asm = + GCC backend does not support unwinding from inline asm diff --git a/compiler/rustc_codegen_gcc/src/common.rs b/compiler/rustc_codegen_gcc/src/common.rs index ac04b61a306..bad87db4732 100644 --- a/compiler/rustc_codegen_gcc/src/common.rs +++ b/compiler/rustc_codegen_gcc/src/common.rs @@ -1,17 +1,15 @@ use gccjit::LValue; use gccjit::{RValue, Type, ToRValue}; -use rustc_codegen_ssa::mir::place::PlaceRef; use rustc_codegen_ssa::traits::{ BaseTypeMethods, ConstMethods, - DerivedTypeMethods, MiscMethods, StaticMethods, }; use rustc_middle::mir::Mutability; -use rustc_middle::ty::layout::{TyAndLayout, LayoutOf}; +use rustc_middle::ty::layout::{LayoutOf}; use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc, Scalar}; -use rustc_target::abi::{self, HasDataLayout, Pointer, Size}; +use rustc_target::abi::{self, HasDataLayout, Pointer}; use crate::consts::const_alloc_to_gcc; use crate::context::CodegenCx; @@ -240,28 +238,26 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> { const_alloc_to_gcc(self, alloc) } - fn from_const_alloc(&self, layout: TyAndLayout<'tcx>, alloc: ConstAllocation<'tcx>, offset: Size) -> PlaceRef<'tcx, RValue<'gcc>> { - assert_eq!(alloc.inner().align, layout.align.abi); - let ty = self.type_ptr_to(layout.gcc_type(self)); - let value = - if layout.size == Size::ZERO { - let value = self.const_usize(alloc.inner().align.bytes()); - self.const_bitcast(value, ty) - } - else { - let init = const_alloc_to_gcc(self, alloc); - let base_addr = self.static_addr_of(init, alloc.inner().align, None); - - let array = self.const_bitcast(base_addr, self.type_i8p()); - let value = self.context.new_array_access(None, array, self.const_usize(offset.bytes())).get_address(None); - self.const_bitcast(value, ty) - }; - PlaceRef::new_sized(value, layout) - } - fn const_ptrcast(&self, val: RValue<'gcc>, ty: Type<'gcc>) -> RValue<'gcc> { self.context.new_cast(None, val, ty) } + + fn const_bitcast(&self, value: RValue<'gcc>, typ: Type<'gcc>) -> RValue<'gcc> { + if value.get_type() == self.bool_type.make_pointer() { + if let Some(pointee) = typ.get_pointee() { + if pointee.dyncast_vector().is_some() { + panic!() + } + } + } + // NOTE: since bitcast makes a value non-constant, don't bitcast if not necessary as some + // SIMD builtins require a constant value. + self.bitcast_if_needed(value, typ) + } + + fn const_ptr_byte_offset(&self, base_addr: Self::Value, offset: abi::Size) -> Self::Value { + self.context.new_array_access(None, base_addr, self.const_usize(offset.bytes())).get_address(None) + } } pub trait SignType<'gcc, 'tcx> { diff --git a/compiler/rustc_codegen_gcc/src/consts.rs b/compiler/rustc_codegen_gcc/src/consts.rs index 792ab8f890d..873f652e6f1 100644 --- a/compiler/rustc_codegen_gcc/src/consts.rs +++ b/compiler/rustc_codegen_gcc/src/consts.rs @@ -1,6 +1,6 @@ #[cfg(feature = "master")] use gccjit::FnAttribute; -use gccjit::{Function, GlobalKind, LValue, RValue, ToRValue, Type}; +use gccjit::{Function, GlobalKind, LValue, RValue, ToRValue}; use rustc_codegen_ssa::traits::{BaseTypeMethods, ConstMethods, DerivedTypeMethods, StaticMethods}; use rustc_middle::span_bug; use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; @@ -16,21 +16,6 @@ use crate::context::CodegenCx; use crate::errors::InvalidMinimumAlignment; use crate::type_of::LayoutGccExt; -impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { - pub fn const_bitcast(&self, value: RValue<'gcc>, typ: Type<'gcc>) -> RValue<'gcc> { - if value.get_type() == self.bool_type.make_pointer() { - if let Some(pointee) = typ.get_pointee() { - if pointee.dyncast_vector().is_some() { - panic!() - } - } - } - // NOTE: since bitcast makes a value non-constant, don't bitcast if not necessary as some - // SIMD builtins require a constant value. - self.bitcast_if_needed(value, typ) - } -} - fn set_global_alignment<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, gv: LValue<'gcc>, mut align: Align) { // The target may require greater alignment for globals than the type does. // Note: GCC and Clang also allow `__attribute__((aligned))` on variables, diff --git a/compiler/rustc_codegen_llvm/messages.ftl b/compiler/rustc_codegen_llvm/messages.ftl index d77634741fb..55622fdb20a 100644 --- a/compiler/rustc_codegen_llvm/messages.ftl +++ b/compiler/rustc_codegen_llvm/messages.ftl @@ -1,90 +1,90 @@ -codegen_llvm_unknown_ctarget_feature = - unknown feature specified for `-Ctarget-feature`: `{$feature}` - .note = it is still passed through to the codegen backend - .possible_feature = you might have meant: `{$rust_feature}` - .consider_filing_feature_request = consider filing a feature request +codegen_llvm_copy_bitcode = failed to copy bitcode to object file: {$err} -codegen_llvm_unknown_ctarget_feature_prefix = - unknown feature specified for `-Ctarget-feature`: `{$feature}` - .note = features must begin with a `+` to enable or `-` to disable it +codegen_llvm_dlltool_fail_import_library = + Dlltool could not create import library: {$stdout} + {$stderr} + +codegen_llvm_dynamic_linking_with_lto = + cannot prefer dynamic linking when performing LTO + .note = only 'staticlib', 'bin', and 'cdylib' outputs are supported with LTO + +codegen_llvm_error_calling_dlltool = + Error calling dlltool '{$dlltool_path}': {$error} codegen_llvm_error_creating_import_library = Error creating import library for {$lib_name}: {$error} -codegen_llvm_symbol_already_defined = - symbol `{$symbol_name}` is already defined +codegen_llvm_error_writing_def_file = + Error writing .DEF file: {$error} + +codegen_llvm_from_llvm_diag = {$message} +codegen_llvm_from_llvm_optimization_diag = {$filename}:{$line}:{$column} {$pass_name} ({$kind}): {$message} codegen_llvm_invalid_minimum_alignment = invalid minimum global alignment: {$err} -codegen_llvm_sanitizer_memtag_requires_mte = - `-Zsanitizer=memtag` requires `-Ctarget-feature=+mte` - -codegen_llvm_error_writing_def_file = - Error writing .DEF file: {$error} +codegen_llvm_load_bitcode = failed to load bitcode of module "{$name}" +codegen_llvm_load_bitcode_with_llvm_err = failed to load bitcode of module "{$name}": {$llvm_err} -codegen_llvm_error_calling_dlltool = - Error calling dlltool '{$dlltool_path}': {$error} +codegen_llvm_lto_bitcode_from_rlib = failed to get bitcode from object file for LTO ({$llvm_err}) -codegen_llvm_dlltool_fail_import_library = - Dlltool could not create import library: {$stdout} - {$stderr} +codegen_llvm_lto_disallowed = lto can only be run for executables, cdylibs and static library outputs -codegen_llvm_target_feature_disable_or_enable = - the target features {$features} must all be either enabled or disabled together +codegen_llvm_lto_dylib = lto cannot be used for `dylib` crate type without `-Zdylib-lto` codegen_llvm_missing_features = add the missing features in a `target_feature` attribute -codegen_llvm_dynamic_linking_with_lto = - cannot prefer dynamic linking when performing LTO - .note = only 'staticlib', 'bin', and 'cdylib' outputs are supported with LTO +codegen_llvm_multiple_source_dicompileunit = multiple source DICompileUnits found +codegen_llvm_multiple_source_dicompileunit_with_llvm_err = multiple source DICompileUnits found: {$llvm_err} + +codegen_llvm_parse_bitcode = failed to parse bitcode for LTO module +codegen_llvm_parse_bitcode_with_llvm_err = failed to parse bitcode for LTO module: {$llvm_err} codegen_llvm_parse_target_machine_config = failed to parse target machine config to target machine: {$error} -codegen_llvm_lto_disallowed = lto can only be run for executables, cdylibs and static library outputs - -codegen_llvm_lto_dylib = lto cannot be used for `dylib` crate type without `-Zdylib-lto` - -codegen_llvm_lto_bitcode_from_rlib = failed to get bitcode from object file for LTO ({$llvm_err}) - -codegen_llvm_write_output = could not write output to {$path} -codegen_llvm_write_output_with_llvm_err = could not write output to {$path}: {$llvm_err} +codegen_llvm_prepare_thin_lto_context = failed to prepare thin LTO context +codegen_llvm_prepare_thin_lto_context_with_llvm_err = failed to prepare thin LTO context: {$llvm_err} -codegen_llvm_target_machine = could not create LLVM TargetMachine for triple: {$triple} -codegen_llvm_target_machine_with_llvm_err = could not create LLVM TargetMachine for triple: {$triple}: {$llvm_err} +codegen_llvm_prepare_thin_lto_module = failed to prepare thin LTO module +codegen_llvm_prepare_thin_lto_module_with_llvm_err = failed to prepare thin LTO module: {$llvm_err} codegen_llvm_run_passes = failed to run LLVM passes codegen_llvm_run_passes_with_llvm_err = failed to run LLVM passes: {$llvm_err} +codegen_llvm_sanitizer_memtag_requires_mte = + `-Zsanitizer=memtag` requires `-Ctarget-feature=+mte` + codegen_llvm_serialize_module = failed to serialize module {$name} codegen_llvm_serialize_module_with_llvm_err = failed to serialize module {$name}: {$llvm_err} -codegen_llvm_write_ir = failed to write LLVM IR to {$path} -codegen_llvm_write_ir_with_llvm_err = failed to write LLVM IR to {$path}: {$llvm_err} - -codegen_llvm_prepare_thin_lto_context = failed to prepare thin LTO context -codegen_llvm_prepare_thin_lto_context_with_llvm_err = failed to prepare thin LTO context: {$llvm_err} +codegen_llvm_symbol_already_defined = + symbol `{$symbol_name}` is already defined -codegen_llvm_load_bitcode = failed to load bitcode of module "{$name}" -codegen_llvm_load_bitcode_with_llvm_err = failed to load bitcode of module "{$name}": {$llvm_err} +codegen_llvm_target_feature_disable_or_enable = + the target features {$features} must all be either enabled or disabled together -codegen_llvm_write_thinlto_key = error while writing ThinLTO key data: {$err} -codegen_llvm_write_thinlto_key_with_llvm_err = error while writing ThinLTO key data: {$err}: {$llvm_err} +codegen_llvm_target_machine = could not create LLVM TargetMachine for triple: {$triple} +codegen_llvm_target_machine_with_llvm_err = could not create LLVM TargetMachine for triple: {$triple}: {$llvm_err} -codegen_llvm_multiple_source_dicompileunit = multiple source DICompileUnits found -codegen_llvm_multiple_source_dicompileunit_with_llvm_err = multiple source DICompileUnits found: {$llvm_err} +codegen_llvm_unknown_ctarget_feature = + unknown feature specified for `-Ctarget-feature`: `{$feature}` + .note = it is still passed through to the codegen backend + .possible_feature = you might have meant: `{$rust_feature}` + .consider_filing_feature_request = consider filing a feature request -codegen_llvm_prepare_thin_lto_module = failed to prepare thin LTO module -codegen_llvm_prepare_thin_lto_module_with_llvm_err = failed to prepare thin LTO module: {$llvm_err} +codegen_llvm_unknown_ctarget_feature_prefix = + unknown feature specified for `-Ctarget-feature`: `{$feature}` + .note = features must begin with a `+` to enable or `-` to disable it -codegen_llvm_parse_bitcode = failed to parse bitcode for LTO module -codegen_llvm_parse_bitcode_with_llvm_err = failed to parse bitcode for LTO module: {$llvm_err} +codegen_llvm_write_bytecode = failed to write bytecode to {$path}: {$err} -codegen_llvm_from_llvm_optimization_diag = {$filename}:{$line}:{$column} {$pass_name} ({$kind}): {$message} -codegen_llvm_from_llvm_diag = {$message} +codegen_llvm_write_ir = failed to write LLVM IR to {$path} +codegen_llvm_write_ir_with_llvm_err = failed to write LLVM IR to {$path}: {$llvm_err} -codegen_llvm_write_bytecode = failed to write bytecode to {$path}: {$err} +codegen_llvm_write_output = could not write output to {$path} +codegen_llvm_write_output_with_llvm_err = could not write output to {$path}: {$llvm_err} -codegen_llvm_copy_bitcode = failed to copy bitcode to object file: {$err} +codegen_llvm_write_thinlto_key = error while writing ThinLTO key data: {$err} +codegen_llvm_write_thinlto_key_with_llvm_err = error while writing ThinLTO key data: {$err}: {$llvm_err} diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index 651d644ebb6..6d00464e0a0 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -88,6 +88,9 @@ pub fn sanitize_attrs<'ll>( attrs.push(llvm::AttributeKind::SanitizeMemTag.create_attr(cx.llcx)); } + if enabled.contains(SanitizerSet::SAFESTACK) { + attrs.push(llvm::AttributeKind::SanitizeSafeStack.create_attr(cx.llcx)); + } attrs } diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index 9127fba388b..a3910fef954 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -8,16 +8,15 @@ use crate::type_of::LayoutLlvmExt; use crate::value::Value; use rustc_ast::Mutability; -use rustc_codegen_ssa::mir::place::PlaceRef; use rustc_codegen_ssa::traits::*; use rustc_data_structures::stable_hasher::{Hash128, HashStable, StableHasher}; use rustc_hir::def_id::DefId; use rustc_middle::bug; use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc, Scalar}; -use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; +use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::TyCtxt; use rustc_session::cstore::{DllCallingConvention, DllImport, PeImportNameType}; -use rustc_target::abi::{self, AddressSpace, HasDataLayout, Pointer, Size}; +use rustc_target::abi::{self, AddressSpace, HasDataLayout, Pointer}; use rustc_target::spec::Target; use libc::{c_char, c_uint}; @@ -307,38 +306,24 @@ impl<'ll, 'tcx> ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> { const_alloc_to_llvm(self, alloc) } - fn from_const_alloc( - &self, - layout: TyAndLayout<'tcx>, - alloc: ConstAllocation<'tcx>, - offset: Size, - ) -> PlaceRef<'tcx, &'ll Value> { - let alloc_align = alloc.inner().align; - assert_eq!(alloc_align, layout.align.abi); - let llty = self.type_ptr_to(layout.llvm_type(self)); - let llval = if layout.size == Size::ZERO { - let llval = self.const_usize(alloc_align.bytes()); - unsafe { llvm::LLVMConstIntToPtr(llval, llty) } - } else { - let init = const_alloc_to_llvm(self, alloc); - let base_addr = self.static_addr_of(init, alloc_align, None); - - let llval = unsafe { - llvm::LLVMRustConstInBoundsGEP2( - self.type_i8(), - self.const_bitcast(base_addr, self.type_i8p()), - &self.const_usize(offset.bytes()), - 1, - ) - }; - self.const_bitcast(llval, llty) - }; - PlaceRef::new_sized(llval, layout) - } - fn const_ptrcast(&self, val: &'ll Value, ty: &'ll Type) -> &'ll Value { consts::ptrcast(val, ty) } + + fn const_bitcast(&self, val: &'ll Value, ty: &'ll Type) -> &'ll Value { + self.const_bitcast(val, ty) + } + + fn const_ptr_byte_offset(&self, base_addr: Self::Value, offset: abi::Size) -> Self::Value { + unsafe { + llvm::LLVMRustConstInBoundsGEP2( + self.type_i8(), + self.const_bitcast(base_addr, self.type_i8p()), + &self.const_usize(offset.bytes()), + 1, + ) + } + } } /// Get the [LLVM type][Type] of a [`Value`]. 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 3fff112a020..64961baf272 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs @@ -93,7 +93,7 @@ fn make_mir_scope<'ll, 'tcx>( let callee = cx.tcx.subst_and_normalize_erasing_regions( instance.substs, ty::ParamEnv::reveal_all(), - ty::EarlyBinder(callee), + ty::EarlyBinder::bind(callee), ); let callee_fn_abi = cx.fn_abi_of_instance(callee, ty::List::empty()); cx.dbg_scope_fn(callee, callee_fn_abi, None) diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index de93a64c0d6..6ef3418cc5f 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -196,6 +196,7 @@ pub enum AttributeKind { AllocSize = 37, AllocatedPointer = 38, AllocAlign = 39, + SanitizeSafeStack = 40, } /// LLVMIntPredicate diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl index 375fdec1007..9aa2b2e2b2e 100644 --- a/compiler/rustc_codegen_ssa/messages.ftl +++ b/compiler/rustc_codegen_ssa/messages.ftl @@ -1,306 +1,306 @@ -codegen_ssa_lib_def_write_failure = failed to write lib.def file: {$error} - -codegen_ssa_version_script_write_failure = failed to write version script: {$error} +codegen_ssa_L4Bender_exporting_symbols_unimplemented = exporting symbols not implemented yet for L4Bender -codegen_ssa_symbol_file_write_failure = failed to write symbols file: {$error} +codegen_ssa_add_native_library = failed to add native library {$library_path}: {$error} -codegen_ssa_ld64_unimplemented_modifier = `as-needed` modifier not implemented yet for ld64 +codegen_ssa_apple_sdk_error_sdk_path = failed to get {$sdk_name} SDK path: {$error} -codegen_ssa_linker_unsupported_modifier = `as-needed` modifier not supported for current linker +codegen_ssa_archive_build_failure = + failed to build archive: {$error} -codegen_ssa_L4Bender_exporting_symbols_unimplemented = exporting symbols not implemented yet for L4Bender +codegen_ssa_atomic_compare_exchange = Atomic compare-exchange intrinsic missing failure memory ordering -codegen_ssa_no_natvis_directory = error enumerating natvis directory: {$error} +codegen_ssa_check_installed_visual_studio = please ensure that Visual Studio 2017 or later, or Build Tools for Visual Studio were installed with the Visual C++ option. codegen_ssa_copy_path = could not copy {$from} to {$to}: {$error} codegen_ssa_copy_path_buf = unable to copy {$source_file} to {$output_path}: {$error} +codegen_ssa_create_temp_dir = couldn't create a temp dir: {$error} + +codegen_ssa_erroneous_constant = erroneous constant encountered + +codegen_ssa_expected_used_symbol = expected `used`, `used(compiler)` or `used(linker)` + +codegen_ssa_extern_funcs_not_found = some `extern` functions couldn't be found; some native libraries may need to be installed or have their path specified + +codegen_ssa_extract_bundled_libs_archive_member = failed to get data from archive member '{$rlib}': {$error} +codegen_ssa_extract_bundled_libs_convert_name = failed to convert name '{$rlib}': {$error} +codegen_ssa_extract_bundled_libs_mmap_file = failed to mmap file '{$rlib}': {$error} +codegen_ssa_extract_bundled_libs_open_file = failed to open file '{$rlib}': {$error} +codegen_ssa_extract_bundled_libs_parse_archive = failed to parse archive '{$rlib}': {$error} +codegen_ssa_extract_bundled_libs_read_entry = failed to read entry '{$rlib}': {$error} +codegen_ssa_extract_bundled_libs_write_file = failed to write file '{$rlib}': {$error} + +codegen_ssa_failed_to_write = failed to write {$path}: {$error} + codegen_ssa_ignoring_emit_path = ignoring emit path because multiple .{$extension} files were produced codegen_ssa_ignoring_output = ignoring -o because multiple .{$extension} files were produced -codegen_ssa_create_temp_dir = couldn't create a temp dir: {$error} +codegen_ssa_illegal_link_ordinal_format = illegal ordinal format in `link_ordinal` + .note = an unsuffixed integer value, e.g., `1`, is expected codegen_ssa_incompatible_linking_modifiers = link modifiers combination `+bundle,+whole-archive` is unstable when generating rlibs -codegen_ssa_add_native_library = failed to add native library {$library_path}: {$error} - -codegen_ssa_multiple_external_func_decl = multiple declarations of external function `{$function}` from library `{$library_name}` have different calling conventions +codegen_ssa_insufficient_vs_code_product = VS Code is a different product, and is not sufficient. -codegen_ssa_rlib_missing_format = could not find formats for rlibs +codegen_ssa_invalid_link_ordinal_nargs = incorrect number of arguments to `#[link_ordinal]` + .note = the attribute requires exactly one argument -codegen_ssa_rlib_only_rmeta_found = could not find rlib for: `{$crate_name}`, found rmeta (metadata) file +codegen_ssa_invalid_monomorphization_basic_float_type = invalid monomorphization of `{$name}` intrinsic: expected basic float type, found `{$ty}` -codegen_ssa_rlib_not_found = could not find rlib for: `{$crate_name}` +codegen_ssa_invalid_monomorphization_basic_integer_type = invalid monomorphization of `{$name}` intrinsic: expected basic integer type, found `{$ty}` -codegen_ssa_rlib_incompatible_dependency_formats = `{$ty1}` and `{$ty2}` do not have equivalent dependency formats (`{$list1}` vs `{$list2}`) +codegen_ssa_invalid_monomorphization_cannot_return = invalid monomorphization of `{$name}` intrinsic: cannot return `{$ret_ty}`, expected `u{$expected_int_bits}` or `[u8; {$expected_bytes}]` -codegen_ssa_linking_failed = linking with `{$linker_path}` failed: {$exit_status} +codegen_ssa_invalid_monomorphization_cast_fat_pointer = invalid monomorphization of `{$name}` intrinsic: cannot cast fat pointer `{$ty}` -codegen_ssa_extern_funcs_not_found = some `extern` functions couldn't be found; some native libraries may need to be installed or have their path specified +codegen_ssa_invalid_monomorphization_expected_element_type = invalid monomorphization of `{$name}` intrinsic: expected element type `{$expected_element}` of second argument `{$second_arg}` to be a pointer to the element type `{$in_elem}` of the first argument `{$in_ty}`, found `{$expected_element}` != `{$mutability} {$in_elem}` -codegen_ssa_specify_libraries_to_link = use the `-l` flag to specify native libraries to link +codegen_ssa_invalid_monomorphization_expected_pointer = invalid monomorphization of `{$name}` intrinsic: expected pointer, got `{$ty}` -codegen_ssa_use_cargo_directive = use the `cargo:rustc-link-lib` directive to specify the native libraries to link with Cargo (see https://doc.rust-lang.org/cargo/reference/build-scripts.html#cargorustc-link-libkindname) +codegen_ssa_invalid_monomorphization_expected_return_type = invalid monomorphization of `{$name}` intrinsic: expected return type `{$in_ty}`, found `{$ret_ty}` -codegen_ssa_thorin_read_input_failure = failed to read input file +codegen_ssa_invalid_monomorphization_expected_usize = invalid monomorphization of `{$name}` intrinsic: expected `usize`, got `{$ty}` -codegen_ssa_thorin_parse_input_file_kind = failed to parse input file kind +codegen_ssa_invalid_monomorphization_expected_vector_element_type = invalid monomorphization of `{$name}` intrinsic: expected element type `{$expected_element}` of vector type `{$vector_type}` to be a signed or unsigned integer type -codegen_ssa_thorin_parse_input_object_file = failed to parse input object file +codegen_ssa_invalid_monomorphization_float_to_int_unchecked = invalid monomorphization of `float_to_int_unchecked` intrinsic: expected basic float type, found `{$ty}` -codegen_ssa_thorin_parse_input_archive_file = failed to parse input archive file +codegen_ssa_invalid_monomorphization_floating_point_type = invalid monomorphization of `{$name}` intrinsic: `{$in_ty}` is not a floating-point type -codegen_ssa_thorin_parse_archive_member = failed to parse archive member +codegen_ssa_invalid_monomorphization_floating_point_vector = invalid monomorphization of `{$name}` intrinsic: unsupported element type `{$f_ty}` of floating-point vector `{$in_ty}` -codegen_ssa_thorin_invalid_input_kind = input is not an archive or elf object +codegen_ssa_invalid_monomorphization_inserted_type = invalid monomorphization of `{$name}` intrinsic: expected inserted type `{$in_elem}` (element of input `{$in_ty}`), found `{$out_ty}` -codegen_ssa_thorin_decompress_data = failed to decompress compressed section +codegen_ssa_invalid_monomorphization_invalid_bitmask = invalid monomorphization of `{$name}` intrinsic: invalid bitmask `{$mask_ty}`, expected `u{$expected_int_bits}` or `[u8; {$expected_bytes}]` -codegen_ssa_thorin_section_without_name = section without name at offset {$offset} +codegen_ssa_invalid_monomorphization_mask_type = invalid monomorphization of `{$name}` intrinsic: mask element type is `{$ty}`, expected `i_` -codegen_ssa_thorin_relocation_with_invalid_symbol = relocation with invalid symbol for section `{$section}` at offset {$offset} +codegen_ssa_invalid_monomorphization_mismatched_lengths = invalid monomorphization of `{$name}` intrinsic: mismatched lengths: mask length `{$m_len}` != other vector length `{$v_len}` -codegen_ssa_thorin_multiple_relocations = multiple relocations for section `{$section}` at offset {$offset} +codegen_ssa_invalid_monomorphization_return_element = invalid monomorphization of `{$name}` intrinsic: expected return element type `{$in_elem}` (element of input `{$in_ty}`), found `{$ret_ty}` with element type `{$out_ty}` -codegen_ssa_thorin_unsupported_relocation = unsupported relocation for section {$section} at offset {$offset} +codegen_ssa_invalid_monomorphization_return_integer_type = invalid monomorphization of `{$name}` intrinsic: expected return type with integer elements, found `{$ret_ty}` with non-integer `{$out_ty}` -codegen_ssa_thorin_missing_dwo_name = missing path attribute to DWARF object ({$id}) +codegen_ssa_invalid_monomorphization_return_length = invalid monomorphization of `{$name}` intrinsic: expected return type of length {$in_len}, found `{$ret_ty}` with length {$out_len} -codegen_ssa_thorin_no_compilation_units = input object has no compilation units +codegen_ssa_invalid_monomorphization_return_length_input_type = invalid monomorphization of `{$name}` intrinsic: expected return type with length {$in_len} (same as input type `{$in_ty}`), found `{$ret_ty}` with length {$out_len} -codegen_ssa_thorin_no_die = no top-level debugging information entry in compilation/type unit +codegen_ssa_invalid_monomorphization_return_type = invalid monomorphization of `{$name}` intrinsic: expected return type `{$in_elem}` (element of input `{$in_ty}`), found `{$ret_ty}` -codegen_ssa_thorin_top_level_die_not_unit = top-level debugging information entry is not a compilation/type unit +codegen_ssa_invalid_monomorphization_second_argument_length = invalid monomorphization of `{$name}` intrinsic: expected second argument with length {$in_len} (same as input type `{$in_ty}`), found `{$arg_ty}` with length {$out_len} -codegen_ssa_thorin_missing_required_section = input object missing required section `{$section}` +codegen_ssa_invalid_monomorphization_shuffle_index_not_constant = invalid monomorphization of `{$name}` intrinsic: shuffle index #{$arg_idx} is not a constant -codegen_ssa_thorin_parse_unit_abbreviations = failed to parse unit abbreviations +codegen_ssa_invalid_monomorphization_shuffle_index_out_of_bounds = invalid monomorphization of `{$name}` intrinsic: shuffle index #{$arg_idx} is out of bounds (limit {$total_len}) -codegen_ssa_thorin_parse_unit_attribute = failed to parse unit attribute +codegen_ssa_invalid_monomorphization_simd_argument = invalid monomorphization of `{$name}` intrinsic: expected SIMD argument type, found non-SIMD `{$ty}` -codegen_ssa_thorin_parse_unit_header = failed to parse unit header +codegen_ssa_invalid_monomorphization_simd_first = invalid monomorphization of `{$name}` intrinsic: expected SIMD first type, found non-SIMD `{$ty}` -codegen_ssa_thorin_parse_unit = failed to parse unit +codegen_ssa_invalid_monomorphization_simd_input = invalid monomorphization of `{$name}` intrinsic: expected SIMD input type, found non-SIMD `{$ty}` -codegen_ssa_thorin_incompatible_index_version = incompatible `{$section}` index version: found version {$actual}, expected version {$format} +codegen_ssa_invalid_monomorphization_simd_return = invalid monomorphization of `{$name}` intrinsic: expected SIMD return type, found non-SIMD `{$ty}` -codegen_ssa_thorin_offset_at_index = read offset at index {$index} of `.debug_str_offsets.dwo` section +codegen_ssa_invalid_monomorphization_simd_second = invalid monomorphization of `{$name}` intrinsic: expected SIMD second type, found non-SIMD `{$ty}` -codegen_ssa_thorin_str_at_offset = read string at offset {$offset} of `.debug_str.dwo` section +codegen_ssa_invalid_monomorphization_simd_shuffle = invalid monomorphization of `{$name}` intrinsic: simd_shuffle index must be an array of `u32`, got `{$ty}` -codegen_ssa_thorin_parse_index = failed to parse `{$section}` index section +codegen_ssa_invalid_monomorphization_simd_third = invalid monomorphization of `{$name}` intrinsic: expected SIMD third type, found non-SIMD `{$ty}` -codegen_ssa_thorin_unit_not_in_index = unit {$unit} from input package is not in its index +codegen_ssa_invalid_monomorphization_third_arg_element_type = invalid monomorphization of `{$name}` intrinsic: expected element type `{$expected_element}` of third argument `{$third_arg}` to be a signed integer type -codegen_ssa_thorin_row_not_in_index = row {$row} found in index's hash table not present in index +codegen_ssa_invalid_monomorphization_third_argument_length = invalid monomorphization of `{$name}` intrinsic: expected third argument with length {$in_len} (same as input type `{$in_ty}`), found `{$arg_ty}` with length {$out_len} -codegen_ssa_thorin_section_not_in_row = section not found in unit's row in index +codegen_ssa_invalid_monomorphization_unrecognized_intrinsic = invalid monomorphization of `{$name}` intrinsic: unrecognized intrinsic `{$name}` -codegen_ssa_thorin_empty_unit = unit {$unit} in input DWARF object with no data +codegen_ssa_invalid_monomorphization_unsupported_cast = invalid monomorphization of `{$name}` intrinsic: unsupported cast from `{$in_ty}` with element `{$in_elem}` to `{$ret_ty}` with element `{$out_elem}` -codegen_ssa_thorin_multiple_debug_info_section = multiple `.debug_info.dwo` sections +codegen_ssa_invalid_monomorphization_unsupported_operation = invalid monomorphization of `{$name}` intrinsic: unsupported operation on `{$in_ty}` with element `{$in_elem}` -codegen_ssa_thorin_multiple_debug_types_section = multiple `.debug_types.dwo` sections in a package +codegen_ssa_invalid_monomorphization_unsupported_symbol = invalid monomorphization of `{$name}` intrinsic: unsupported {$symbol} from `{$in_ty}` with element `{$in_elem}` to `{$ret_ty}` -codegen_ssa_thorin_not_split_unit = regular compilation unit in object (missing dwo identifier) +codegen_ssa_invalid_monomorphization_unsupported_symbol_of_size = invalid monomorphization of `{$name}` intrinsic: unsupported {$symbol} from `{$in_ty}` with element `{$in_elem}` of size `{$size}` to `{$ret_ty}` -codegen_ssa_thorin_duplicate_unit = duplicate split compilation unit ({$unit}) +codegen_ssa_invalid_monomorphization_vector_argument = invalid monomorphization of `{$name}` intrinsic: vector argument `{$in_ty}`'s element type `{$in_elem}`, expected integer element type -codegen_ssa_thorin_missing_referenced_unit = unit {$unit} referenced by executable was not found +codegen_ssa_invalid_no_sanitize = invalid argument for `no_sanitize` + .note = expected one of: `address`, `cfi`, `hwaddress`, `kcfi`, `memory`, `memtag`, `shadow-call-stack`, or `thread` -codegen_ssa_thorin_not_output_object_created = no output object was created from inputs +codegen_ssa_invalid_windows_subsystem = invalid windows subsystem `{$subsystem}`, only `windows` and `console` are allowed -codegen_ssa_thorin_mixed_input_encodings = input objects haved mixed encodings +codegen_ssa_ld64_unimplemented_modifier = `as-needed` modifier not implemented yet for ld64 -codegen_ssa_thorin_io = {$error} -codegen_ssa_thorin_object_read = {$error} -codegen_ssa_thorin_object_write = {$error} -codegen_ssa_thorin_gimli_read = {$error} -codegen_ssa_thorin_gimli_write = {$error} +codegen_ssa_lib_def_write_failure = failed to write lib.def file: {$error} codegen_ssa_link_exe_unexpected_error = `link.exe` returned an unexpected error -codegen_ssa_repair_vs_build_tools = the Visual Studio build tools may need to be repaired using the Visual Studio installer - -codegen_ssa_missing_cpp_build_tool_component = or a necessary component may be missing from the "C++ build tools" workload +codegen_ssa_link_script_unavailable = can only use link script when linking with GNU-like linker -codegen_ssa_select_cpp_build_tool_workload = in the Visual Studio installer, ensure the "C++ build tools" workload is selected +codegen_ssa_link_script_write_failure = failed to write link script to {$path}: {$error} -codegen_ssa_visual_studio_not_installed = you may need to install Visual Studio build tools with the "C++ build tools" workload +codegen_ssa_linker_file_stem = couldn't extract file stem from specified linker codegen_ssa_linker_not_found = linker `{$linker_path}` not found .note = {$error} -codegen_ssa_unable_to_exe_linker = could not exec the linker `{$linker_path}` - .note = {$error} - .command_note = {$command_formatted} +codegen_ssa_linker_unsupported_modifier = `as-needed` modifier not supported for current linker -codegen_ssa_msvc_missing_linker = the msvc targets depend on the msvc linker but `link.exe` was not found +codegen_ssa_linking_failed = linking with `{$linker_path}` failed: {$exit_status} -codegen_ssa_check_installed_visual_studio = please ensure that Visual Studio 2017 or later, or Build Tools for Visual Studio were installed with the Visual C++ option. +codegen_ssa_metadata_object_file_write = error writing metadata object file: {$error} -codegen_ssa_insufficient_vs_code_product = VS Code is a different product, and is not sufficient. +codegen_ssa_missing_cpp_build_tool_component = or a necessary component may be missing from the "C++ build tools" workload -codegen_ssa_processing_dymutil_failed = processing debug info with `dsymutil` failed: {$status} - .note = {$output} +codegen_ssa_missing_memory_ordering = Atomic intrinsic missing memory ordering -codegen_ssa_unable_to_run_dsymutil = unable to run `dsymutil`: {$error} +codegen_ssa_msvc_missing_linker = the msvc targets depend on the msvc linker but `link.exe` was not found -codegen_ssa_stripping_debug_info_failed = stripping debug info with `{$util}` failed: {$status} - .note = {$output} +codegen_ssa_multiple_external_func_decl = multiple declarations of external function `{$function}` from library `{$library_name}` have different calling conventions -codegen_ssa_unable_to_run = unable to run `{$util}`: {$error} +codegen_ssa_multiple_main_functions = entry symbol `main` declared multiple times + .help = did you use `#[no_mangle]` on `fn main`? Use `#[start]` instead -codegen_ssa_linker_file_stem = couldn't extract file stem from specified linker +codegen_ssa_no_natvis_directory = error enumerating natvis directory: {$error} -codegen_ssa_static_library_native_artifacts = Link against the following native artifacts when linking against this static library. The order and any duplication can be significant on some platforms. +codegen_ssa_option_gcc_only = option `-Z gcc-ld` is used even though linker flavor is not gcc -codegen_ssa_link_script_unavailable = can only use link script when linking with GNU-like linker +codegen_ssa_polymorphic_constant_too_generic = codegen encountered polymorphic constant: TooGeneric -codegen_ssa_link_script_write_failure = failed to write link script to {$path}: {$error} +codegen_ssa_processing_dymutil_failed = processing debug info with `dsymutil` failed: {$status} + .note = {$output} -codegen_ssa_failed_to_write = failed to write {$path}: {$error} +codegen_ssa_read_file = failed to read file: {$message} -codegen_ssa_unable_to_write_debugger_visualizer = Unable to write debugger visualizer file `{$path}`: {$error} +codegen_ssa_repair_vs_build_tools = the Visual Studio build tools may need to be repaired using the Visual Studio installer codegen_ssa_rlib_archive_build_failure = failed to build archive from rlib: {$error} -codegen_ssa_option_gcc_only = option `-Z gcc-ld` is used even though linker flavor is not gcc - -codegen_ssa_extract_bundled_libs_open_file = failed to open file '{$rlib}': {$error} -codegen_ssa_extract_bundled_libs_mmap_file = failed to mmap file '{$rlib}': {$error} -codegen_ssa_extract_bundled_libs_parse_archive = failed to parse archive '{$rlib}': {$error} -codegen_ssa_extract_bundled_libs_read_entry = failed to read entry '{$rlib}': {$error} -codegen_ssa_extract_bundled_libs_archive_member = failed to get data from archive member '{$rlib}': {$error} -codegen_ssa_extract_bundled_libs_convert_name = failed to convert name '{$rlib}': {$error} -codegen_ssa_extract_bundled_libs_write_file = failed to write file '{$rlib}': {$error} - -codegen_ssa_unsupported_arch = unsupported arch `{$arch}` for os `{$os}` - -codegen_ssa_apple_sdk_error_sdk_path = failed to get {$sdk_name} SDK path: {$error} +codegen_ssa_rlib_incompatible_dependency_formats = `{$ty1}` and `{$ty2}` do not have equivalent dependency formats (`{$list1}` vs `{$list2}`) -codegen_ssa_read_file = failed to read file: {$message} +codegen_ssa_rlib_missing_format = could not find formats for rlibs -codegen_ssa_unsupported_link_self_contained = option `-C link-self-contained` is not supported on this target +codegen_ssa_rlib_not_found = could not find rlib for: `{$crate_name}` -codegen_ssa_archive_build_failure = - failed to build archive: {$error} +codegen_ssa_rlib_only_rmeta_found = could not find rlib for: `{$crate_name}`, found rmeta (metadata) file -codegen_ssa_unknown_archive_kind = - Don't know how to build archive of type: {$kind} +codegen_ssa_select_cpp_build_tool_workload = in the Visual Studio installer, ensure the "C++ build tools" workload is selected -codegen_ssa_expected_used_symbol = expected `used`, `used(compiler)` or `used(linker)` +codegen_ssa_shuffle_indices_evaluation = could not evaluate shuffle_indices at compile time -codegen_ssa_multiple_main_functions = entry symbol `main` declared multiple times - .help = did you use `#[no_mangle]` on `fn main`? Use `#[start]` instead +codegen_ssa_specify_libraries_to_link = use the `-l` flag to specify native libraries to link -codegen_ssa_metadata_object_file_write = error writing metadata object file: {$error} +codegen_ssa_static_library_native_artifacts = Link against the following native artifacts when linking against this static library. The order and any duplication can be significant on some platforms. -codegen_ssa_invalid_windows_subsystem = invalid windows subsystem `{$subsystem}`, only `windows` and `console` are allowed +codegen_ssa_stripping_debug_info_failed = stripping debug info with `{$util}` failed: {$status} + .note = {$output} -codegen_ssa_erroneous_constant = erroneous constant encountered +codegen_ssa_symbol_file_write_failure = failed to write symbols file: {$error} -codegen_ssa_shuffle_indices_evaluation = could not evaluate shuffle_indices at compile time +codegen_ssa_target_feature_safe_trait = `#[target_feature(..)]` cannot be applied to safe trait method + .label = cannot be applied to safe trait method + .label_def = not an `unsafe` function -codegen_ssa_missing_memory_ordering = Atomic intrinsic missing memory ordering +codegen_ssa_thorin_decompress_data = failed to decompress compressed section -codegen_ssa_unknown_atomic_ordering = unknown ordering in atomic intrinsic +codegen_ssa_thorin_duplicate_unit = duplicate split compilation unit ({$unit}) -codegen_ssa_atomic_compare_exchange = Atomic compare-exchange intrinsic missing failure memory ordering +codegen_ssa_thorin_empty_unit = unit {$unit} in input DWARF object with no data -codegen_ssa_unknown_atomic_operation = unknown atomic operation +codegen_ssa_thorin_gimli_read = {$error} +codegen_ssa_thorin_gimli_write = {$error} -codegen_ssa_invalid_monomorphization_basic_integer_type = invalid monomorphization of `{$name}` intrinsic: expected basic integer type, found `{$ty}` +codegen_ssa_thorin_incompatible_index_version = incompatible `{$section}` index version: found version {$actual}, expected version {$format} -codegen_ssa_invalid_monomorphization_basic_float_type = invalid monomorphization of `{$name}` intrinsic: expected basic float type, found `{$ty}` +codegen_ssa_thorin_invalid_input_kind = input is not an archive or elf object -codegen_ssa_invalid_monomorphization_float_to_int_unchecked = invalid monomorphization of `float_to_int_unchecked` intrinsic: expected basic float type, found `{$ty}` +codegen_ssa_thorin_io = {$error} +codegen_ssa_thorin_missing_dwo_name = missing path attribute to DWARF object ({$id}) -codegen_ssa_invalid_monomorphization_floating_point_vector = invalid monomorphization of `{$name}` intrinsic: unsupported element type `{$f_ty}` of floating-point vector `{$in_ty}` +codegen_ssa_thorin_missing_referenced_unit = unit {$unit} referenced by executable was not found -codegen_ssa_invalid_monomorphization_floating_point_type = invalid monomorphization of `{$name}` intrinsic: `{$in_ty}` is not a floating-point type +codegen_ssa_thorin_missing_required_section = input object missing required section `{$section}` -codegen_ssa_invalid_monomorphization_unrecognized_intrinsic = invalid monomorphization of `{$name}` intrinsic: unrecognized intrinsic `{$name}` +codegen_ssa_thorin_mixed_input_encodings = input objects haved mixed encodings -codegen_ssa_invalid_monomorphization_simd_argument = invalid monomorphization of `{$name}` intrinsic: expected SIMD argument type, found non-SIMD `{$ty}` +codegen_ssa_thorin_multiple_debug_info_section = multiple `.debug_info.dwo` sections -codegen_ssa_invalid_monomorphization_simd_input = invalid monomorphization of `{$name}` intrinsic: expected SIMD input type, found non-SIMD `{$ty}` +codegen_ssa_thorin_multiple_debug_types_section = multiple `.debug_types.dwo` sections in a package -codegen_ssa_invalid_monomorphization_simd_first = invalid monomorphization of `{$name}` intrinsic: expected SIMD first type, found non-SIMD `{$ty}` +codegen_ssa_thorin_multiple_relocations = multiple relocations for section `{$section}` at offset {$offset} -codegen_ssa_invalid_monomorphization_simd_second = invalid monomorphization of `{$name}` intrinsic: expected SIMD second type, found non-SIMD `{$ty}` +codegen_ssa_thorin_no_compilation_units = input object has no compilation units -codegen_ssa_invalid_monomorphization_simd_third = invalid monomorphization of `{$name}` intrinsic: expected SIMD third type, found non-SIMD `{$ty}` +codegen_ssa_thorin_no_die = no top-level debugging information entry in compilation/type unit -codegen_ssa_invalid_monomorphization_simd_return = invalid monomorphization of `{$name}` intrinsic: expected SIMD return type, found non-SIMD `{$ty}` +codegen_ssa_thorin_not_output_object_created = no output object was created from inputs -codegen_ssa_invalid_monomorphization_invalid_bitmask = invalid monomorphization of `{$name}` intrinsic: invalid bitmask `{$mask_ty}`, expected `u{$expected_int_bits}` or `[u8; {$expected_bytes}]` +codegen_ssa_thorin_not_split_unit = regular compilation unit in object (missing dwo identifier) -codegen_ssa_polymorphic_constant_too_generic = codegen encountered polymorphic constant: TooGeneric +codegen_ssa_thorin_object_read = {$error} +codegen_ssa_thorin_object_write = {$error} +codegen_ssa_thorin_offset_at_index = read offset at index {$index} of `.debug_str_offsets.dwo` section -codegen_ssa_invalid_monomorphization_return_length_input_type = invalid monomorphization of `{$name}` intrinsic: expected return type with length {$in_len} (same as input type `{$in_ty}`), found `{$ret_ty}` with length {$out_len} +codegen_ssa_thorin_parse_archive_member = failed to parse archive member -codegen_ssa_invalid_monomorphization_second_argument_length = invalid monomorphization of `{$name}` intrinsic: expected second argument with length {$in_len} (same as input type `{$in_ty}`), found `{$arg_ty}` with length {$out_len} +codegen_ssa_thorin_parse_index = failed to parse `{$section}` index section -codegen_ssa_invalid_monomorphization_third_argument_length = invalid monomorphization of `{$name}` intrinsic: expected third argument with length {$in_len} (same as input type `{$in_ty}`), found `{$arg_ty}` with length {$out_len} +codegen_ssa_thorin_parse_input_archive_file = failed to parse input archive file -codegen_ssa_invalid_monomorphization_return_integer_type = invalid monomorphization of `{$name}` intrinsic: expected return type with integer elements, found `{$ret_ty}` with non-integer `{$out_ty}` +codegen_ssa_thorin_parse_input_file_kind = failed to parse input file kind -codegen_ssa_invalid_monomorphization_simd_shuffle = invalid monomorphization of `{$name}` intrinsic: simd_shuffle index must be an array of `u32`, got `{$ty}` +codegen_ssa_thorin_parse_input_object_file = failed to parse input object file -codegen_ssa_invalid_monomorphization_return_length = invalid monomorphization of `{$name}` intrinsic: expected return type of length {$in_len}, found `{$ret_ty}` with length {$out_len} +codegen_ssa_thorin_parse_unit = failed to parse unit -codegen_ssa_invalid_monomorphization_return_element = invalid monomorphization of `{$name}` intrinsic: expected return element type `{$in_elem}` (element of input `{$in_ty}`), found `{$ret_ty}` with element type `{$out_ty}` +codegen_ssa_thorin_parse_unit_abbreviations = failed to parse unit abbreviations -codegen_ssa_invalid_monomorphization_shuffle_index_not_constant = invalid monomorphization of `{$name}` intrinsic: shuffle index #{$arg_idx} is not a constant +codegen_ssa_thorin_parse_unit_attribute = failed to parse unit attribute -codegen_ssa_invalid_monomorphization_shuffle_index_out_of_bounds = invalid monomorphization of `{$name}` intrinsic: shuffle index #{$arg_idx} is out of bounds (limit {$total_len}) +codegen_ssa_thorin_parse_unit_header = failed to parse unit header -codegen_ssa_invalid_monomorphization_inserted_type = invalid monomorphization of `{$name}` intrinsic: expected inserted type `{$in_elem}` (element of input `{$in_ty}`), found `{$out_ty}` +codegen_ssa_thorin_read_input_failure = failed to read input file -codegen_ssa_invalid_monomorphization_return_type = invalid monomorphization of `{$name}` intrinsic: expected return type `{$in_elem}` (element of input `{$in_ty}`), found `{$ret_ty}` +codegen_ssa_thorin_relocation_with_invalid_symbol = relocation with invalid symbol for section `{$section}` at offset {$offset} -codegen_ssa_invalid_monomorphization_expected_return_type = invalid monomorphization of `{$name}` intrinsic: expected return type `{$in_ty}`, found `{$ret_ty}` +codegen_ssa_thorin_row_not_in_index = row {$row} found in index's hash table not present in index -codegen_ssa_invalid_monomorphization_mismatched_lengths = invalid monomorphization of `{$name}` intrinsic: mismatched lengths: mask length `{$m_len}` != other vector length `{$v_len}` +codegen_ssa_thorin_section_not_in_row = section not found in unit's row in index -codegen_ssa_invalid_monomorphization_mask_type = invalid monomorphization of `{$name}` intrinsic: mask element type is `{$ty}`, expected `i_` +codegen_ssa_thorin_section_without_name = section without name at offset {$offset} -codegen_ssa_invalid_monomorphization_vector_argument = invalid monomorphization of `{$name}` intrinsic: vector argument `{$in_ty}`'s element type `{$in_elem}`, expected integer element type +codegen_ssa_thorin_str_at_offset = read string at offset {$offset} of `.debug_str.dwo` section -codegen_ssa_invalid_monomorphization_cannot_return = invalid monomorphization of `{$name}` intrinsic: cannot return `{$ret_ty}`, expected `u{$expected_int_bits}` or `[u8; {$expected_bytes}]` +codegen_ssa_thorin_top_level_die_not_unit = top-level debugging information entry is not a compilation/type unit -codegen_ssa_invalid_monomorphization_expected_element_type = invalid monomorphization of `{$name}` intrinsic: expected element type `{$expected_element}` of second argument `{$second_arg}` to be a pointer to the element type `{$in_elem}` of the first argument `{$in_ty}`, found `{$expected_element}` != `{$mutability} {$in_elem}` +codegen_ssa_thorin_unit_not_in_index = unit {$unit} from input package is not in its index -codegen_ssa_invalid_monomorphization_third_arg_element_type = invalid monomorphization of `{$name}` intrinsic: expected element type `{$expected_element}` of third argument `{$third_arg}` to be a signed integer type +codegen_ssa_thorin_unsupported_relocation = unsupported relocation for section {$section} at offset {$offset} -codegen_ssa_invalid_monomorphization_unsupported_symbol_of_size = invalid monomorphization of `{$name}` intrinsic: unsupported {$symbol} from `{$in_ty}` with element `{$in_elem}` of size `{$size}` to `{$ret_ty}` +codegen_ssa_unable_to_exe_linker = could not exec the linker `{$linker_path}` + .note = {$error} + .command_note = {$command_formatted} -codegen_ssa_invalid_monomorphization_unsupported_symbol = invalid monomorphization of `{$name}` intrinsic: unsupported {$symbol} from `{$in_ty}` with element `{$in_elem}` to `{$ret_ty}` +codegen_ssa_unable_to_run = unable to run `{$util}`: {$error} -codegen_ssa_invalid_monomorphization_cast_fat_pointer = invalid monomorphization of `{$name}` intrinsic: cannot cast fat pointer `{$ty}` +codegen_ssa_unable_to_run_dsymutil = unable to run `dsymutil`: {$error} -codegen_ssa_invalid_monomorphization_expected_pointer = invalid monomorphization of `{$name}` intrinsic: expected pointer, got `{$ty}` +codegen_ssa_unable_to_write_debugger_visualizer = Unable to write debugger visualizer file `{$path}`: {$error} -codegen_ssa_invalid_monomorphization_expected_usize = invalid monomorphization of `{$name}` intrinsic: expected `usize`, got `{$ty}` +codegen_ssa_unknown_archive_kind = + Don't know how to build archive of type: {$kind} -codegen_ssa_invalid_monomorphization_unsupported_cast = invalid monomorphization of `{$name}` intrinsic: unsupported cast from `{$in_ty}` with element `{$in_elem}` to `{$ret_ty}` with element `{$out_elem}` +codegen_ssa_unknown_atomic_operation = unknown atomic operation -codegen_ssa_invalid_monomorphization_unsupported_operation = invalid monomorphization of `{$name}` intrinsic: unsupported operation on `{$in_ty}` with element `{$in_elem}` +codegen_ssa_unknown_atomic_ordering = unknown ordering in atomic intrinsic -codegen_ssa_invalid_monomorphization_expected_vector_element_type = invalid monomorphization of `{$name}` intrinsic: expected element type `{$expected_element}` of vector type `{$vector_type}` to be a signed or unsigned integer type +codegen_ssa_unsupported_arch = unsupported arch `{$arch}` for os `{$os}` -codegen_ssa_invalid_no_sanitize = invalid argument for `no_sanitize` - .note = expected one of: `address`, `cfi`, `hwaddress`, `kcfi`, `memory`, `memtag`, `shadow-call-stack`, or `thread` +codegen_ssa_unsupported_link_self_contained = option `-C link-self-contained` is not supported on this target -codegen_ssa_invalid_link_ordinal_nargs = incorrect number of arguments to `#[link_ordinal]` - .note = the attribute requires exactly one argument +codegen_ssa_use_cargo_directive = use the `cargo:rustc-link-lib` directive to specify the native libraries to link with Cargo (see https://doc.rust-lang.org/cargo/reference/build-scripts.html#cargorustc-link-libkindname) -codegen_ssa_illegal_link_ordinal_format = illegal ordinal format in `link_ordinal` - .note = an unsuffixed integer value, e.g., `1`, is expected +codegen_ssa_version_script_write_failure = failed to write version script: {$error} -codegen_ssa_target_feature_safe_trait = `#[target_feature(..)]` cannot be applied to safe trait method - .label = cannot be applied to safe trait method - .label_def = not an `unsafe` function +codegen_ssa_visual_studio_not_installed = you may need to install Visual Studio build tools with the "C++ build tools" workload diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 8a00c42a0e8..bdbd10f8260 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -893,7 +893,7 @@ fn link_natively<'a>( linker_path: &linker_path, exit_status: prog.status, command: &cmd, - escaped_output: &escaped_output, + escaped_output, }; sess.diagnostic().emit_err(err); // If MSVC's `link.exe` was expected but the return code @@ -1188,6 +1188,9 @@ fn add_sanitizer_libraries(sess: &Session, crate_type: CrateType, linker: &mut d if sanitizer.contains(SanitizerSet::HWADDRESS) { link_sanitizer_runtime(sess, linker, "hwasan"); } + if sanitizer.contains(SanitizerSet::SAFESTACK) { + link_sanitizer_runtime(sess, linker, "safestack"); + } } fn link_sanitizer_runtime(sess: &Session, linker: &mut dyn Linker, name: &str) { diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs index 8bf84772f08..ad27b854d59 100644 --- a/compiler/rustc_codegen_ssa/src/back/metadata.rs +++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs @@ -188,6 +188,11 @@ pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static }; let mut file = write::Object::new(binary_format, architecture, endianness); + if sess.target.is_like_osx { + if let Some(build_version) = macho_object_build_version_for_target(&sess.target) { + file.set_macho_build_version(build_version) + } + } let e_flags = match architecture { Architecture::Mips => { let arch = match sess.target.options.cpu.as_ref() { @@ -258,6 +263,33 @@ pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static Some(file) } +/// Apple's LD, when linking for Mac Catalyst, requires object files to +/// contain information about what they were built for (LC_BUILD_VERSION): +/// the platform (macOS/watchOS etc), minimum OS version, and SDK version. +/// This returns a `MachOBuildVersion` if necessary for the target. +fn macho_object_build_version_for_target( + target: &Target, +) -> Option<object::write::MachOBuildVersion> { + if !target.llvm_target.ends_with("-macabi") { + return None; + } + /// The `object` crate demands "X.Y.Z encoded in nibbles as xxxx.yy.zz" + /// e.g. minOS 14.0 = 0x000E0000, or SDK 16.2 = 0x00100200 + fn pack_version((major, minor): (u32, u32)) -> u32 { + (major << 16) | (minor << 8) + } + + let platform = object::macho::PLATFORM_MACCATALYST; + let min_os = (14, 0); + let sdk = (16, 2); + + let mut build_version = object::write::MachOBuildVersion::default(); + build_version.platform = platform; + build_version.minos = pack_version(min_os); + build_version.sdk = pack_version(sdk); + Some(build_version) +} + pub enum MetadataPosition { First, Last, diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index c323372bda4..10e9e5588f6 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -1800,7 +1800,7 @@ impl SharedEmitterMain { handler.emit_diagnostic(&mut d); } Ok(SharedEmitterMessage::InlineAsmError(cookie, msg, level, source)) => { - let msg = msg.strip_prefix("error: ").unwrap_or(&msg); + let msg = msg.strip_prefix("error: ").unwrap_or(&msg).to_string(); let mut err = match level { Level::Error { lint: false } => sess.struct_err(msg).forget_guarantee(), diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index cf4893b8226..bf37ac69f2d 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -336,7 +336,7 @@ pub struct LinkingFailed<'a> { pub linker_path: &'a PathBuf, pub exit_status: ExitStatus, pub command: &'a Command, - pub escaped_output: &'a str, + pub escaped_output: String, } impl IntoDiagnostic<'_> for LinkingFailed<'_> { @@ -345,11 +345,13 @@ impl IntoDiagnostic<'_> for LinkingFailed<'_> { diag.set_arg("linker_path", format!("{}", self.linker_path.display())); diag.set_arg("exit_status", format!("{}", self.exit_status)); - diag.note(format!("{:?}", self.command)).note(self.escaped_output); + let contains_undefined_ref = self.escaped_output.contains("undefined reference to"); + + diag.note(format!("{:?}", self.command)).note(self.escaped_output.to_string()); // Trying to match an error from OS linkers // which by now we have no way to translate. - if self.escaped_output.contains("undefined reference to") { + if contains_undefined_ref { diag.note(fluent::codegen_ssa_extern_funcs_not_found) .note(fluent::codegen_ssa_specify_libraries_to_link) .note(fluent::codegen_ssa_use_cargo_directive); diff --git a/compiler/rustc_codegen_ssa/src/mir/analyze.rs b/compiler/rustc_codegen_ssa/src/mir/analyze.rs index 835074806e9..22c1f05974d 100644 --- a/compiler/rustc_codegen_ssa/src/mir/analyze.rs +++ b/compiler/rustc_codegen_ssa/src/mir/analyze.rs @@ -234,7 +234,6 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx> | PlaceContext::NonMutatingUse( NonMutatingUseContext::Inspect | NonMutatingUseContext::SharedBorrow - | NonMutatingUseContext::UniqueBorrow | NonMutatingUseContext::ShallowBorrow | NonMutatingUseContext::AddressOf | NonMutatingUseContext::Projection, diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index d516ac4ebb7..3f0b64b1103 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -1256,7 +1256,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { MergingSucc::False } - mir::TerminatorKind::Drop { place, target, unwind } => { + mir::TerminatorKind::Drop { place, target, unwind, replace: _ } => { self.codegen_drop_terminator(helper, bx, place, target, unwind, mergeable_succ()) } diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index 1204c99e533..00414003202 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -111,7 +111,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { self.instance.subst_mir_and_normalize_erasing_regions( self.cx.tcx(), ty::ParamEnv::reveal_all(), - ty::EarlyBinder(value), + ty::EarlyBinder::bind(value), ) } } diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index 2301c3ef13e..4000c9540ce 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -8,10 +8,10 @@ use crate::traits::*; use crate::MemFlags; use rustc_middle::mir; -use rustc_middle::mir::interpret::{ConstValue, Pointer, Scalar}; +use rustc_middle::mir::interpret::{alloc_range, ConstValue, Pointer, Scalar}; use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; use rustc_middle::ty::Ty; -use rustc_target::abi::{Abi, Align, Size}; +use rustc_target::abi::{self, Abi, Align, Size}; use std::fmt; @@ -115,13 +115,82 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { OperandValue::Pair(a_llval, b_llval) } ConstValue::ByRef { alloc, offset } => { - return bx.load_operand(bx.from_const_alloc(layout, alloc, offset)); + return Self::from_const_alloc(bx, layout, alloc, offset); } }; OperandRef { val, layout } } + fn from_const_alloc<Bx: BuilderMethods<'a, 'tcx, Value = V>>( + bx: &mut Bx, + layout: TyAndLayout<'tcx>, + alloc: rustc_middle::mir::interpret::ConstAllocation<'tcx>, + offset: Size, + ) -> Self { + let alloc_align = alloc.inner().align; + assert_eq!(alloc_align, layout.align.abi); + let ty = bx.type_ptr_to(bx.cx().backend_type(layout)); + + let read_scalar = |start, size, s: abi::Scalar, ty| { + let val = alloc + .0 + .read_scalar( + bx, + alloc_range(start, size), + /*read_provenance*/ matches!(s.primitive(), abi::Pointer(_)), + ) + .unwrap(); + bx.scalar_to_backend(val, s, ty) + }; + + // It may seem like all types with `Scalar` or `ScalarPair` ABI are fair game at this point. + // However, `MaybeUninit<u64>` is considered a `Scalar` as far as its layout is concerned -- + // and yet cannot be represented by an interpreter `Scalar`, since we have to handle the + // case where some of the bytes are initialized and others are not. So, we need an extra + // check that walks over the type of `mplace` to make sure it is truly correct to treat this + // like a `Scalar` (or `ScalarPair`). + match layout.abi { + Abi::Scalar(s @ abi::Scalar::Initialized { .. }) => { + let size = s.size(bx); + assert_eq!(size, layout.size, "abi::Scalar size does not match layout size"); + let val = read_scalar(Size::ZERO, size, s, ty); + OperandRef { val: OperandValue::Immediate(val), layout } + } + Abi::ScalarPair( + a @ abi::Scalar::Initialized { .. }, + b @ abi::Scalar::Initialized { .. }, + ) => { + let (a_size, b_size) = (a.size(bx), b.size(bx)); + let b_offset = a_size.align_to(b.align(bx).abi); + assert!(b_offset.bytes() > 0); + let a_val = read_scalar( + Size::ZERO, + a_size, + a, + bx.scalar_pair_element_backend_type(layout, 0, true), + ); + let b_val = read_scalar( + b_offset, + b_size, + b, + bx.scalar_pair_element_backend_type(layout, 1, true), + ); + OperandRef { val: OperandValue::Pair(a_val, b_val), layout } + } + _ if layout.is_zst() => OperandRef::new_zst(bx, layout), + _ => { + // Neither a scalar nor scalar pair. Load from a place + let init = bx.const_data_from_alloc(alloc); + let base_addr = bx.static_addr_of(init, alloc_align, None); + + let llval = bx.const_ptr_byte_offset(base_addr, offset); + let llval = bx.const_bitcast(llval, ty); + bx.load_operand(PlaceRef::new_sized(llval, layout)) + } + } + } + /// Asserts that this operand refers to a scalar and returns /// a reference to its value. pub fn immediate(self) -> V { diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 6e7065713b8..0255b660380 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -668,11 +668,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mir::Rvalue::NullaryOp(ref null_op, ty) => { let ty = self.monomorphize(ty); - assert!(bx.cx().type_is_sized(ty)); let layout = bx.cx().layout_of(ty); let val = match null_op { - mir::NullOp::SizeOf => layout.size.bytes(), - mir::NullOp::AlignOf => layout.align.abi.bytes(), + mir::NullOp::SizeOf => { + assert!(bx.cx().type_is_sized(ty)); + layout.size.bytes() + } + mir::NullOp::AlignOf => { + assert!(bx.cx().type_is_sized(ty)); + layout.align.abi.bytes() + } mir::NullOp::OffsetOf(fields) => { layout.offset_of_subfield(bx.cx(), fields.iter().map(|f| f.index())).bytes() } diff --git a/compiler/rustc_codegen_ssa/src/traits/consts.rs b/compiler/rustc_codegen_ssa/src/traits/consts.rs index 61906302779..dc2fc396480 100644 --- a/compiler/rustc_codegen_ssa/src/traits/consts.rs +++ b/compiler/rustc_codegen_ssa/src/traits/consts.rs @@ -1,8 +1,6 @@ use super::BackendTypes; -use crate::mir::place::PlaceRef; use rustc_middle::mir::interpret::{ConstAllocation, Scalar}; -use rustc_middle::ty::layout::TyAndLayout; -use rustc_target::abi::{self, Size}; +use rustc_target::abi; pub trait ConstMethods<'tcx>: BackendTypes { // Constant constructors @@ -30,12 +28,8 @@ pub trait ConstMethods<'tcx>: BackendTypes { fn const_data_from_alloc(&self, alloc: ConstAllocation<'tcx>) -> Self::Value; fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, llty: Self::Type) -> Self::Value; - fn from_const_alloc( - &self, - layout: TyAndLayout<'tcx>, - alloc: ConstAllocation<'tcx>, - offset: Size, - ) -> PlaceRef<'tcx, Self::Value>; fn const_ptrcast(&self, val: Self::Value, ty: Self::Type) -> Self::Value; + fn const_bitcast(&self, val: Self::Value, ty: Self::Type) -> Self::Value; + fn const_ptr_byte_offset(&self, val: Self::Value, offset: abi::Size) -> Self::Value; } diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl index f6751df443f..7d56cf0aa07 100644 --- a/compiler/rustc_const_eval/messages.ftl +++ b/compiler/rustc_const_eval/messages.ftl @@ -1,40 +1,60 @@ -const_eval_unstable_in_stable = - const-stable function cannot use `#[feature({$gate})]` - .unstable_sugg = if it is not part of the public API, make this function unstably const - .bypass_sugg = otherwise `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks +const_eval_interior_mutability_borrow = + cannot borrow here, since the borrowed element may contain interior mutability -const_eval_thread_local_access = - thread-local statics cannot be accessed at compile-time +const_eval_interior_mutable_data_refer = + {$kind}s cannot refer to interior mutable data + .label = this borrow of an interior mutable value may end up in the final value + .help = to fix this, the value can be extracted to a separate `static` item and then referenced + .teach_note = + A constant containing interior mutable data behind a reference can allow you to modify that data. + This would make multiple uses of a constant to be able to see different values and allow circumventing + the `Send` and `Sync` requirements for shared mutable data, which is unsound. -const_eval_static_access = - {$kind}s cannot refer to statics - .help = consider extracting the value of the `static` to a `const`, and referring to that - .teach_note = `static` and `const` variables can refer to other `const` variables. A `const` variable, however, cannot refer to a `static` variable. - .teach_help = To fix this, the value can be extracted to a `const` and then used. +const_eval_max_num_nodes_in_const = maximum number of nodes exceeded in constant {$global_const_id} -const_eval_raw_ptr_to_int = - pointers cannot be cast to integers during const eval - .note = at compile-time, pointers do not have an integer value - .note2 = avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior +const_eval_mut_deref = + mutation through a reference is not allowed in {$kind}s + +const_eval_non_const_fmt_macro_call = + cannot call non-const formatting macro in {$kind}s + +const_eval_non_const_fn_call = + cannot call non-const fn `{$def_path_str}` in {$kind}s + +const_eval_panic_non_str = argument to `panic!()` in a const context must have type `&str` const_eval_raw_ptr_comparison = pointers cannot be reliably compared during const eval .note = see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information -const_eval_panic_non_str = argument to `panic!()` in a const context must have type `&str` +const_eval_raw_ptr_to_int = + pointers cannot be cast to integers during const eval + .note = at compile-time, pointers do not have an integer value + .note2 = avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior -const_eval_mut_deref = - mutation through a reference is not allowed in {$kind}s +const_eval_static_access = + {$kind}s cannot refer to statics + .help = consider extracting the value of the `static` to a `const`, and referring to that + .teach_note = `static` and `const` variables can refer to other `const` variables. A `const` variable, however, cannot refer to a `static` variable. + .teach_help = To fix this, the value can be extracted to a `const` and then used. + +const_eval_thread_local_access = + thread-local statics cannot be accessed at compile-time const_eval_transient_mut_borrow = mutable references are not allowed in {$kind}s const_eval_transient_mut_borrow_raw = raw mutable references are not allowed in {$kind}s -const_eval_max_num_nodes_in_const = maximum number of nodes exceeded in constant {$global_const_id} - const_eval_unallowed_fn_pointer_call = function pointer calls are not allowed in {$kind}s -const_eval_unstable_const_fn = `{$def_path}` is not yet stable as a const fn +const_eval_unallowed_heap_allocations = + allocations are not allowed in {$kind}s + .label = allocation not allowed in {$kind}s + .teach_note = + The value of statics and constants must be known at compile time, and they live for the entire lifetime of a program. Creating a boxed value allocates memory on the heap at runtime, and therefore cannot be done at compile time. + +const_eval_unallowed_inline_asm = + inline assembly is not allowed in {$kind}s const_eval_unallowed_mutable_refs = mutable references are not allowed in the final value of {$kind}s @@ -60,32 +80,12 @@ const_eval_unallowed_mutable_refs_raw = If you really want global mutable state, try using static mut or a global UnsafeCell. -const_eval_non_const_fmt_macro_call = - cannot call non-const formatting macro in {$kind}s - -const_eval_non_const_fn_call = - cannot call non-const fn `{$def_path_str}` in {$kind}s - const_eval_unallowed_op_in_const_context = {$msg} -const_eval_unallowed_heap_allocations = - allocations are not allowed in {$kind}s - .label = allocation not allowed in {$kind}s - .teach_note = - The value of statics and constants must be known at compile time, and they live for the entire lifetime of a program. Creating a boxed value allocates memory on the heap at runtime, and therefore cannot be done at compile time. - -const_eval_unallowed_inline_asm = - inline assembly is not allowed in {$kind}s - -const_eval_interior_mutable_data_refer = - {$kind}s cannot refer to interior mutable data - .label = this borrow of an interior mutable value may end up in the final value - .help = to fix this, the value can be extracted to a separate `static` item and then referenced - .teach_note = - A constant containing interior mutable data behind a reference can allow you to modify that data. - This would make multiple uses of a constant to be able to see different values and allow circumventing - the `Send` and `Sync` requirements for shared mutable data, which is unsound. +const_eval_unstable_const_fn = `{$def_path}` is not yet stable as a const fn -const_eval_interior_mutability_borrow = - cannot borrow here, since the borrowed element may contain interior mutability +const_eval_unstable_in_stable = + const-stable function cannot use `#[feature({$gate})]` + .unstable_sugg = if it is not part of the public API, make this function unstably const + .bypass_sugg = otherwise `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index 7e94578003e..91ccdef7215 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -497,7 +497,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { .try_subst_mir_and_normalize_erasing_regions( *self.tcx, self.param_env, - ty::EarlyBinder(value), + ty::EarlyBinder::bind(value), ) .map_err(|_| err_inval!(TooGeneric)) } diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs index df387920010..586e8f063ee 100644 --- a/compiler/rustc_const_eval/src/interpret/terminator.rs +++ b/compiler/rustc_const_eval/src/interpret/terminator.rs @@ -114,7 +114,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } } - Drop { place, target, unwind } => { + Drop { place, target, unwind, replace: _ } => { let frame = self.frame(); let ty = place.ty(&frame.body.local_decls, *self.tcx).ty; let ty = self.subst_from_frame_and_normalize_erasing_regions(frame, ty)?; diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs index 138bc3eb74a..57d939747aa 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -412,9 +412,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { BorrowKind::Shallow => { PlaceContext::NonMutatingUse(NonMutatingUseContext::ShallowBorrow) } - BorrowKind::Unique => { - PlaceContext::NonMutatingUse(NonMutatingUseContext::UniqueBorrow) - } + BorrowKind::Unique => PlaceContext::MutatingUse(MutatingUseContext::Borrow), BorrowKind::Mut { .. } => { PlaceContext::MutatingUse(MutatingUseContext::Borrow) } diff --git a/compiler/rustc_data_structures/src/sharded.rs b/compiler/rustc_data_structures/src/sharded.rs index 7ed70ba1e0f..40cbf14958e 100644 --- a/compiler/rustc_data_structures/src/sharded.rs +++ b/compiler/rustc_data_structures/src/sharded.rs @@ -1,4 +1,6 @@ use crate::fx::{FxHashMap, FxHasher}; +#[cfg(parallel_compiler)] +use crate::sync::is_dyn_thread_safe; use crate::sync::{CacheAligned, Lock, LockGuard}; use std::borrow::Borrow; use std::collections::hash_map::RawEntryMut; @@ -18,6 +20,11 @@ pub const SHARDS: usize = 1 << SHARD_BITS; /// An array of cache-line aligned inner locked structures with convenience methods. pub struct Sharded<T> { + /// This mask is used to ensure that accesses are inbounds of `shards`. + /// When dynamic thread safety is off, this field is set to 0 causing only + /// a single shard to be used for greater cache efficiency. + #[cfg(parallel_compiler)] + mask: usize, shards: [CacheAligned<Lock<T>>; SHARDS], } @@ -31,31 +38,54 @@ impl<T: Default> Default for Sharded<T> { impl<T> Sharded<T> { #[inline] pub fn new(mut value: impl FnMut() -> T) -> Self { - Sharded { shards: [(); SHARDS].map(|()| CacheAligned(Lock::new(value()))) } + Sharded { + #[cfg(parallel_compiler)] + mask: if is_dyn_thread_safe() { SHARDS - 1 } else { 0 }, + shards: [(); SHARDS].map(|()| CacheAligned(Lock::new(value()))), + } + } + + #[inline(always)] + fn mask(&self) -> usize { + #[cfg(parallel_compiler)] + { + if SHARDS == 1 { 0 } else { self.mask } + } + #[cfg(not(parallel_compiler))] + { + 0 + } + } + + #[inline(always)] + fn count(&self) -> usize { + // `self.mask` is always one below the used shard count + self.mask() + 1 } /// The shard is selected by hashing `val` with `FxHasher`. #[inline] pub fn get_shard_by_value<K: Hash + ?Sized>(&self, val: &K) -> &Lock<T> { - if SHARDS == 1 { &self.shards[0].0 } else { self.get_shard_by_hash(make_hash(val)) } + self.get_shard_by_hash(if SHARDS == 1 { 0 } else { make_hash(val) }) } #[inline] pub fn get_shard_by_hash(&self, hash: u64) -> &Lock<T> { - &self.shards[get_shard_index_by_hash(hash)].0 + self.get_shard_by_index(get_shard_hash(hash)) } #[inline] pub fn get_shard_by_index(&self, i: usize) -> &Lock<T> { - &self.shards[i].0 + // SAFETY: The index get ANDed with the mask, ensuring it is always inbounds. + unsafe { &self.shards.get_unchecked(i & self.mask()).0 } } pub fn lock_shards(&self) -> Vec<LockGuard<'_, T>> { - (0..SHARDS).map(|i| self.shards[i].0.lock()).collect() + (0..self.count()).map(|i| self.get_shard_by_index(i).lock()).collect() } pub fn try_lock_shards(&self) -> Option<Vec<LockGuard<'_, T>>> { - (0..SHARDS).map(|i| self.shards[i].0.try_lock()).collect() + (0..self.count()).map(|i| self.get_shard_by_index(i).try_lock()).collect() } } @@ -136,11 +166,9 @@ pub fn make_hash<K: Hash + ?Sized>(val: &K) -> u64 { /// `hash` can be computed with any hasher, so long as that hasher is used /// consistently for each `Sharded` instance. #[inline] -#[allow(clippy::modulo_one)] -pub fn get_shard_index_by_hash(hash: u64) -> usize { +fn get_shard_hash(hash: u64) -> usize { let hash_len = mem::size_of::<usize>(); // Ignore the top 7 bits as hashbrown uses these and get the next SHARD_BITS highest bits. // hashbrown also uses the lowest bits, so we can't use those - let bits = (hash >> (hash_len * 8 - 7 - SHARD_BITS)) as usize; - bits % SHARDS + (hash >> (hash_len * 8 - 7 - SHARD_BITS)) as usize } diff --git a/compiler/rustc_driver_impl/messages.ftl b/compiler/rustc_driver_impl/messages.ftl index f19b1ff6426..22b4ec6b0d1 100644 --- a/compiler/rustc_driver_impl/messages.ftl +++ b/compiler/rustc_driver_impl/messages.ftl @@ -1,19 +1,19 @@ -driver_impl_rlink_unable_to_read = failed to read rlink file: `{$err}` - -driver_impl_rlink_wrong_file_type = The input does not look like a .rlink file +driver_impl_ice = the compiler unexpectedly panicked. this is a bug. +driver_impl_ice_bug_report = we would appreciate a bug report: {$bug_report_url} +driver_impl_ice_exclude_cargo_defaults = some of the compiler flags provided by cargo are hidden +driver_impl_ice_flags = compiler flags: {$flags} +driver_impl_ice_version = rustc {$version} running on {$triple} driver_impl_rlink_empty_version_number = The input does not contain version number driver_impl_rlink_encoding_version_mismatch = .rlink file was produced with encoding version `{$version_array}`, but the current version is `{$rlink_version}` +driver_impl_rlink_no_a_file = rlink must be a file + driver_impl_rlink_rustc_version_mismatch = .rlink file was produced by rustc version `{$rustc_version}`, but the current version is `{$current_version}` -driver_impl_rlink_no_a_file = rlink must be a file +driver_impl_rlink_unable_to_read = failed to read rlink file: `{$err}` -driver_impl_unpretty_dump_fail = pretty-print failed to write `{$path}` due to error `{$err}` +driver_impl_rlink_wrong_file_type = The input does not look like a .rlink file -driver_impl_ice = the compiler unexpectedly panicked. this is a bug. -driver_impl_ice_bug_report = we would appreciate a bug report: {$bug_report_url} -driver_impl_ice_version = rustc {$version} running on {$triple} -driver_impl_ice_flags = compiler flags: {$flags} -driver_impl_ice_exclude_cargo_defaults = some of the compiler flags provided by cargo are hidden +driver_impl_unpretty_dump_fail = pretty-print failed to write `{$path}` due to error `{$err}` diff --git a/compiler/rustc_driver_impl/src/args.rs b/compiler/rustc_driver_impl/src/args.rs index a713affa099..eb92ccc17b2 100644 --- a/compiler/rustc_driver_impl/src/args.rs +++ b/compiler/rustc_driver_impl/src/args.rs @@ -18,6 +18,9 @@ fn arg_expand(arg: String) -> Result<Vec<String>, Error> { } } +/// **Note:** This function doesn't interpret argument 0 in any special way. +/// If this function is intended to be used with command line arguments, +/// `argv[0]` must be removed prior to calling it manually. pub fn arg_expand_all(at_args: &[String]) -> Vec<String> { let mut args = Vec::new(); for arg in at_args { diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 40aa69e5a41..14888cf4d75 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -250,6 +250,16 @@ fn run_compiler( Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>, >, ) -> interface::Result<()> { + // Throw away the first argument, the name of the binary. + // In case of at_args being empty, as might be the case by + // passing empty argument array to execve under some platforms, + // just use an empty slice. + // + // This situation was possible before due to arg_expand_all being + // called before removing the argument, enabling a crash by calling + // the compiler with @empty_file as argv[0] and no more arguments. + let at_args = at_args.get(1..).unwrap_or_default(); + let args = args::arg_expand_all(at_args); let Some(matches) = handle_options(&args) else { return Ok(()) }; @@ -1074,9 +1084,6 @@ fn print_flag_list<T>( /// So with all that in mind, the comments below have some more detail about the /// contortions done here to get things to work out correctly. pub fn handle_options(args: &[String]) -> Option<getopts::Matches> { - // Throw away the first argument, the name of the binary - let args = &args[1..]; - if args.is_empty() { // user did not write `-v` nor `-Z unstable-options`, so do not // include that extra information. @@ -1251,7 +1258,7 @@ pub fn install_ice_hook(bug_report_url: &'static str, extra_info: fn(&Handler)) if let Some(msg) = info.payload().downcast_ref::<String>() { if msg.starts_with("failed printing to stdout: ") && msg.ends_with("(os error 232)") { // the error code is already going to be reported when the panic unwinds up the stack - let _ = early_error_no_abort(ErrorOutputType::default(), msg.as_str()); + let _ = early_error_no_abort(ErrorOutputType::default(), msg.clone()); return; } }; diff --git a/compiler/rustc_error_codes/src/error_codes/E0133.md b/compiler/rustc_error_codes/src/error_codes/E0133.md index 1adbcc31356..8ca3f03ce15 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0133.md +++ b/compiler/rustc_error_codes/src/error_codes/E0133.md @@ -1,4 +1,4 @@ -Unsafe code was used outside of an unsafe function or block. +Unsafe code was used outside of an unsafe block. Erroneous code example: @@ -30,4 +30,21 @@ fn main() { See the [unsafe section][unsafe-section] of the Book for more details. +#### Unsafe code in functions + +Unsafe code is currently accepted in unsafe functions, but that is being phased +out in favor of requiring unsafe blocks here too. + +``` +unsafe fn f() { return; } + +unsafe fn g() { + f(); // Is accepted, but no longer recommended + unsafe { f(); } // Recommended way to write this +} +``` + +Linting against this is controlled via the `unsafe_op_in_unsafe_fn` lint, which +is `allow` by default but will be upgraded to `warn` in a future edition. + [unsafe-section]: https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs index 0accb4ab96f..2a97c4ff7ae 100644 --- a/compiler/rustc_error_messages/src/lib.rs +++ b/compiler/rustc_error_messages/src/lib.rs @@ -263,8 +263,7 @@ type FluentId = Cow<'static, str>; #[rustc_diagnostic_item = "SubdiagnosticMessage"] pub enum SubdiagnosticMessage { /// Non-translatable diagnostic message. - // FIXME(davidtwco): can a `Cow<'static, str>` be used here? - Str(String), + Str(Cow<'static, str>), /// Translatable message which has already been translated eagerly. /// /// Some diagnostics have repeated subdiagnostics where the same interpolated variables would @@ -275,8 +274,7 @@ pub enum SubdiagnosticMessage { /// incorrect diagnostics. Eager translation results in translation for a subdiagnostic /// happening immediately after the subdiagnostic derive's logic has been run. This variant /// stores messages which have been translated eagerly. - // FIXME(#100717): can a `Cow<'static, str>` be used here? - Eager(String), + Eager(Cow<'static, str>), /// Identifier of a Fluent message. Instances of this variant are generated by the /// `Subdiagnostic` derive. FluentIdentifier(FluentId), @@ -290,17 +288,17 @@ pub enum SubdiagnosticMessage { impl From<String> for SubdiagnosticMessage { fn from(s: String) -> Self { - SubdiagnosticMessage::Str(s) + SubdiagnosticMessage::Str(Cow::Owned(s)) } } -impl<'a> From<&'a str> for SubdiagnosticMessage { - fn from(s: &'a str) -> Self { - SubdiagnosticMessage::Str(s.to_string()) +impl From<&'static str> for SubdiagnosticMessage { + fn from(s: &'static str) -> Self { + SubdiagnosticMessage::Str(Cow::Borrowed(s)) } } impl From<Cow<'static, str>> for SubdiagnosticMessage { fn from(s: Cow<'static, str>) -> Self { - SubdiagnosticMessage::Str(s.to_string()) + SubdiagnosticMessage::Str(s) } } @@ -312,8 +310,7 @@ impl From<Cow<'static, str>> for SubdiagnosticMessage { #[rustc_diagnostic_item = "DiagnosticMessage"] pub enum DiagnosticMessage { /// Non-translatable diagnostic message. - // FIXME(#100717): can a `Cow<'static, str>` be used here? - Str(String), + Str(Cow<'static, str>), /// Translatable message which has already been translated eagerly. /// /// Some diagnostics have repeated subdiagnostics where the same interpolated variables would @@ -324,8 +321,7 @@ pub enum DiagnosticMessage { /// incorrect diagnostics. Eager translation results in translation for a subdiagnostic /// happening immediately after the subdiagnostic derive's logic has been run. This variant /// stores messages which have been translated eagerly. - // FIXME(#100717): can a `Cow<'static, str>` be used here? - Eager(String), + Eager(Cow<'static, str>), /// Identifier for a Fluent message (with optional attribute) corresponding to the diagnostic /// message. /// @@ -363,17 +359,17 @@ impl DiagnosticMessage { impl From<String> for DiagnosticMessage { fn from(s: String) -> Self { - DiagnosticMessage::Str(s) + DiagnosticMessage::Str(Cow::Owned(s)) } } -impl<'a> From<&'a str> for DiagnosticMessage { - fn from(s: &'a str) -> Self { - DiagnosticMessage::Str(s.to_string()) +impl From<&'static str> for DiagnosticMessage { + fn from(s: &'static str) -> Self { + DiagnosticMessage::Str(Cow::Borrowed(s)) } } impl From<Cow<'static, str>> for DiagnosticMessage { fn from(s: Cow<'static, str>) -> Self { - DiagnosticMessage::Str(s.to_string()) + DiagnosticMessage::Str(s) } } diff --git a/compiler/rustc_errors/messages.ftl b/compiler/rustc_errors/messages.ftl index dde1d6c0a81..33709734322 100644 --- a/compiler/rustc_errors/messages.ftl +++ b/compiler/rustc_errors/messages.ftl @@ -1,19 +1,19 @@ -errors_target_invalid_address_space = - invalid address space `{$addr_space}` for `{$cause}` in "data-layout": {$err} +errors_target_inconsistent_architecture = + inconsistent target specification: "data-layout" claims architecture is {$dl}-endian, while "target-endian" is `{$target}` -errors_target_invalid_bits = - invalid {$kind} `{$bit}` for `{$cause}` in "data-layout": {$err} +errors_target_inconsistent_pointer_width = + inconsistent target specification: "data-layout" claims pointers are {$pointer_size}-bit, while "target-pointer-width" is `{$target}` -errors_target_missing_alignment = - missing alignment for `{$cause}` in "data-layout" +errors_target_invalid_address_space = + invalid address space `{$addr_space}` for `{$cause}` in "data-layout": {$err} errors_target_invalid_alignment = invalid alignment for `{$cause}` in "data-layout": {$err} -errors_target_inconsistent_architecture = - inconsistent target specification: "data-layout" claims architecture is {$dl}-endian, while "target-endian" is `{$target}` - -errors_target_inconsistent_pointer_width = - inconsistent target specification: "data-layout" claims pointers are {$pointer_size}-bit, while "target-pointer-width" is `{$target}` +errors_target_invalid_bits = + invalid {$kind} `{$bit}` for `{$cause}` in "data-layout": {$err} errors_target_invalid_bits_size = {$err} + +errors_target_missing_alignment = + missing alignment for `{$cause}` in "data-layout" diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 29c692128bc..488f2d67ee5 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -352,14 +352,9 @@ impl Diagnostic { /// Labels all the given spans with the provided label. /// See [`Self::span_label()`] for more information. - pub fn span_labels( - &mut self, - spans: impl IntoIterator<Item = Span>, - label: impl AsRef<str>, - ) -> &mut Self { - let label = label.as_ref(); + pub fn span_labels(&mut self, spans: impl IntoIterator<Item = Span>, label: &str) -> &mut Self { for span in spans { - self.span_label(span, label); + self.span_label(span, label.to_string()); } self } @@ -394,17 +389,18 @@ impl Diagnostic { expected: DiagnosticStyledString, found: DiagnosticStyledString, ) -> &mut Self { - let mut msg: Vec<_> = vec![("required when trying to coerce from type `", Style::NoStyle)]; + let mut msg: Vec<_> = + vec![(Cow::from("required when trying to coerce from type `"), Style::NoStyle)]; msg.extend(expected.0.iter().map(|x| match *x { - StringPart::Normal(ref s) => (s.as_str(), Style::NoStyle), - StringPart::Highlighted(ref s) => (s.as_str(), Style::Highlight), + StringPart::Normal(ref s) => (Cow::from(s.clone()), Style::NoStyle), + StringPart::Highlighted(ref s) => (Cow::from(s.clone()), Style::Highlight), })); - msg.push(("` to type '", Style::NoStyle)); + msg.push((Cow::from("` to type '"), Style::NoStyle)); msg.extend(found.0.iter().map(|x| match *x { - StringPart::Normal(ref s) => (s.as_str(), Style::NoStyle), - StringPart::Highlighted(ref s) => (s.as_str(), Style::Highlight), + StringPart::Normal(ref s) => (Cow::from(s.clone()), Style::NoStyle), + StringPart::Highlighted(ref s) => (Cow::from(s.clone()), Style::Highlight), })); - msg.push(("`", Style::NoStyle)); + msg.push((Cow::from("`"), Style::NoStyle)); // For now, just attach these as notes self.highlighted_note(msg); diff --git a/compiler/rustc_errors/src/diagnostic_builder.rs b/compiler/rustc_errors/src/diagnostic_builder.rs index db97d96fccd..7d9d0c76450 100644 --- a/compiler/rustc_errors/src/diagnostic_builder.rs +++ b/compiler/rustc_errors/src/diagnostic_builder.rs @@ -558,7 +558,7 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> { } // Take the `Diagnostic` by replacing it with a dummy. - let dummy = Diagnostic::new(Level::Allow, DiagnosticMessage::Str("".to_string())); + let dummy = Diagnostic::new(Level::Allow, DiagnosticMessage::from("")); let diagnostic = std::mem::replace(&mut *self.inner.diagnostic, dummy); // Disable the ICE on `Drop`. @@ -627,7 +627,7 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> { pub fn span_labels( &mut self, spans: impl IntoIterator<Item = Span>, - label: impl AsRef<str>, + label: &str, ) -> &mut Self); forward!(pub fn note_expected_found( @@ -781,8 +781,8 @@ impl Drop for DiagnosticBuilderInner<'_> { if !panicking() { handler.emit_diagnostic(&mut Diagnostic::new( Level::Bug, - DiagnosticMessage::Str( - "the following error was constructed but not emitted".to_string(), + DiagnosticMessage::from( + "the following error was constructed but not emitted", ), )); handler.emit_diagnostic(&mut self.diagnostic); diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index e8cd7eaa60f..d8c997b49a1 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -367,7 +367,7 @@ pub trait Emitter: Translate { children.push(SubDiagnostic { level: Level::Note, - message: vec![(DiagnosticMessage::Str(msg), Style::NoStyle)], + message: vec![(DiagnosticMessage::from(msg), Style::NoStyle)], span: MultiSpan::new(), render_span: None, }); diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 3dec0d9299c..6c5f3e62454 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -628,7 +628,7 @@ impl Handler { message: DiagnosticMessage, args: impl Iterator<Item = DiagnosticArg<'a, 'static>>, ) -> SubdiagnosticMessage { - SubdiagnosticMessage::Eager(self.eagerly_translate_to_string(message, args)) + SubdiagnosticMessage::Eager(Cow::from(self.eagerly_translate_to_string(message, args))) } /// Translate `message` eagerly with `args` to `String`. @@ -1450,14 +1450,14 @@ impl HandlerInner { self.emit_stashed_diagnostics(); let warnings = match self.deduplicated_warn_count { - 0 => String::new(), - 1 => "1 warning emitted".to_string(), - count => format!("{count} warnings emitted"), + 0 => Cow::from(""), + 1 => Cow::from("1 warning emitted"), + count => Cow::from(format!("{count} warnings emitted")), }; let errors = match self.deduplicated_err_count { - 0 => String::new(), - 1 => "aborting due to previous error".to_string(), - count => format!("aborting due to {count} previous errors"), + 0 => Cow::from(""), + 1 => Cow::from("aborting due to previous error"), + count => Cow::from(format!("aborting due to {count} previous errors")), }; if self.treat_err_as_bug() { return; diff --git a/compiler/rustc_expand/messages.ftl b/compiler/rustc_expand/messages.ftl index 70d2718b706..6c7e68246ea 100644 --- a/compiler/rustc_expand/messages.ftl +++ b/compiler/rustc_expand/messages.ftl @@ -1,142 +1,142 @@ -expand_explain_doc_comment_outer = - outer doc comments expand to `#[doc = "..."]`, which is what this macro attempted to match - -expand_explain_doc_comment_inner = - inner doc comments expand to `#![doc = "..."]`, which is what this macro attempted to match - -expand_expr_repeat_no_syntax_vars = - attempted to repeat an expression containing no syntax variables matched as repeating at this depth - -expand_must_repeat_once = - this must repeat at least once - -expand_count_repetition_misplaced = - `count` can not be placed inside the inner-most repetition - -expand_meta_var_expr_unrecognized_var = - variable `{$key}` is not recognized in meta-variable expression - -expand_var_still_repeating = - variable '{$ident}' is still repeating at this depth - -expand_meta_var_dif_seq_matchers = {$msg} - -expand_macro_const_stability = - macros cannot have const stability attributes - .label = invalid const stability attribute - .label2 = const stability attribute affects this macro - -expand_macro_body_stability = - macros cannot have body stability attributes - .label = invalid body stability attribute - .label2 = body stability attribute affects this macro - -expand_resolve_relative_path = - cannot resolve relative path in non-file source `{$path}` +expand_arg_not_attributes = + second argument must be `attributes` expand_attr_no_arguments = attribute must have either one or two arguments -expand_not_a_meta_item = - not a meta item - -expand_only_one_word = - must only be one word - -expand_cannot_be_name_of_macro = - `{$trait_ident}` cannot be a name of {$macro_type} macro +expand_attribute_meta_item = + attribute must be a meta item, not a literal -expand_arg_not_attributes = - second argument must be `attributes` +expand_attribute_single_word = + attribute must only be a single word expand_attributes_wrong_form = attribute must be of form: `attributes(foo, bar)` -expand_attribute_meta_item = - attribute must be a meta item, not a literal +expand_cannot_be_name_of_macro = + `{$trait_ident}` cannot be a name of {$macro_type} macro -expand_attribute_single_word = - attribute must only be a single word +expand_count_repetition_misplaced = + `count` can not be placed inside the inner-most repetition -expand_helper_attribute_name_invalid = - `{$name}` cannot be a name of derive helper attribute +expand_duplicate_matcher_binding = duplicate matcher binding + .label = duplicate binding + .label2 = previous binding expand_expected_comma_in_list = expected token: `,` -expand_only_one_argument = - {$name} takes 1 argument +expand_explain_doc_comment_inner = + inner doc comments expand to `#![doc = "..."]`, which is what this macro attempted to match -expand_takes_no_arguments = - {$name} takes no arguments +expand_explain_doc_comment_outer = + outer doc comments expand to `#[doc = "..."]`, which is what this macro attempted to match + +expand_expr_repeat_no_syntax_vars = + attempted to repeat an expression containing no syntax variables matched as repeating at this depth expand_feature_included_in_edition = the feature `{$feature}` is included in the Rust {$edition} edition +expand_feature_not_allowed = + the feature `{$name}` is not in the list of allowed features + expand_feature_removed = feature has been removed .label = feature has been removed .reason = {$reason} -expand_feature_not_allowed = - the feature `{$name}` is not in the list of allowed features - -expand_recursion_limit_reached = - recursion limit reached while expanding `{$descr}` - .help = consider increasing the recursion limit by adding a `#![recursion_limit = "{$suggested_limit}"]` attribute to your crate (`{$crate_name}`) +expand_helper_attribute_name_invalid = + `{$name}` cannot be a name of derive helper attribute -expand_malformed_feature_attribute = - malformed `feature` attribute input - .expected = expected just one word +expand_incomplete_parse = + macro expansion ignores token `{$token}` and any following + .label = caused by the macro expansion here + .note = the usage of `{$macro_path}!` is likely invalid in {$kind_name} context + .suggestion_add_semi = you might be missing a semicolon here -expand_remove_expr_not_supported = - removing an expression is not supported in this position +expand_invalid_cfg_expected_syntax = expected syntax is +expand_invalid_cfg_multiple_predicates = multiple `cfg` predicates are specified expand_invalid_cfg_no_parens = `cfg` is not followed by parentheses expand_invalid_cfg_no_predicate = `cfg` predicate is not specified -expand_invalid_cfg_multiple_predicates = multiple `cfg` predicates are specified expand_invalid_cfg_predicate_literal = `cfg` predicate key cannot be a literal -expand_invalid_cfg_expected_syntax = expected syntax is +expand_macro_body_stability = + macros cannot have body stability attributes + .label = invalid body stability attribute + .label2 = body stability attribute affects this macro -expand_wrong_fragment_kind = - non-{$kind} macro in {$kind} position: {$name} +expand_macro_const_stability = + macros cannot have const stability attributes + .label = invalid const stability attribute + .label2 = const stability attribute affects this macro -expand_unsupported_key_value = - key-value macro attributes are not supported +expand_malformed_feature_attribute = + malformed `feature` attribute input + .expected = expected just one word -expand_incomplete_parse = - macro expansion ignores token `{$token}` and any following - .label = caused by the macro expansion here - .note = the usage of `{$macro_path}!` is likely invalid in {$kind_name} context - .suggestion_add_semi = you might be missing a semicolon here +expand_meta_var_dif_seq_matchers = {$msg} -expand_remove_node_not_supported = - removing {$descr} is not supported in this position +expand_meta_var_expr_unrecognized_var = + variable `{$key}` is not recognized in meta-variable expression expand_module_circular = circular modules: {$modules} -expand_module_in_block = - cannot declare a non-inline module inside a block unless it has a path attribute - .note = maybe `use` the module `{$name}` instead of redeclaring it - expand_module_file_not_found = file not found for module `{$name}` .help = to create the module `{$name}`, create file "{$default_path}" or "{$secondary_path}" +expand_module_in_block = + cannot declare a non-inline module inside a block unless it has a path attribute + .note = maybe `use` the module `{$name}` instead of redeclaring it + expand_module_multiple_candidates = file for module `{$name}` found at both "{$default_path}" and "{$secondary_path}" .help = delete or rename one of them to remove the ambiguity -expand_trace_macro = trace_macro +expand_must_repeat_once = + this must repeat at least once + +expand_not_a_meta_item = + not a meta item + +expand_only_one_argument = + {$name} takes 1 argument + +expand_only_one_word = + must only be one word + +expand_proc_macro_derive_tokens = + proc-macro derive produced unparsable tokens expand_proc_macro_panicked = proc macro panicked .help = message: {$message} -expand_proc_macro_derive_tokens = - proc-macro derive produced unparsable tokens +expand_recursion_limit_reached = + recursion limit reached while expanding `{$descr}` + .help = consider increasing the recursion limit by adding a `#![recursion_limit = "{$suggested_limit}"]` attribute to your crate (`{$crate_name}`) -expand_duplicate_matcher_binding = duplicate matcher binding - .label = duplicate binding - .label2 = previous binding +expand_remove_expr_not_supported = + removing an expression is not supported in this position + +expand_remove_node_not_supported = + removing {$descr} is not supported in this position + +expand_resolve_relative_path = + cannot resolve relative path in non-file source `{$path}` + +expand_takes_no_arguments = + {$name} takes no arguments + +expand_trace_macro = trace_macro + +expand_unsupported_key_value = + key-value macro attributes are not supported + +expand_var_still_repeating = + variable '{$ident}' is still repeating at this depth + +expand_wrong_fragment_kind = + non-{$kind} macro in {$kind} position: {$name} diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 4671adccc54..0d43b30474b 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -1154,7 +1154,7 @@ impl<'a> ExtCtxt<'a> { // Fixme: does this result in errors? self.expansions.clear(); } - pub fn bug(&self, msg: &str) -> ! { + pub fn bug(&self, msg: &'static str) -> ! { self.sess.parse_sess.span_diagnostic.bug(msg); } pub fn trace_macros(&self) -> bool { @@ -1224,7 +1224,7 @@ pub fn resolve_path( pub fn expr_to_spanned_string<'a>( cx: &'a mut ExtCtxt<'_>, expr: P<ast::Expr>, - err_msg: &str, + err_msg: &'static str, ) -> Result<(Symbol, ast::StrStyle, Span), Option<(DiagnosticBuilder<'a, ErrorGuaranteed>, bool)>> { // Perform eager expansion on the expression. // We want to be able to handle e.g., `concat!("foo", "bar")`. @@ -1262,7 +1262,7 @@ pub fn expr_to_spanned_string<'a>( pub fn expr_to_string( cx: &mut ExtCtxt<'_>, expr: P<ast::Expr>, - err_msg: &str, + err_msg: &'static str, ) -> Option<(Symbol, ast::StrStyle)> { expr_to_spanned_string(cx, expr, err_msg) .map_err(|err| { diff --git a/compiler/rustc_expand/src/mbe/diagnostics.rs b/compiler/rustc_expand/src/mbe/diagnostics.rs index cb8b4899e48..3593bed2d02 100644 --- a/compiler/rustc_expand/src/mbe/diagnostics.rs +++ b/compiler/rustc_expand/src/mbe/diagnostics.rs @@ -170,7 +170,7 @@ impl<'a, 'cx, 'matcher> Tracker<'matcher> for CollectTrackerAndEmitter<'a, 'cx, } Error(err_sp, msg) => { let span = err_sp.substitute_dummy(self.root_span); - self.cx.struct_span_err(span, msg.as_str()).emit(); + self.cx.struct_span_err(span, msg.clone()).emit(); self.result = Some(DummyResult::any(span)); } ErrorReported(_) => self.result = Some(DummyResult::any(self.root_span)), @@ -222,7 +222,7 @@ pub(super) fn emit_frag_parse_err( { let msg = &e.message[0]; e.message[0] = ( - DiagnosticMessage::Str(format!( + DiagnosticMessage::from(format!( "macro expansion ends with an incomplete expression: {}", message.replace(", found `<eof>`", ""), )), @@ -313,9 +313,9 @@ pub(super) fn annotate_doc_comment(err: &mut Diagnostic, sm: &SourceMap, span: S /// Generates an appropriate parsing failure message. For EOF, this is "unexpected end...". For /// other tokens, this is "unexpected token...". -pub(super) fn parse_failure_msg(tok: &Token) -> String { +pub(super) fn parse_failure_msg(tok: &Token) -> Cow<'static, str> { match tok.kind { - token::Eof => "unexpected end of macro invocation".to_string(), - _ => format!("no rules expected the token `{}`", pprust::token_to_string(tok),), + token::Eof => Cow::from("unexpected end of macro invocation"), + _ => Cow::from(format!("no rules expected the token `{}`", pprust::token_to_string(tok))), } } diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index 5e5c984a7ea..02d1dfcd113 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -1,77 +1,144 @@ -hir_analysis_unrecognized_atomic_operation = - unrecognized atomic operation function: `{$op}` - .label = unrecognized atomic operation +hir_analysis_ambiguous_lifetime_bound = + ambiguous lifetime bound, explicit lifetime bound required -hir_analysis_wrong_number_of_generic_arguments_to_intrinsic = - intrinsic has wrong number of {$descr} parameters: found {$found}, expected {$expected} - .label = expected {$expected} {$descr} {$expected -> - [one] parameter - *[other] parameters - } +hir_analysis_assoc_type_binding_not_allowed = + associated type bindings are not allowed here + .label = associated type not allowed here -hir_analysis_unrecognized_intrinsic_function = - unrecognized intrinsic function: `{$name}` - .label = unrecognized intrinsic +hir_analysis_associated_type_trait_uninferred_generic_params = cannot use the associated type of a trait with uninferred generic parameters + .suggestion = use a fully qualified path with inferred lifetimes -hir_analysis_lifetimes_or_bounds_mismatch_on_trait = - lifetime parameters or bounds on {$item_kind} `{$ident}` do not match the trait declaration - .label = lifetimes do not match {$item_kind} in trait - .generics_label = lifetimes in impl do not match this {$item_kind} in trait - .where_label = this `where` clause might not match the one in the trait - .bounds_label = this bound might be missing in the impl +hir_analysis_associated_type_trait_uninferred_generic_params_multipart_suggestion = use a fully qualified path with explicit lifetimes hir_analysis_async_trait_impl_should_be_async = method `{$method_name}` should be async because the method from the trait is async .trait_item_label = required because the trait method is async +hir_analysis_auto_deref_reached_recursion_limit = reached the recursion limit while auto-dereferencing `{$ty}` + .label = deref recursion limit reached + .help = consider increasing the recursion limit by adding a `#![recursion_limit = "{$suggested_limit}"]` attribute to your crate (`{$crate_name}`) + +hir_analysis_cannot_capture_late_bound_const_in_anon_const = + cannot capture late-bound const parameter in a constant + .label = parameter defined here + +hir_analysis_cannot_capture_late_bound_ty_in_anon_const = + cannot capture late-bound type parameter in a constant + .label = parameter defined here + +hir_analysis_cast_thin_pointer_to_fat_pointer = cannot cast thin pointer `{$expr_ty}` to fat pointer `{$cast_ty}` + +hir_analysis_closure_implicit_hrtb = implicit types in closure signatures are forbidden when `for<...>` is present + .label = `for<...>` is here + +hir_analysis_const_bound_for_non_const_trait = + ~const can only be applied to `#[const_trait]` traits + +hir_analysis_const_impl_for_non_const_trait = + const `impl` for trait `{$trait_name}` which is not marked with `#[const_trait]` + .suggestion = mark `{$trait_name}` as const + .note = marking a trait with `#[const_trait]` ensures all default method bodies are `const` + .adding = adding a non-const method body in the future would be a breaking change + +hir_analysis_const_param_ty_impl_on_non_adt = + the trait `ConstParamTy` may not be implemented for this type + .label = type is not a structure or enumeration + +hir_analysis_const_specialize = cannot specialize on const impl with non-const impl + +hir_analysis_copy_impl_on_non_adt = + the trait `Copy` cannot be implemented for this type + .label = type is not a structure or enumeration + +hir_analysis_copy_impl_on_type_with_dtor = + the trait `Copy` cannot be implemented for this type; the type has a destructor + .label = `Copy` not allowed on types with destructors + +hir_analysis_drop_impl_negative = negative `Drop` impls are not supported + hir_analysis_drop_impl_on_wrong_item = the `Drop` trait may only be implemented for local structs, enums, and unions .label = must be a struct, enum, or union in the current crate +hir_analysis_drop_impl_reservation = reservation `Drop` impls are not supported + +hir_analysis_empty_specialization = specialization impl does not specialize any associated items + .note = impl is a specialization of this impl + +hir_analysis_enum_discriminant_overflowed = enum discriminant overflowed + .label = overflowed on value after {$discr} + .note = explicitly set `{$item_name} = {$wrapped_discr}` if that is desired outcome + +hir_analysis_expected_used_symbol = expected `used`, `used(compiler)` or `used(linker)` + hir_analysis_field_already_declared = field `{$field_name}` is already declared .label = field already declared .previous_decl_label = `{$field_name}` first declared here -hir_analysis_expected_used_symbol = expected `used`, `used(compiler)` or `used(linker)` +hir_analysis_function_not_found_in_trait = function not found in this trait -hir_analysis_const_param_ty_impl_on_non_adt = - the trait `ConstParamTy` may not be implemented for this type - .label = type is not a structure or enumeration +hir_analysis_function_not_have_default_implementation = function doesn't have a default implementation + .note = required by this annotation -hir_analysis_ambiguous_lifetime_bound = - ambiguous lifetime bound, explicit lifetime bound required +hir_analysis_functions_names_duplicated = functions names are duplicated + .note = all `#[rustc_must_implement_one_of]` arguments must be unique -hir_analysis_assoc_type_binding_not_allowed = - associated type bindings are not allowed here - .label = associated type not allowed here +hir_analysis_impl_not_marked_default = `{$ident}` specializes an item from a parent `impl`, but that item is not marked `default` + .label = cannot specialize default item `{$ident}` + .ok_label = parent `impl` is here + .note = to specialize, `{$ident}` in the parent `impl` must be marked `default` -hir_analysis_parenthesized_fn_trait_expansion = - parenthesized trait syntax expands to `{$expanded_type}` +hir_analysis_impl_not_marked_default_err = `{$ident}` specializes an item from a parent `impl`, but that item is not marked `default` + .note = parent implementation is in crate `{$cname}` -hir_analysis_typeof_reserved_keyword_used = - `typeof` is a reserved keyword but unimplemented - .suggestion = consider replacing `typeof(...)` with an actual type - .label = reserved keyword +hir_analysis_invalid_union_field = + field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union + .note = union fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>` -hir_analysis_value_of_associated_struct_already_specified = - the value of the associated type `{$item_name}` (from trait `{$def_path}`) is already specified - .label = re-bound here - .previous_bound_label = `{$item_name}` bound here first +hir_analysis_invalid_union_field_sugg = + wrap the field type in `ManuallyDrop<...>` -hir_analysis_unconstrained_opaque_type = unconstrained opaque type - .note = `{$name}` must be used in combination with a concrete type within the same {$what} +hir_analysis_lifetimes_or_bounds_mismatch_on_trait = + lifetime parameters or bounds on {$item_kind} `{$ident}` do not match the trait declaration + .label = lifetimes do not match {$item_kind} in trait + .generics_label = lifetimes in impl do not match this {$item_kind} in trait + .where_label = this `where` clause might not match the one in the trait + .bounds_label = this bound might be missing in the impl + +hir_analysis_linkage_type = + invalid type for variable with `#[linkage]` attribute + +hir_analysis_main_function_async = `main` function is not allowed to be `async` + .label = `main` function is not allowed to be `async` + +hir_analysis_main_function_generic_parameters = `main` function is not allowed to have generic parameters + .label = `main` cannot have generic parameters + +hir_analysis_main_function_return_type_generic = `main` function return type is not allowed to have generic parameters hir_analysis_manual_implementation = manual implementations of `{$trait_name}` are experimental .label = manual implementations of `{$trait_name}` are experimental .help = add `#![feature(unboxed_closures)]` to the crate attributes to enable -hir_analysis_substs_on_overridden_impl = could not resolve substs on overridden impl +hir_analysis_missing_one_of_trait_item = not all trait items implemented, missing one of: `{$missing_items_msg}` + .label = missing one of `{$missing_items_msg}` in implementation + .note = required because of this annotation -hir_analysis_trait_object_declared_with_no_traits = - at least one trait is required for an object type - .alias_span = this alias does not contain a trait +hir_analysis_missing_tilde_const = missing `~const` qualifier for specialization + +hir_analysis_missing_trait_item = not all trait items implemented, missing: `{$missing_items_msg}` + .label = missing `{$missing_items_msg}` in implementation + +hir_analysis_missing_trait_item_label = `{$item}` from trait + +hir_analysis_missing_trait_item_suggestion = implement the missing item: `{$snippet}` + +hir_analysis_missing_trait_item_unstable = not all trait items implemented, missing: `{$missing_item_name}` + .note = default implementation of `{$missing_item_name}` is unstable + .some_note = use of unstable library feature '{$feature}': {$r} + .none_note = use of unstable library feature '{$feature}' hir_analysis_missing_type_params = the type {$parameterCount -> @@ -95,98 +162,35 @@ hir_analysis_missing_type_params = } to {$parameters} .note = because of the default `Self` reference, type parameters must be specified on object types -hir_analysis_copy_impl_on_type_with_dtor = - the trait `Copy` cannot be implemented for this type; the type has a destructor - .label = `Copy` not allowed on types with destructors - hir_analysis_multiple_relaxed_default_bounds = type parameter has more than one relaxed default bound, only one is supported -hir_analysis_copy_impl_on_non_adt = - the trait `Copy` cannot be implemented for this type - .label = type is not a structure or enumeration - -hir_analysis_const_impl_for_non_const_trait = - const `impl` for trait `{$trait_name}` which is not marked with `#[const_trait]` - .suggestion = mark `{$trait_name}` as const - .note = marking a trait with `#[const_trait]` ensures all default method bodies are `const` - .adding = adding a non-const method body in the future would be a breaking change - -hir_analysis_const_bound_for_non_const_trait = - ~const can only be applied to `#[const_trait]` traits - -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_linkage_type = - invalid type for variable with `#[linkage]` attribute - -hir_analysis_auto_deref_reached_recursion_limit = reached the recursion limit while auto-dereferencing `{$ty}` - .label = deref recursion limit reached - .help = consider increasing the recursion limit by adding a `#![recursion_limit = "{$suggested_limit}"]` attribute to your crate (`{$crate_name}`) - -hir_analysis_where_clause_on_main = `main` function is not allowed to have a `where` clause - .label = `main` cannot have a `where` clause - -hir_analysis_track_caller_on_main = `main` function is not allowed to be `#[track_caller]` - .suggestion = remove this annotation - -hir_analysis_target_feature_on_main = `main` function is not allowed to have `#[target_feature]` - -hir_analysis_start_not_track_caller = `start` is not allowed to be `#[track_caller]` - .label = `start` is not allowed to be `#[track_caller]` - -hir_analysis_start_not_target_feature = `start` is not allowed to have `#[target_feature]` - .label = `start` is not allowed to have `#[target_feature]` - -hir_analysis_start_not_async = `start` is not allowed to be `async` - .label = `start` is not allowed to be `async` - -hir_analysis_start_function_where = start function is not allowed to have a `where` clause - .label = start function cannot have a `where` clause - -hir_analysis_start_function_parameters = start function is not allowed to have type parameters - .label = start function cannot have type parameters - -hir_analysis_main_function_return_type_generic = `main` function return type is not allowed to have generic parameters +hir_analysis_must_be_name_of_associated_function = must be a name of an associated function -hir_analysis_main_function_async = `main` function is not allowed to be `async` - .label = `main` function is not allowed to be `async` +hir_analysis_must_implement_not_function = not a function -hir_analysis_main_function_generic_parameters = `main` function is not allowed to have generic parameters - .label = `main` cannot have generic parameters +hir_analysis_must_implement_not_function_note = all `#[rustc_must_implement_one_of]` arguments must be associated function names -hir_analysis_variadic_function_compatible_convention = C-variadic function must have a compatible calling convention, like {$conventions} - .label = C-variadic function must have a compatible calling convention +hir_analysis_must_implement_not_function_span_note = required by this annotation -hir_analysis_cannot_capture_late_bound_ty_in_anon_const = - cannot capture late-bound type parameter in a constant - .label = parameter defined here +hir_analysis_must_implement_one_of_attribute = the `#[rustc_must_implement_one_of]` attribute must be used with at least 2 args -hir_analysis_cannot_capture_late_bound_const_in_anon_const = - cannot capture late-bound const parameter in a constant - .label = parameter defined here +hir_analysis_paren_sugar_attribute = the `#[rustc_paren_sugar]` attribute is a temporary means of controlling which traits can use parenthetical notation + .help = add `#![feature(unboxed_closures)]` to the crate attributes to use it -hir_analysis_variances_of = {$variances_of} +hir_analysis_parenthesized_fn_trait_expansion = + parenthesized trait syntax expands to `{$expanded_type}` hir_analysis_pass_to_variadic_function = can't pass `{$ty}` to variadic function .suggestion = cast the value to `{$cast_ty}` .help = cast the value to `{$cast_ty}` -hir_analysis_cast_thin_pointer_to_fat_pointer = cannot cast thin pointer `{$expr_ty}` to fat pointer `{$cast_ty}` - -hir_analysis_invalid_union_field = - field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union - .note = union fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>` - -hir_analysis_invalid_union_field_sugg = - wrap the field type in `ManuallyDrop<...>` +hir_analysis_placeholder_not_allowed_item_signatures = the placeholder `_` is not allowed within types on item signatures for {$kind} + .label = not allowed in type signatures -hir_analysis_return_type_notation_on_non_rpitit = - return type notation used on function that is not `async` and does not return `impl Trait` - .note = function returns `{$ty}`, which is not compatible with associated type return bounds - .label = this function must be `async` or return `impl Trait` +hir_analysis_return_type_notation_conflicting_bound = + ambiguous associated function `{$assoc_name}` for `{$ty_name}` + .note = `{$assoc_name}` is declared in two supertraits: `{$first_bound}` and `{$second_bound}` hir_analysis_return_type_notation_equality_bound = return type notation is not allowed to use type equality @@ -194,100 +198,96 @@ hir_analysis_return_type_notation_equality_bound = hir_analysis_return_type_notation_missing_method = cannot find associated function `{$assoc_name}` for `{$ty_name}` -hir_analysis_return_type_notation_conflicting_bound = - ambiguous associated function `{$assoc_name}` for `{$ty_name}` - .note = `{$assoc_name}` is declared in two supertraits: `{$first_bound}` and `{$second_bound}` - -hir_analysis_placeholder_not_allowed_item_signatures = the placeholder `_` is not allowed within types on item signatures for {$kind} - .label = not allowed in type signatures - -hir_analysis_associated_type_trait_uninferred_generic_params = cannot use the associated type of a trait with uninferred generic parameters - .suggestion = use a fully qualified path with inferred lifetimes - -hir_analysis_associated_type_trait_uninferred_generic_params_multipart_suggestion = use a fully qualified path with explicit lifetimes - -hir_analysis_enum_discriminant_overflowed = enum discriminant overflowed - .label = overflowed on value after {$discr} - .note = explicitly set `{$item_name} = {$wrapped_discr}` if that is desired outcome - -hir_analysis_paren_sugar_attribute = the `#[rustc_paren_sugar]` attribute is a temporary means of controlling which traits can use parenthetical notation - .help = add `#![feature(unboxed_closures)]` to the crate attributes to use it - -hir_analysis_must_implement_one_of_attribute = the `#[rustc_must_implement_one_of]` attribute must be used with at least 2 args - -hir_analysis_must_be_name_of_associated_function = must be a name of an associated function +hir_analysis_return_type_notation_on_non_rpitit = + return type notation used on function that is not `async` and does not return `impl Trait` + .note = function returns `{$ty}`, which is not compatible with associated type return bounds + .label = this function must be `async` or return `impl Trait` -hir_analysis_function_not_have_default_implementation = function doesn't have a default implementation - .note = required by this annotation +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_must_implement_not_function = not a function +hir_analysis_simd_ffi_highly_experimental = use of SIMD type{$snip} in FFI is highly experimental and may result in invalid code + .help = add `#![feature(simd_ffi)]` to the crate attributes to enable -hir_analysis_must_implement_not_function_span_note = required by this annotation +hir_analysis_specialization_trait = implementing `rustc_specialization_trait` traits is unstable + .help = add `#![feature(min_specialization)]` to the crate attributes to enable -hir_analysis_must_implement_not_function_note = all `#[rustc_must_implement_one_of]` arguments must be associated function names +hir_analysis_start_function_parameters = start function is not allowed to have type parameters + .label = start function cannot have type parameters -hir_analysis_function_not_found_in_trait = function not found in this trait +hir_analysis_start_function_where = start function is not allowed to have a `where` clause + .label = start function cannot have a `where` clause -hir_analysis_functions_names_duplicated = functions names are duplicated - .note = all `#[rustc_must_implement_one_of]` arguments must be unique +hir_analysis_start_not_async = `start` is not allowed to be `async` + .label = `start` is not allowed to be `async` -hir_analysis_simd_ffi_highly_experimental = use of SIMD type{$snip} in FFI is highly experimental and may result in invalid code - .help = add `#![feature(simd_ffi)]` to the crate attributes to enable +hir_analysis_start_not_target_feature = `start` is not allowed to have `#[target_feature]` + .label = `start` is not allowed to have `#[target_feature]` -hir_analysis_impl_not_marked_default = `{$ident}` specializes an item from a parent `impl`, but that item is not marked `default` - .label = cannot specialize default item `{$ident}` - .ok_label = parent `impl` is here - .note = to specialize, `{$ident}` in the parent `impl` must be marked `default` +hir_analysis_start_not_track_caller = `start` is not allowed to be `#[track_caller]` + .label = `start` is not allowed to be `#[track_caller]` -hir_analysis_impl_not_marked_default_err = `{$ident}` specializes an item from a parent `impl`, but that item is not marked `default` - .note = parent implementation is in crate `{$cname}` +hir_analysis_static_specialize = cannot specialize on `'static` lifetime -hir_analysis_missing_trait_item = not all trait items implemented, missing: `{$missing_items_msg}` - .label = missing `{$missing_items_msg}` in implementation +hir_analysis_substs_on_overridden_impl = could not resolve substs on overridden impl -hir_analysis_missing_trait_item_suggestion = implement the missing item: `{$snippet}` +hir_analysis_target_feature_on_main = `main` function is not allowed to have `#[target_feature]` -hir_analysis_missing_trait_item_label = `{$item}` from trait +hir_analysis_too_large_static = extern static is too large for the current architecture -hir_analysis_missing_one_of_trait_item = not all trait items implemented, missing one of: `{$missing_items_msg}` - .label = missing one of `{$missing_items_msg}` in implementation - .note = required because of this annotation +hir_analysis_track_caller_on_main = `main` function is not allowed to be `#[track_caller]` + .suggestion = remove this annotation -hir_analysis_missing_trait_item_unstable = not all trait items implemented, missing: `{$missing_item_name}` - .note = default implementation of `{$missing_item_name}` is unstable - .some_note = use of unstable library feature '{$feature}': {$r} - .none_note = use of unstable library feature '{$feature}' +hir_analysis_trait_object_declared_with_no_traits = + at least one trait is required for an object type + .alias_span = this alias does not contain a trait hir_analysis_transparent_enum_variant = transparent enum needs exactly one variant, but has {$number} .label = needs exactly one variant, but has {$number} .many_label = too many variants in `{$path}` .multi_label = variant here -hir_analysis_transparent_non_zero_sized_enum = the variant of a transparent {$desc} needs at most one non-zero-sized field, but has {$field_count} +hir_analysis_transparent_non_zero_sized = transparent {$desc} needs at most one non-zero-sized field, but has {$field_count} .label = needs at most one non-zero-sized field, but has {$field_count} .labels = this field is non-zero-sized -hir_analysis_transparent_non_zero_sized = transparent {$desc} needs at most one non-zero-sized field, but has {$field_count} +hir_analysis_transparent_non_zero_sized_enum = the variant of a transparent {$desc} needs at most one non-zero-sized field, but has {$field_count} .label = needs at most one non-zero-sized field, but has {$field_count} .labels = this field is non-zero-sized -hir_analysis_too_large_static = extern static is too large for the current architecture +hir_analysis_typeof_reserved_keyword_used = + `typeof` is a reserved keyword but unimplemented + .suggestion = consider replacing `typeof(...)` with an actual type + .label = reserved keyword -hir_analysis_specialization_trait = implementing `rustc_specialization_trait` traits is unstable - .help = add `#![feature(min_specialization)]` to the crate attributes to enable +hir_analysis_unconstrained_opaque_type = unconstrained opaque type + .note = `{$name}` must be used in combination with a concrete type within the same {$what} -hir_analysis_closure_implicit_hrtb = implicit types in closure signatures are forbidden when `for<...>` is present - .label = `for<...>` is here +hir_analysis_unrecognized_atomic_operation = + unrecognized atomic operation function: `{$op}` + .label = unrecognized atomic operation -hir_analysis_empty_specialization = specialization impl does not specialize any associated items - .note = impl is a specialization of this impl +hir_analysis_unrecognized_intrinsic_function = + unrecognized intrinsic function: `{$name}` + .label = unrecognized intrinsic -hir_analysis_const_specialize = cannot specialize on const impl with non-const impl +hir_analysis_value_of_associated_struct_already_specified = + the value of the associated type `{$item_name}` (from trait `{$def_path}`) is already specified + .label = re-bound here + .previous_bound_label = `{$item_name}` bound here first -hir_analysis_static_specialize = cannot specialize on `'static` lifetime +hir_analysis_variadic_function_compatible_convention = C-variadic function must have a compatible calling convention, like {$conventions} + .label = C-variadic function must have a compatible calling convention -hir_analysis_missing_tilde_const = missing `~const` qualifier for specialization +hir_analysis_variances_of = {$variances_of} -hir_analysis_drop_impl_negative = negative `Drop` impls are not supported +hir_analysis_where_clause_on_main = `main` function is not allowed to have a `where` clause + .label = `main` cannot have a `where` clause -hir_analysis_drop_impl_reservation = reservation `Drop` impls are not supported +hir_analysis_wrong_number_of_generic_arguments_to_intrinsic = + intrinsic has wrong number of {$descr} parameters: found {$found}, expected {$expected} + .label = expected {$expected} {$descr} {$expected -> + [one] parameter + *[other] parameters + } diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 5fb06cf9465..3d78ea9aa9b 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -239,7 +239,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { var: ty::BoundVar::from_u32(index), kind: ty::BrNamed(def_id, name), }; - tcx.mk_re_late_bound(debruijn, br) + ty::Region::new_late_bound(tcx, debruijn, br) } Some(rbv::ResolvedArg::EarlyBound(def_id)) => { @@ -247,12 +247,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let item_def_id = tcx.hir().ty_param_owner(def_id.expect_local()); let generics = tcx.generics_of(item_def_id); let index = generics.param_def_id_to_index[&def_id]; - tcx.mk_re_early_bound(ty::EarlyBoundRegion { def_id, index, name }) + ty::Region::new_early_bound(tcx, ty::EarlyBoundRegion { def_id, index, name }) } Some(rbv::ResolvedArg::Free(scope, id)) => { let name = lifetime_name(id.expect_local()); - tcx.mk_re_free(scope, ty::BrNamed(id, name)) + ty::Region::new_free(tcx, scope, ty::BrNamed(id, name)) // (*) -- not late-bound, won't change } @@ -269,7 +269,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // elision. `resolve_lifetime` should have // reported an error in this case -- but if // not, let's error out. - tcx.mk_re_error_with_message( + ty::Region::new_error_with_message( + tcx, lifetime.ident.span, "unelided lifetime in signature", ) @@ -485,7 +486,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { debug!(?param, "unelided lifetime in signature"); // This indicates an illegal lifetime in a non-assoc-trait position - tcx.mk_re_error_with_message( + ty::Region::new_error_with_message( + tcx, self.span, "unelided lifetime in signature", ) @@ -1159,7 +1161,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // those that do. self.one_bound_for_assoc_type( || traits::supertraits(tcx, trait_ref), - trait_ref.print_only_trait_path(), + trait_ref.skip_binder().print_only_trait_name(), binding.item_name, path_span, match binding.kind { @@ -1219,15 +1221,15 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let substs = candidate.skip_binder().substs.extend_to(tcx, assoc_item.def_id, |param, _| { let subst = match param.kind { - GenericParamDefKind::Lifetime => tcx - .mk_re_late_bound( - ty::INNERMOST, - ty::BoundRegion { - var: ty::BoundVar::from_usize(num_bound_vars), - kind: ty::BoundRegionKind::BrNamed(param.def_id, param.name), - }, - ) - .into(), + GenericParamDefKind::Lifetime => ty::Region::new_late_bound( + tcx, + ty::INNERMOST, + ty::BoundRegion { + var: ty::BoundVar::from_usize(num_bound_vars), + kind: ty::BoundRegionKind::BrNamed(param.def_id, param.name), + }, + ) + .into(), GenericParamDefKind::Type { .. } => tcx .mk_bound( ty::INNERMOST, @@ -1278,7 +1280,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // params (and trait ref's late bound params). This logic is very similar to // `Predicate::subst_supertrait`, and it's no coincidence why. let shifted_output = tcx.shift_bound_var_indices(num_bound_vars, output); - let subst_output = ty::EarlyBinder(shifted_output).subst(tcx, substs); + let subst_output = ty::EarlyBinder::bind(shifted_output).subst(tcx, substs); let bound_vars = tcx.late_bound_vars(binding.hir_id); ty::Binder::bind_with_vars(subst_output, bound_vars) @@ -1804,7 +1806,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } else { err.emit() }; - tcx.mk_re_error(e) + ty::Region::new_error(tcx, e) }) } }) 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 8bf1e0e84a4..31b89525f15 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -25,6 +25,7 @@ use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _; use rustc_trait_selection::traits::{ self, ObligationCause, ObligationCauseCode, ObligationCtxt, Reveal, }; +use std::borrow::Cow; use std::iter; /// Checks that a method from an impl conforms to the signature of @@ -471,7 +472,8 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for RemapLateBound<'_, 'tcx> { fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { if let ty::ReFree(fr) = *r { - self.tcx.mk_re_free( + ty::Region::new_free( + self.tcx, fr.scope, self.mapping.get(&fr.bound_region).copied().unwrap_or(fr.bound_region), ) @@ -684,7 +686,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( &cause, hir.get_if_local(impl_m.def_id) .and_then(|node| node.fn_decl()) - .map(|decl| (decl.output.span(), "return type in trait".to_owned())), + .map(|decl| (decl.output.span(), Cow::from("return type in trait"))), Some(infer::ValuePairs::Terms(ExpectedFound { expected: trait_return_ty.into(), found: impl_return_ty.into(), @@ -785,23 +787,23 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( } let Some(ty::ReEarlyBound(e)) = map.get(®ion.into()).map(|r| r.expect_region().kind()) else { - return tcx.mk_re_error_with_message(return_span, "expected ReFree to map to ReEarlyBound") + return ty::Region::new_error_with_message(tcx, return_span, "expected ReFree to map to ReEarlyBound") }; - tcx.mk_re_early_bound(ty::EarlyBoundRegion { + ty::Region::new_early_bound(tcx, ty::EarlyBoundRegion { def_id: e.def_id, name: e.name, index: (e.index as usize - num_trait_substs + num_impl_substs) as u32, }) }); debug!(%ty); - collected_tys.insert(def_id, ty::EarlyBinder(ty)); + collected_tys.insert(def_id, ty::EarlyBinder::bind(ty)); } Err(err) => { let reported = tcx.sess.delay_span_bug( return_span, format!("could not fully resolve: {ty} => {err:?}"), ); - collected_tys.insert(def_id, ty::EarlyBinder(tcx.ty_error(reported))); + collected_tys.insert(def_id, ty::EarlyBinder::bind(tcx.ty_error(reported))); } } } @@ -901,7 +903,7 @@ fn report_trait_method_mismatch<'tcx>( if trait_m.fn_has_self_parameter => { let ty = trait_sig.inputs()[0]; - let sugg = match ExplicitSelf::determine(ty, |_| ty == impl_trait_ref.self_ty()) { + let sugg = match ExplicitSelf::determine(ty, |ty| ty == impl_trait_ref.self_ty()) { ExplicitSelf::ByValue => "self".to_owned(), ExplicitSelf::ByReference(_, hir::Mutability::Not) => "&self".to_owned(), ExplicitSelf::ByReference(_, hir::Mutability::Mut) => "&mut self".to_owned(), @@ -963,7 +965,7 @@ fn report_trait_method_mismatch<'tcx>( infcx.err_ctxt().note_type_err( &mut diag, &cause, - trait_err_span.map(|sp| (sp, "type in trait".to_owned())), + trait_err_span.map(|sp| (sp, Cow::from("type in trait"))), Some(infer::ValuePairs::Sigs(ExpectedFound { expected: trait_sig, found: impl_sig })), terr, false, @@ -1731,7 +1733,7 @@ pub(super) fn compare_impl_const_raw( infcx.err_ctxt().note_type_err( &mut diag, &cause, - trait_c_span.map(|span| (span, "type in trait".to_owned())), + trait_c_span.map(|span| (span, Cow::from("type in trait"))), Some(infer::ValuePairs::Terms(ExpectedFound { expected: trait_ty.into(), found: impl_ty.into(), @@ -1932,7 +1934,8 @@ pub(super) fn check_type_bounds<'tcx>( let kind = ty::BoundRegionKind::BrNamed(param.def_id, param.name); let bound_var = ty::BoundVariableKind::Region(kind); bound_vars.push(bound_var); - tcx.mk_re_late_bound( + ty::Region::new_late_bound( + tcx, ty::INNERMOST, ty::BoundRegion { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind }, ) diff --git a/compiler/rustc_hir_analysis/src/check/dropck.rs b/compiler/rustc_hir_analysis/src/check/dropck.rs index e0ba255cc06..13d1abe2a65 100644 --- a/compiler/rustc_hir_analysis/src/check/dropck.rs +++ b/compiler/rustc_hir_analysis/src/check/dropck.rs @@ -128,7 +128,7 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>( // We don't need to normalize this param-env or anything, since we're only // substituting it with free params, so no additional param-env normalization // can occur on top of what has been done in the param_env query itself. - let param_env = ty::EarlyBinder(tcx.param_env(adt_def_id)) + let param_env = ty::EarlyBinder::bind(tcx.param_env(adt_def_id)) .subst(tcx, adt_to_impl_substs) .with_constness(tcx.constness(drop_impl_def_id)); @@ -183,7 +183,7 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>( } RegionResolutionError::SubSupConflict(_, _, _, a, _, b, _) => format!("{b}: {a}"), RegionResolutionError::UpperBoundUniverseConflict(a, _, _, _, b) => { - format!("{b}: {a}", a = tcx.mk_re_var(a)) + format!("{b}: {a}", a = ty::Region::new_var(tcx, a)) } }; guar = Some( diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index e8785235c83..1f18017f00b 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -121,10 +121,11 @@ pub fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: DefId) -> hir if has_safe_attr != is_in_list { tcx.sess.struct_span_err( tcx.def_span(intrinsic_id), - DiagnosticMessage::Str(format!( - "intrinsic safety mismatch between list of intrinsics within the compiler and core library intrinsics for intrinsic `{}`", - tcx.item_name(intrinsic_id) - ))).emit(); + DiagnosticMessage::from(format!( + "intrinsic safety mismatch between list of intrinsics within the compiler and core library intrinsics for intrinsic `{}`", + tcx.item_name(intrinsic_id) + ) + )).emit(); } is_in_list @@ -144,11 +145,13 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { ]); let mk_va_list_ty = |mutbl| { tcx.lang_items().va_list().map(|did| { - let region = tcx.mk_re_late_bound( + let region = ty::Region::new_late_bound( + tcx, ty::INNERMOST, ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(None) }, ); - let env_region = tcx.mk_re_late_bound( + let env_region = ty::Region::new_late_bound( + tcx, ty::INNERMOST, ty::BoundRegion { var: ty::BoundVar::from_u32(1), kind: ty::BrEnv }, ); @@ -392,7 +395,12 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { let br = ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(None) }; ( 1, - vec![tcx.mk_imm_ref(tcx.mk_re_late_bound(ty::INNERMOST, br), param(0))], + vec![ + tcx.mk_imm_ref( + ty::Region::new_late_bound(tcx, ty::INNERMOST, br), + param(0), + ), + ], tcx.mk_projection(discriminant_def_id, tcx.mk_substs(&[param(0).into()])), ) } @@ -442,7 +450,8 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { sym::raw_eq => { let br = ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(None) }; - let param_ty = tcx.mk_imm_ref(tcx.mk_re_late_bound(ty::INNERMOST, br), param(0)); + let param_ty = + tcx.mk_imm_ref(ty::Region::new_late_bound(tcx, ty::INNERMOST, br), param(0)); (1, vec![param_ty; 2], tcx.types.bool) } diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index b403ee96b42..fff417fcb29 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -556,11 +556,14 @@ fn gather_gat_bounds<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>( // Same for the region. In our example, 'a corresponds // to the 'me parameter. let region_param = gat_generics.param_at(*region_a_idx, tcx); - let region_param = tcx.mk_re_early_bound(ty::EarlyBoundRegion { - def_id: region_param.def_id, - index: region_param.index, - name: region_param.name, - }); + let region_param = ty::Region::new_early_bound( + tcx, + ty::EarlyBoundRegion { + def_id: region_param.def_id, + index: region_param.index, + name: region_param.name, + }, + ); // The predicate we expect to see. (In our example, // `Self: 'me`.) let clause = ty::PredicateKind::Clause(ty::Clause::TypeOutlives( @@ -593,18 +596,24 @@ fn gather_gat_bounds<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>( debug!("required clause: {region_a} must outlive {region_b}"); // Translate into the generic parameters of the GAT. let region_a_param = gat_generics.param_at(*region_a_idx, tcx); - let region_a_param = tcx.mk_re_early_bound(ty::EarlyBoundRegion { - def_id: region_a_param.def_id, - index: region_a_param.index, - name: region_a_param.name, - }); + let region_a_param = ty::Region::new_early_bound( + tcx, + ty::EarlyBoundRegion { + def_id: region_a_param.def_id, + index: region_a_param.index, + name: region_a_param.name, + }, + ); // Same for the region. let region_b_param = gat_generics.param_at(*region_b_idx, tcx); - let region_b_param = tcx.mk_re_early_bound(ty::EarlyBoundRegion { - def_id: region_b_param.def_id, - index: region_b_param.index, - name: region_b_param.name, - }); + let region_b_param = ty::Region::new_early_bound( + tcx, + ty::EarlyBoundRegion { + def_id: region_b_param.def_id, + index: region_b_param.index, + name: region_b_param.name, + }, + ); // The predicate we expect to see. let clause = ty::PredicateKind::Clause(ty::Clause::RegionOutlives( ty::OutlivesPredicate(region_a_param, region_b_param), @@ -1398,7 +1407,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id } let mut param_count = CountParams::default(); let has_region = pred.visit_with(&mut param_count).is_break(); - let substituted_pred = ty::EarlyBinder(pred).subst(tcx, substs); + let substituted_pred = ty::EarlyBinder::bind(pred).subst(tcx, substs); // Don't check non-defaulted params, dependent defaults (including lifetimes) // or preds with multiple params. if substituted_pred.has_non_region_param() || param_count.params.len() > 1 || has_region diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index ca0d5509c57..2f7d465839c 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -440,7 +440,7 @@ impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> { self.tcx.replace_late_bound_regions_uncached( poly_trait_ref, |_| { - self.tcx.mk_re_early_bound(ty::EarlyBoundRegion { + ty::Region::new_early_bound(self.tcx, ty::EarlyBoundRegion { def_id: item_def_id, index: 0, name: Symbol::intern(<_name), @@ -1124,7 +1124,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<ty::PolyFnSig< bug!("unexpected sort of node in fn_sig(): {:?}", x); } }; - ty::EarlyBinder(output) + ty::EarlyBinder::bind(output) } fn infer_return_ty_for_fn_sig<'tcx>( @@ -1312,7 +1312,7 @@ fn impl_trait_ref( check_impl_constness(tcx, impl_.constness, ast_trait_ref), ) }) - .map(ty::EarlyBinder) + .map(ty::EarlyBinder::bind) } fn check_impl_constness( diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index 948b903e509..b92d561fb86 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -86,7 +86,7 @@ pub(super) fn explicit_item_bounds( Some(ty::ImplTraitInTraitData::Trait { opaque_def_id, .. }) => { let item = tcx.hir().get_by_def_id(opaque_def_id.expect_local()).expect_item(); let opaque_ty = item.expect_opaque_ty(); - return ty::EarlyBinder(opaque_type_bounds( + return ty::EarlyBinder::bind(opaque_type_bounds( tcx, opaque_def_id.expect_local(), opaque_ty.bounds, @@ -124,7 +124,7 @@ pub(super) fn explicit_item_bounds( } _ => bug!("item_bounds called on {:?}", def_id), }; - ty::EarlyBinder(bounds) + ty::EarlyBinder::bind(bounds) } pub(super) fn item_bounds( diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index e5b5dae551e..70d950eddd8 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -306,11 +306,14 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen let Some(dup_index) = generics.param_def_id_to_index(tcx, dup_def) else { bug!() }; - let dup_region = tcx.mk_re_early_bound(ty::EarlyBoundRegion { - def_id: dup_def, - index: dup_index, - name: duplicate.name.ident().name, - }); + let dup_region = ty::Region::new_early_bound( + tcx, + ty::EarlyBoundRegion { + def_id: dup_def, + index: dup_index, + name: duplicate.name.ident().name, + }, + ); predicates.push(( ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::RegionOutlives( ty::OutlivesPredicate(orig_region, dup_region), diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index 8e082d3c532..65ab00fda81 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -323,7 +323,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty return map[&assoc_item.trait_item_def_id.unwrap()]; } Err(_) => { - return ty::EarlyBinder(tcx.ty_error_with_message( + return ty::EarlyBinder::bind(tcx.ty_error_with_message( DUMMY_SP, "Could not collect return position impl trait in trait tys", )); @@ -497,7 +497,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty bug!("unexpected sort of node in type_of(): {:?}", x); } }; - ty::EarlyBinder(output) + ty::EarlyBinder::bind(output) } fn infer_placeholder_type<'a>( diff --git a/compiler/rustc_hir_analysis/src/outlives/explicit.rs b/compiler/rustc_hir_analysis/src/outlives/explicit.rs index 357deb07b8f..7ce48fe1c01 100644 --- a/compiler/rustc_hir_analysis/src/outlives/explicit.rs +++ b/compiler/rustc_hir_analysis/src/outlives/explicit.rs @@ -68,7 +68,7 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> { } } - ty::EarlyBinder(required_predicates) + ty::EarlyBinder::bind(required_predicates) }) } } diff --git a/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs index 0cd2fc1aa29..71dca918fc5 100644 --- a/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs +++ b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs @@ -68,12 +68,13 @@ pub(super) fn infer_predicates( // Therefore mark `predicates_added` as true and which will ensure // we walk the crates again and re-calculate predicates for all // items. - let item_predicates_len: usize = - global_inferred_outlives.get(&item_did.to_def_id()).map_or(0, |p| p.0.len()); + let item_predicates_len: usize = global_inferred_outlives + .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; global_inferred_outlives - .insert(item_did.to_def_id(), ty::EarlyBinder(item_required_predicates)); + .insert(item_did.to_def_id(), ty::EarlyBinder::bind(item_required_predicates)); } } @@ -137,7 +138,9 @@ fn insert_required_predicates_to_be_wf<'tcx>( // 'a` holds for `Foo`. debug!("Adt"); if let Some(unsubstituted_predicates) = global_inferred_outlives.get(&def.did()) { - for (unsubstituted_predicate, &span) in &unsubstituted_predicates.0 { + for (unsubstituted_predicate, &span) in + unsubstituted_predicates.as_ref().skip_binder() + { // `unsubstituted_predicate` is `U: 'b` in the // example above. So apply the substitution to // get `T: 'a` (or `predicate`): @@ -251,7 +254,7 @@ fn check_explicit_predicates<'tcx>( ); let explicit_predicates = explicit_map.explicit_predicates_of(tcx, def_id); - for (outlives_predicate, &span) in &explicit_predicates.0 { + for (outlives_predicate, &span) in explicit_predicates.as_ref().skip_binder() { debug!("outlives_predicate = {:?}", &outlives_predicate); // Careful: If we are inferring the effects of a `dyn Trait<..>` diff --git a/compiler/rustc_hir_analysis/src/outlives/mod.rs b/compiler/rustc_hir_analysis/src/outlives/mod.rs index a8596c707f3..2106d6ff07d 100644 --- a/compiler/rustc_hir_analysis/src/outlives/mod.rs +++ b/compiler/rustc_hir_analysis/src/outlives/mod.rs @@ -98,24 +98,27 @@ fn inferred_outlives_crate(tcx: TyCtxt<'_>, (): ()) -> CratePredicatesMap<'_> { let predicates = global_inferred_outlives .iter() .map(|(&def_id, set)| { - let predicates = &*tcx.arena.alloc_from_iter(set.0.iter().filter_map( - |(ty::OutlivesPredicate(kind1, region2), &span)| { - match kind1.unpack() { - GenericArgKind::Type(ty1) => Some(( - ty::Clause::TypeOutlives(ty::OutlivesPredicate(ty1, *region2)), - span, - )), - GenericArgKind::Lifetime(region1) => Some(( - ty::Clause::RegionOutlives(ty::OutlivesPredicate(region1, *region2)), - span, - )), - GenericArgKind::Const(_) => { - // Generic consts don't impose any constraints. - None + let predicates = + &*tcx.arena.alloc_from_iter(set.as_ref().skip_binder().iter().filter_map( + |(ty::OutlivesPredicate(kind1, region2), &span)| { + match kind1.unpack() { + GenericArgKind::Type(ty1) => Some(( + ty::Clause::TypeOutlives(ty::OutlivesPredicate(ty1, *region2)), + span, + )), + GenericArgKind::Lifetime(region1) => Some(( + ty::Clause::RegionOutlives(ty::OutlivesPredicate( + region1, *region2, + )), + span, + )), + GenericArgKind::Const(_) => { + // Generic consts don't impose any constraints. + None + } } - } - }, - )); + }, + )); (def_id, predicates) }) .collect(); diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl index 4a669e3f8b8..aab432eee57 100644 --- a/compiler/rustc_hir_typeck/messages.ftl +++ b/compiler/rustc_hir_typeck/messages.ftl @@ -1,92 +1,94 @@ -hir_typeck_field_multiply_specified_in_initializer = - field `{$ident}` specified more than once - .label = used more than once - .previous_use_label = first use of `{$ident}` +hir_typeck_add_missing_parentheses_in_range = you must surround the range in parentheses to call its `{$func_name}` function -hir_typeck_functional_record_update_on_non_struct = - functional record update syntax requires a struct +hir_typeck_add_return_type_add = try adding a return type -hir_typeck_return_stmt_outside_of_fn_body = - return statement outside of function body - .encl_body_label = the return is part of this body... - .encl_fn_label = ...not the enclosing function body +hir_typeck_add_return_type_missing_here = a return type might be missing here -hir_typeck_yield_expr_outside_of_generator = - yield expression outside of generator literal +hir_typeck_address_of_temporary_taken = cannot take address of a temporary + .label = temporary value -hir_typeck_struct_expr_non_exhaustive = - cannot create non-exhaustive {$what} using struct expression +hir_typeck_arg_mismatch_indeterminate = argument type mismatch was detected, but rustc had trouble determining where + .note = we would appreciate a bug report: https://github.com/rust-lang/rust/issues/new -hir_typeck_method_call_on_unknown_type = - the type of this value must be known to call a method on a raw pointer on it +hir_typeck_candidate_trait_note = `{$trait_name}` defines an item `{$item_name}`{$action_or_ty -> + [NONE] {""} + [implement] , perhaps you need to implement it + *[other] , perhaps you need to restrict type parameter `{$action_or_ty}` with it +} -hir_typeck_address_of_temporary_taken = cannot take address of a temporary - .label = temporary value +hir_typeck_const_select_must_be_const = this argument must be a `const fn` + .help = consult the documentation on `const_eval_select` for more information -hir_typeck_add_return_type_add = try adding a return type +hir_typeck_const_select_must_be_fn = this argument must be a function item + .note = expected a function item, found {$ty} + .help = consult the documentation on `const_eval_select` for more information -hir_typeck_add_return_type_missing_here = a return type might be missing here +hir_typeck_convert_to_str = try converting the passed type into a `&str` + +hir_typeck_ctor_is_private = tuple struct constructor `{$def}` is private hir_typeck_expected_default_return_type = expected `()` because of default return type hir_typeck_expected_return_type = expected `{$expected}` because of return type -hir_typeck_missing_parentheses_in_range = can't call method `{$method_name}` on type `{$ty_str}` +hir_typeck_field_multiply_specified_in_initializer = + field `{$ident}` specified more than once + .label = used more than once + .previous_use_label = first use of `{$ident}` -hir_typeck_add_missing_parentheses_in_range = you must surround the range in parentheses to call its `{$func_name}` function +hir_typeck_fru_expr = this expression does not end in a comma... +hir_typeck_fru_expr2 = ... so this is interpreted as a `..` range expression, instead of functional record update syntax +hir_typeck_fru_note = this expression may have been misinterpreted as a `..` range expression +hir_typeck_fru_suggestion = + to set the remaining fields{$expr -> + [NONE]{""} + *[other] {" "}from `{$expr}` + }, separate the last named field with a comma -hir_typeck_lang_start_incorrect_number_params = incorrect number of parameters for the `start` lang item -hir_typeck_lang_start_incorrect_number_params_note_expected_count = the `start` lang item should have four parameters, but found {$found_param_count} +hir_typeck_functional_record_update_on_non_struct = + functional record update syntax requires a struct +hir_typeck_help_set_edition_cargo = set `edition = "{$edition}"` in `Cargo.toml` +hir_typeck_help_set_edition_standalone = pass `--edition {$edition}` to `rustc` hir_typeck_lang_start_expected_sig_note = the `start` lang item should have the signature `fn(fn() -> T, isize, *const *const u8, u8) -> isize` +hir_typeck_lang_start_incorrect_number_params = incorrect number of parameters for the `start` lang item +hir_typeck_lang_start_incorrect_number_params_note_expected_count = the `start` lang item should have four parameters, but found {$found_param_count} + hir_typeck_lang_start_incorrect_param = parameter {$param_num} of the `start` lang item is incorrect .suggestion = change the type from `{$found_ty}` to `{$expected_ty}` hir_typeck_lang_start_incorrect_ret_ty = the return type of the `start` lang item is incorrect .suggestion = change the type from `{$found_ty}` to `{$expected_ty}` -hir_typeck_help_set_edition_cargo = set `edition = "{$edition}"` in `Cargo.toml` -hir_typeck_help_set_edition_standalone = pass `--edition {$edition}` to `rustc` -hir_typeck_note_edition_guide = for more on editions, read https://doc.rust-lang.org/edition-guide - -hir_typeck_convert_to_str = try converting the passed type into a `&str` +hir_typeck_method_call_on_unknown_raw_pointee = + cannot call a method on a raw pointer with an unknown pointee type -hir_typeck_op_trait_generic_params = `{$method_name}` must not have any generic parameters +hir_typeck_missing_parentheses_in_range = can't call method `{$method_name}` on type `{$ty_str}` -hir_typeck_fru_note = this expression may have been misinterpreted as a `..` range expression -hir_typeck_fru_expr = this expression does not end in a comma... -hir_typeck_fru_expr2 = ... so this is interpreted as a `..` range expression, instead of functional record update syntax -hir_typeck_fru_suggestion = - to set the remaining fields{$expr -> - [NONE]{""} - *[other] {" "}from `{$expr}` - }, separate the last named field with a comma +hir_typeck_no_associated_item = no {$item_kind} named `{$item_name}` found for {$ty_prefix} `{$ty_str}`{$trait_missing_method -> + [true] {""} + *[other] {" "}in the current scope +} -hir_typeck_const_select_must_be_const = this argument must be a `const fn` - .help = consult the documentation on `const_eval_select` for more information +hir_typeck_note_edition_guide = for more on editions, read https://doc.rust-lang.org/edition-guide -hir_typeck_const_select_must_be_fn = this argument must be a function item - .note = expected a function item, found {$ty} - .help = consult the documentation on `const_eval_select` for more information +hir_typeck_op_trait_generic_params = `{$method_name}` must not have any generic parameters -hir_typeck_union_pat_multiple_fields = union patterns should have exactly one field -hir_typeck_union_pat_dotdot = `..` cannot be used in union patterns +hir_typeck_return_stmt_outside_of_fn_body = + return statement outside of function body + .encl_body_label = the return is part of this body... + .encl_fn_label = ...not the enclosing function body -hir_typeck_arg_mismatch_indeterminate = argument type mismatch was detected, but rustc had trouble determining where - .note = we would appreciate a bug report: https://github.com/rust-lang/rust/issues/new +hir_typeck_struct_expr_non_exhaustive = + cannot create non-exhaustive {$what} using struct expression hir_typeck_suggest_boxing_note = for more on the distinction between the stack and the heap, read https://doc.rust-lang.org/book/ch15-01-box.html, https://doc.rust-lang.org/rust-by-example/std/box.html, and https://doc.rust-lang.org/std/boxed/index.html hir_typeck_suggest_boxing_when_appropriate = store this in the heap by calling `Box::new` -hir_typeck_no_associated_item = no {$item_kind} named `{$item_name}` found for {$ty_prefix} `{$ty_str}`{$trait_missing_method -> - [true] {""} - *[other] {" "}in the current scope -} +hir_typeck_union_pat_dotdot = `..` cannot be used in union patterns -hir_typeck_candidate_trait_note = `{$trait_name}` defines an item `{$item_name}`{$action_or_ty -> - [NONE] {""} - [implement] , perhaps you need to implement it - *[other] , perhaps you need to restrict type parameter `{$action_or_ty}` with it -} +hir_typeck_union_pat_multiple_fields = union patterns should have exactly one field +hir_typeck_yield_expr_outside_of_generator = + yield expression outside of generator literal diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index 655ab94eb48..4389ad6ef26 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -420,20 +420,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .steal_diagnostic(segment.ident.span, StashKey::CallIntoMethod) { // Try suggesting `foo(a)` -> `a.foo()` if possible. - if let Some(ty) = - self.suggest_call_as_method( - &mut diag, - segment, - arg_exprs, - call_expr, - expected - ) - { - diag.emit(); - return ty; - } else { - diag.emit(); - } + self.suggest_call_as_method( + &mut diag, + segment, + arg_exprs, + call_expr, + expected + ); + diag.emit(); } let err = self.report_invalid_callee(call_expr, callee_expr, callee_ty, arg_exprs); @@ -496,9 +490,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { arg_exprs: &'tcx [hir::Expr<'tcx>], call_expr: &'tcx hir::Expr<'tcx>, expected: Expectation<'tcx>, - ) -> Option<Ty<'tcx>> { + ) { if let [callee_expr, rest @ ..] = arg_exprs { - let callee_ty = self.typeck_results.borrow().expr_ty_adjusted_opt(callee_expr)?; + let Some(callee_ty) = self.typeck_results.borrow().expr_ty_adjusted_opt(callee_expr) else { + return; + }; // First, do a probe with `IsSuggestion(true)` to avoid emitting // any strange errors. If it's successful, then we'll do a true @@ -513,7 +509,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ProbeScope::AllTraits, expected.only_has_type(self), ) else { - return None; + return; }; let pick = self.confirm_method( @@ -525,7 +521,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { segment, ); if pick.illegal_sized_bound.is_some() { - return None; + return; } let up_to_rcvr_span = segment.ident.span.until(callee_expr.span); @@ -567,22 +563,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { sugg, Applicability::MaybeIncorrect, ); - - // Let's check the method fully now - let return_ty = self.check_method_argument_types( - segment.ident.span, - call_expr, - Ok(pick.callee), - rest, - TupleArgumentsFlag::DontTupleArguments, - expected, - ); - - return Some(return_ty); } } - - None } fn report_invalid_callee( diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 08c4082e885..905781ec8f5 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -62,6 +62,7 @@ use rustc_span::{self, BytePos, DesugaringKind, Span}; use rustc_target::spec::abi::Abi; use rustc_trait_selection::infer::InferCtxtExt as _; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _; +use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use rustc_trait_selection::traits::{ self, NormalizeExt, ObligationCause, ObligationCauseCode, ObligationCtxt, }; @@ -144,12 +145,28 @@ impl<'f, 'tcx> Coerce<'f, '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); - if self.use_lub { + + let res = if self.use_lub { at.lub(DefineOpaqueTypes::Yes, b, a) } else { at.sup(DefineOpaqueTypes::Yes, b, a) .map(|InferOk { value: (), obligations }| InferOk { value: a, obligations }) + }; + + // In the new solver, lazy norm may allow us to shallowly equate + // more types, but we emit possibly impossible-to-satisfy obligations. + // Filter these cases out to make sure our coercion is more accurate. + if self.tcx.trait_solver_next() { + if let Ok(res) = &res { + for obligation in &res.obligations { + if !self.predicate_may_hold(&obligation) { + return Err(TypeError::Mismatch); + } + } + } } + + res }) } @@ -791,6 +808,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { G: FnOnce(Ty<'tcx>) -> Vec<Adjustment<'tcx>>, { self.commit_if_ok(|snapshot| { + let outer_universe = self.infcx.universe(); + let result = if let ty::FnPtr(fn_ty_b) = b.kind() && let (hir::Unsafety::Normal, hir::Unsafety::Unsafe) = (fn_ty_a.unsafety(), fn_ty_b.unsafety()) @@ -807,7 +826,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // want the coerced type to be the actual supertype of these two, // but for now, we want to just error to ensure we don't lock // ourselves into a specific behavior with NLL. - self.leak_check(false, snapshot)?; + self.leak_check(outer_universe, Some(snapshot))?; result }) diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index 102a313067f..4222205c841 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -49,8 +49,8 @@ pub struct StructExprNonExhaustive { } #[derive(Diagnostic)] -#[diag(hir_typeck_method_call_on_unknown_type, code = "E0699")] -pub struct MethodCallOnUnknownType { +#[diag(hir_typeck_method_call_on_unknown_raw_pointee, code = "E0699")] +pub struct MethodCallOnUnknownRawPointee { #[primary_span] pub span: Span, } @@ -319,3 +319,11 @@ pub struct CandidateTraitNote { pub item_name: Ident, pub action_or_ty: String, } + +#[derive(Diagnostic)] +#[diag(hir_typeck_ctor_is_private, code = "E0603")] +pub struct CtorIsPrivate { + #[primary_span] + pub span: Span, + pub def: String, +} diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 2fdcd09b9a2..38ddb7e7604 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -1,4 +1,5 @@ use crate::callee::{self, DeferredCallResolution}; +use crate::errors::CtorIsPrivate; use crate::method::{self, MethodCallee, SelfSource}; use crate::rvalue_scopes; use crate::{BreakableCtxt, Diverges, Expectation, FnCtxt, LocalTy, RawTy}; @@ -1207,6 +1208,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match ty.normalized.ty_adt_def() { Some(adt_def) if adt_def.has_ctor() => { let (ctor_kind, ctor_def_id) = adt_def.non_enum_variant().ctor.unwrap(); + // Check the visibility of the ctor. + let vis = tcx.visibility(ctor_def_id); + if !vis.is_accessible_from(tcx.parent_module(hir_id).to_def_id(), tcx) { + tcx.sess + .emit_err(CtorIsPrivate { span, def: tcx.def_path_str(adt_def.did()) }); + } let new_res = Res::Def(DefKind::Ctor(CtorOf::Struct, ctor_kind), ctor_def_id); let user_substs = Self::user_substs_for_adt(ty); user_self_ty = user_substs.user_self_ty; @@ -1379,7 +1386,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // the referenced item. let ty = tcx.type_of(def_id); assert!(!substs.has_escaping_bound_vars()); - assert!(!ty.0.has_escaping_bound_vars()); + assert!(!ty.skip_binder().has_escaping_bound_vars()); let ty_substituted = self.normalize(span, ty.subst(tcx, substs)); if let Some(UserSelfTy { impl_def_id, self_ty }) = user_self_ty { diff --git a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs index 019fb86f55c..fb28233bfb1 100644 --- a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs +++ b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs @@ -122,7 +122,7 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> { self.fcx .need_type_info_err_in_generator(self.kind, span, unresolved_term) - .span_note(yield_data.span, &*note) + .span_note(yield_data.span, note) .emit(); } } else { @@ -269,7 +269,7 @@ pub fn resolve_interior<'a, 'tcx>( }, _ => mk_bound_region(ty::BrAnon(None)), }; - let r = fcx.tcx.mk_re_late_bound(current_depth, br); + let r = ty::Region::new_late_bound(fcx.tcx, current_depth, br); r }); captured_tys.insert(ty).then(|| { @@ -295,7 +295,11 @@ pub fn resolve_interior<'a, 'tcx>( let var = ty::BoundVar::from_usize(bound_vars.len()); bound_vars.push(ty::BoundVariableKind::Region(kind)); counter += 1; - fcx.tcx.mk_re_late_bound(ty::INNERMOST, ty::BoundRegion { var, kind }) + ty::Region::new_late_bound( + fcx.tcx, + ty::INNERMOST, + ty::BoundRegion { var, kind }, + ) }, types: &mut |b| bug!("unexpected bound ty in binder: {b:?}"), consts: &mut |b, ty| bug!("unexpected bound ct in binder: {b:?} {ty}"), @@ -686,7 +690,7 @@ fn check_must_not_suspend_def( // Add optional reason note if let Some(note) = attr.value_str() { // FIXME(guswynn): consider formatting this better - lint.span_note(data.source_span, note.as_str()); + lint.span_note(data.source_span, note.to_string()); } // Add some quick suggestions on what to do diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index ba21edea30b..9f3d35a77dc 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -3,7 +3,7 @@ use super::CandidateSource; use super::MethodError; use super::NoMatchData; -use crate::errors::MethodCallOnUnknownType; +use crate::errors::MethodCallOnUnknownRawPointee; use crate::FnCtxt; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; @@ -438,7 +438,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // so we do a future-compat lint here for the 2015 edition // (see https://github.com/rust-lang/rust/issues/46906) if self.tcx.sess.rust_2018() { - self.tcx.sess.emit_err(MethodCallOnUnknownType { span }); + self.tcx.sess.emit_err(MethodCallOnUnknownRawPointee { span }); } else { self.tcx.struct_span_lint_hir( lint::builtin::TYVAR_BEHIND_RAW_POINTER, diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 8555c20204a..9ee967dc7a9 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -473,6 +473,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut custom_span_label = false; let static_candidates = &mut no_match_data.static_candidates; + + // `static_candidates` may have same candidates appended by + // inherent and extension, which may result in incorrect + // diagnostic. + static_candidates.dedup(); + if !static_candidates.is_empty() { err.note( "found the following associated functions; to be used as methods, \ diff --git a/compiler/rustc_incremental/messages.ftl b/compiler/rustc_incremental/messages.ftl index b760620e3d4..9fa4e0fb27c 100644 --- a/compiler/rustc_incremental/messages.ftl +++ b/compiler/rustc_incremental/messages.ftl @@ -1,118 +1,118 @@ -incremental_unrecognized_depnode = unrecognized `DepNode` variant: {$name} +incremental_assert_loaded = + we asserted that an existing incremental cache directory should be successfully loaded, but it was not -incremental_missing_depnode = missing `DepNode` variant +incremental_assert_not_loaded = + we asserted that the incremental cache should not be loaded, but it was loaded -incremental_missing_if_this_changed = no `#[rustc_if_this_changed]` annotation detected +incremental_assertion_auto = + `except` specified DepNodes that can not be affected for "{$name}": "{$e}" -incremental_no_path = no path from `{$source}` to `{$target}` +incremental_associated_value_expected = expected an associated value -incremental_ok = OK +incremental_associated_value_expected_for = associated value expected for `{$ident}` -incremental_unknown_reuse_kind = unknown cgu-reuse-kind `{$kind}` specified +incremental_canonicalize_path = incremental compilation: error canonicalizing path `{$path}`: {$err} -incremental_missing_query_depgraph = - found CGU-reuse attribute but `-Zquery-dep-graph` was not specified +incremental_cargo_help_1 = + incremental compilation can be disabled by setting the environment variable CARGO_INCREMENTAL=0 (see https://doc.rust-lang.org/cargo/reference/profiles.html#incremental) +incremental_cargo_help_2 = + the entire build directory can be changed to a different filesystem by setting the environment variable CARGO_TARGET_DIR to a different path (see https://doc.rust-lang.org/cargo/reference/config.html#buildtarget-dir) -incremental_malformed_cgu_name = - found malformed codegen unit name `{$user_path}`. codegen units names must always start with the name of the crate (`{$crate_name}` in this case). +incremental_copy_workproduct_to_cache = + error copying object file `{$from}` to incremental directory as `{$to}`: {$err} -incremental_no_module_named = - no module named `{$user_path}` (mangled: {$cgu_name}). available modules: {$cgu_names} +incremental_create_dep_graph = failed to create dependency graph at `{$path}`: {$err} -incremental_field_associated_value_expected = associated value expected for `{$name}` +incremental_create_incr_comp_dir = + could not create incremental compilation {$tag} directory `{$path}`: {$err} -incremental_no_field = no field `{$name}` +incremental_create_lock = + incremental compilation: could not create session directory lock file: {$lock_err} +incremental_create_new = failed to create {$name} at `{$path}`: {$err} -incremental_assertion_auto = - `except` specified DepNodes that can not be affected for "{$name}": "{$e}" +incremental_decode_incr_cache = could not decode incremental cache: {$err} -incremental_undefined_clean_dirty_assertions_item = - clean/dirty auto-assertions not yet defined for Node::Item.node={$kind} +incremental_delete_full = error deleting incremental compilation session directory `{$path}`: {$err} -incremental_undefined_clean_dirty_assertions = - clean/dirty auto-assertions not yet defined for {$kind} +incremental_delete_incompatible = + failed to delete invalidated or incompatible incremental compilation session directory contents `{$path}`: {$err} -incremental_repeated_depnode_label = dep-node label `{$label}` is repeated +incremental_delete_lock = + error deleting lock file for incremental compilation session directory `{$path}`: {$err} -incremental_unrecognized_depnode_label = dep-node label `{$label}` not recognized +incremental_delete_old = unable to delete old {$name} at `{$path}`: {$err} -incremental_not_dirty = `{$dep_node_str}` should be dirty but is not +incremental_delete_partial = failed to delete partly initialized session dir `{$path}`: {$err} -incremental_not_clean = `{$dep_node_str}` should be clean but is not +incremental_delete_workproduct = file-system error deleting outdated file `{$path}`: {$err} -incremental_not_loaded = `{$dep_node_str}` should have been loaded from disk but it was not +incremental_field_associated_value_expected = associated value expected for `{$name}` -incremental_unknown_item = unknown item `{$name}` +incremental_finalize = error finalizing incremental compilation session directory `{$path}`: {$err} -incremental_no_cfg = no cfg attribute +incremental_finalized_gc_failed = + failed to garbage collect finalized incremental compilation session directory `{$path}`: {$err} -incremental_associated_value_expected_for = associated value expected for `{$ident}` +incremental_hard_link_failed = + hard linking files in the incremental compilation cache failed. copying files instead. consider moving the cache directory to a file system which supports hard linking in session dir `{$path}` -incremental_associated_value_expected = expected an associated value +incremental_invalid_gc_failed = + failed to garbage collect invalid incremental compilation session directory `{$path}`: {$err} -incremental_unchecked_clean = found unchecked `#[rustc_clean]` attribute +incremental_load_dep_graph = could not load dep-graph from `{$path}`: {$err} -incremental_delete_old = unable to delete old {$name} at `{$path}`: {$err} +incremental_lock_unsupported = + the filesystem for the incremental path at {$session_dir} does not appear to support locking, consider changing the incremental path to a filesystem that supports locking or disable incremental compilation +incremental_malformed_cgu_name = + found malformed codegen unit name `{$user_path}`. codegen units names must always start with the name of the crate (`{$crate_name}` in this case). -incremental_create_new = failed to create {$name} at `{$path}`: {$err} +incremental_missing_depnode = missing `DepNode` variant -incremental_write_new = failed to write {$name} to `{$path}`: {$err} +incremental_missing_if_this_changed = no `#[rustc_if_this_changed]` annotation detected -incremental_canonicalize_path = incremental compilation: error canonicalizing path `{$path}`: {$err} +incremental_missing_query_depgraph = + found CGU-reuse attribute but `-Zquery-dep-graph` was not specified -incremental_create_incr_comp_dir = - could not create incremental compilation {$tag} directory `{$path}`: {$err} +incremental_move_dep_graph = failed to move dependency graph from `{$from}` to `{$to}`: {$err} -incremental_create_lock = - incremental compilation: could not create session directory lock file: {$lock_err} -incremental_lock_unsupported = - the filesystem for the incremental path at {$session_dir} does not appear to support locking, consider changing the incremental path to a filesystem that supports locking or disable incremental compilation -incremental_cargo_help_1 = - incremental compilation can be disabled by setting the environment variable CARGO_INCREMENTAL=0 (see https://doc.rust-lang.org/cargo/reference/profiles.html#incremental) -incremental_cargo_help_2 = - the entire build directory can be changed to a different filesystem by setting the environment variable CARGO_TARGET_DIR to a different path (see https://doc.rust-lang.org/cargo/reference/config.html#buildtarget-dir) +incremental_no_cfg = no cfg attribute -incremental_delete_lock = - error deleting lock file for incremental compilation session directory `{$path}`: {$err} +incremental_no_field = no field `{$name}` -incremental_hard_link_failed = - hard linking files in the incremental compilation cache failed. copying files instead. consider moving the cache directory to a file system which supports hard linking in session dir `{$path}` +incremental_no_module_named = + no module named `{$user_path}` (mangled: {$cgu_name}). available modules: {$cgu_names} -incremental_delete_partial = failed to delete partly initialized session dir `{$path}`: {$err} +incremental_no_path = no path from `{$source}` to `{$target}` -incremental_delete_full = error deleting incremental compilation session directory `{$path}`: {$err} +incremental_not_clean = `{$dep_node_str}` should be clean but is not -incremental_finalize = error finalizing incremental compilation session directory `{$path}`: {$err} +incremental_not_dirty = `{$dep_node_str}` should be dirty but is not -incremental_invalid_gc_failed = - failed to garbage collect invalid incremental compilation session directory `{$path}`: {$err} +incremental_not_loaded = `{$dep_node_str}` should have been loaded from disk but it was not -incremental_finalized_gc_failed = - failed to garbage collect finalized incremental compilation session directory `{$path}`: {$err} +incremental_ok = OK + +incremental_repeated_depnode_label = dep-node label `{$label}` is repeated incremental_session_gc_failed = failed to garbage collect incremental compilation session directory `{$path}`: {$err} -incremental_assert_not_loaded = - we asserted that the incremental cache should not be loaded, but it was loaded - -incremental_assert_loaded = - we asserted that an existing incremental cache directory should be successfully loaded, but it was not +incremental_unchecked_clean = found unchecked `#[rustc_clean]` attribute -incremental_delete_incompatible = - failed to delete invalidated or incompatible incremental compilation session directory contents `{$path}`: {$err} +incremental_undefined_clean_dirty_assertions = + clean/dirty auto-assertions not yet defined for {$kind} -incremental_load_dep_graph = could not load dep-graph from `{$path}`: {$err} +incremental_undefined_clean_dirty_assertions_item = + clean/dirty auto-assertions not yet defined for Node::Item.node={$kind} -incremental_decode_incr_cache = could not decode incremental cache: {$err} +incremental_unknown_item = unknown item `{$name}` -incremental_write_dep_graph = failed to write dependency graph to `{$path}`: {$err} +incremental_unknown_reuse_kind = unknown cgu-reuse-kind `{$kind}` specified -incremental_move_dep_graph = failed to move dependency graph from `{$from}` to `{$to}`: {$err} +incremental_unrecognized_depnode = unrecognized `DepNode` variant: {$name} -incremental_create_dep_graph = failed to create dependency graph at `{$path}`: {$err} +incremental_unrecognized_depnode_label = dep-node label `{$label}` not recognized -incremental_copy_workproduct_to_cache = - error copying object file `{$from}` to incremental directory as `{$to}`: {$err} +incremental_write_dep_graph = failed to write dependency graph to `{$path}`: {$err} -incremental_delete_workproduct = file-system error deleting outdated file `{$path}`: {$err} +incremental_write_new = failed to write {$name} to `{$path}`: {$err} diff --git a/compiler/rustc_infer/messages.ftl b/compiler/rustc_infer/messages.ftl index fdc4ff0896f..f44c4a7c1e3 100644 --- a/compiler/rustc_infer/messages.ftl +++ b/compiler/rustc_infer/messages.ftl @@ -1,285 +1,72 @@ -infer_opaque_hidden_type = - opaque type's hidden type cannot be another opaque type from the same scope - .label = one of the two opaque types used here has to be outside its defining scope - .opaque_type = opaque type whose hidden type is being assigned - .hidden_type = opaque type being used as hidden type - -infer_type_annotations_needed = {$source_kind -> - [closure] type annotations needed for the closure `{$source_name}` - [normal] type annotations needed for `{$source_name}` - *[other] type annotations needed -} - .label = type must be known at this point - -infer_label_bad = {$bad_kind -> - *[other] cannot infer type - [more_info] cannot infer {$prefix_kind -> - *[type] type for {$prefix} - [const_with_param] the value of const parameter - [const] the value of the constant - } `{$name}`{$has_parent -> - [true] {" "}declared on the {$parent_prefix} `{$parent_name}` - *[false] {""} - } -} - -infer_source_kind_subdiag_let = {$kind -> - [with_pattern] consider giving `{$name}` an explicit type - [closure] consider giving this closure parameter an explicit type - *[other] consider giving this pattern a type -}{$x_kind -> - [has_name] , where the {$prefix_kind -> - *[type] type for {$prefix} - [const_with_param] value of const parameter - [const] value of the constant - } `{$arg_name}` is specified - [underscore] , where the placeholders `_` are specified - *[empty] {""} -} - -infer_source_kind_subdiag_generic_label = - cannot infer {$is_type -> - [true] type - *[false] the value - } of the {$is_type -> - [true] type - *[false] const - } {$parent_exists -> - [true] parameter `{$param_name}` declared on the {$parent_prefix} `{$parent_name}` - *[false] parameter {$param_name} - } - -infer_source_kind_subdiag_generic_suggestion = - consider specifying the generic {$arg_count -> - [one] argument - *[other] arguments - } - -infer_source_kind_fully_qualified = - try using a fully qualified path to specify the expected types - -infer_source_kind_closure_return = - try giving this closure an explicit return type - -# generator_kind may need to be translated -infer_need_type_info_in_generator = - type inside {$generator_kind -> - [async_block] `async` block - [async_closure] `async` closure - [async_fn] `async fn` body - *[generator] generator - } must be known in this context - - -infer_subtype = ...so that the {$requirement -> - [method_compat] method type is compatible with trait - [type_compat] associated type is compatible with trait - [const_compat] const is compatible with trait - [expr_assignable] expression is assignable - [if_else_different] `if` and `else` have incompatible types - [no_else] `if` missing an `else` returns `()` - [fn_main_correct_type] `main` function has the correct type - [fn_start_correct_type] `#[start]` function has the correct type - [intrinsic_correct_type] intrinsic has the correct type - [method_correct_type] method receiver has the correct type - *[other] types are compatible -} -infer_subtype_2 = ...so that {$requirement -> - [method_compat] method type is compatible with trait - [type_compat] associated type is compatible with trait - [const_compat] const is compatible with trait - [expr_assignable] expression is assignable - [if_else_different] `if` and `else` have incompatible types - [no_else] `if` missing an `else` returns `()` - [fn_main_correct_type] `main` function has the correct type - [fn_start_correct_type] `#[start]` function has the correct type - [intrinsic_correct_type] intrinsic has the correct type - [method_correct_type] method receiver has the correct type - *[other] types are compatible -} - -infer_reborrow = ...so that reference does not outlive borrowed content -infer_reborrow_upvar = ...so that closure can access `{$name}` -infer_relate_object_bound = ...so that it can be closed over into an object -infer_reference_outlives_referent = ...so that the reference type `{$name}` does not outlive the data it points at -infer_relate_param_bound = ...so that the type `{$name}` will meet its required lifetime bounds{$continues -> - [true] ... +infer_actual_impl_expl_but_actually_implemented_for_ty = ...but `{$trait_path}` is actually implemented for the type `{$ty}`{$has_lifetime -> + [true] , for some specific lifetime `'{$lifetime}` *[false] {""} } -infer_relate_param_bound_2 = ...that is required by this bound -infer_relate_region_param_bound = ...so that the declared lifetime parameter bounds are satisfied -infer_compare_impl_item_obligation = ...so that the definition in impl matches the definition from the trait -infer_ascribe_user_type_prove_predicate = ...so that the where clause holds - -infer_nothing = {""} - -infer_lifetime_mismatch = lifetime mismatch - -infer_declared_different = this parameter and the return type are declared with different lifetimes... -infer_data_returned = ...but data{$label_var1_exists -> - [true] {" "}from `{$label_var1}` - *[false] {""} -} is returned here - -infer_data_lifetime_flow = ...but data with one lifetime flows into the other here -infer_declared_multiple = this type is declared with multiple lifetimes... -infer_types_declared_different = these two types are declared with different lifetimes... -infer_data_flows = ...but data{$label_var1_exists -> - [true] {" "}from `{$label_var1}` - *[false] -> {""} -} flows{$label_var2_exists -> - [true] {" "}into `{$label_var2}` - *[false] -> {""} -} here - -infer_lifetime_param_suggestion = consider introducing a named lifetime parameter{$is_impl -> - [true] {" "}and update trait if needed +infer_actual_impl_expl_but_actually_implements_trait = ...but it actually implements `{$trait_path}`{$has_lifetime -> + [true] , for some specific lifetime `'{$lifetime}` *[false] {""} } -infer_lifetime_param_suggestion_elided = each elided lifetime in input position becomes a distinct lifetime - -infer_region_explanation = {$pref_kind -> - *[should_not_happen] [{$pref_kind}] - [ref_valid_for] ...the reference is valid for - [content_valid_for] ...but the borrowed content is only valid for - [type_obj_valid_for] object type is valid for - [source_pointer_valid_for] source pointer is only valid for - [type_satisfy] type must satisfy - [type_outlive] type must outlive - [lf_param_instantiated_with] lifetime parameter instantiated with - [lf_param_must_outlive] but lifetime parameter must outlive - [lf_instantiated_with] lifetime instantiated with - [lf_must_outlive] but lifetime must outlive - [pointer_valid_for] the pointer is valid for - [data_valid_for] but the referenced data is only valid for - [empty] {""} -}{$pref_kind -> - [empty] {""} - *[other] {" "} -}{$desc_kind -> - *[should_not_happen] [{$desc_kind}] - [restatic] the static lifetime - [revar] lifetime {$desc_arg} - [as_defined] the lifetime `{$desc_arg}` as defined here - [as_defined_anon] the anonymous lifetime as defined here - [defined_here] the anonymous lifetime defined here - [defined_here_reg] the lifetime `{$desc_arg}` as defined here -}{$suff_kind -> - *[should_not_happen] [{$suff_kind}] - [empty]{""} - [continues] ... - [req_by_binding] {" "}as required by this binding +infer_actual_impl_expl_but_actually_ty_implements = ...but `{$ty}` actually implements `{$trait_path}`{$has_lifetime -> + [true] , for some specific lifetime `'{$lifetime}` + *[false] {""} } -infer_outlives_content = lifetime of reference outlives lifetime of borrowed content... -infer_outlives_bound = lifetime of the source pointer does not outlive lifetime bound of the object type -infer_fulfill_req_lifetime = the type `{$ty}` does not fulfill the required lifetime -infer_lf_bound_not_satisfied = lifetime bound not satisfied -infer_borrowed_too_long = a value of type `{$ty}` is borrowed for too long -infer_ref_longer_than_data = in type `{$ty}`, reference has a longer lifetime than the data it references - -infer_mismatched_static_lifetime = incompatible lifetime on type -infer_does_not_outlive_static_from_impl = ...does not necessarily outlive the static lifetime introduced by the compatible `impl` -infer_implicit_static_lifetime_note = this has an implicit `'static` lifetime requirement -infer_implicit_static_lifetime_suggestion = consider relaxing the implicit `'static` requirement -infer_msl_introduces_static = introduces a `'static` lifetime requirement -infer_msl_unmet_req = because this has an unmet lifetime requirement -infer_msl_trait_note = this has an implicit `'static` lifetime requirement -infer_msl_trait_sugg = consider relaxing the implicit `'static` requirement -infer_suggest_add_let_for_letchains = consider adding `let` - -infer_explicit_lifetime_required_with_ident = explicit lifetime required in the type of `{$simple_ident}` - .label = lifetime `{$named}` required - -infer_explicit_lifetime_required_with_param_type = explicit lifetime required in parameter type - .label = lifetime `{$named}` required - -infer_explicit_lifetime_required_sugg_with_ident = add explicit lifetime `{$named}` to the type of `{$simple_ident}` - -infer_explicit_lifetime_required_sugg_with_param_type = add explicit lifetime `{$named}` to type - -infer_actual_impl_expl_expected_signature_two = {$leading_ellipsis -> - [true] ... - *[false] {""} -}closure with signature `{$ty_or_sig}` must implement `{$trait_path}`, for any two lifetimes `'{$lifetime_1}` and `'{$lifetime_2}`... -infer_actual_impl_expl_expected_signature_any = {$leading_ellipsis -> +infer_actual_impl_expl_expected_other_any = {$leading_ellipsis -> [true] ... *[false] {""} -}closure with signature `{$ty_or_sig}` must implement `{$trait_path}`, for any lifetime `'{$lifetime_1}`... -infer_actual_impl_expl_expected_signature_some = {$leading_ellipsis -> +}`{$ty_or_sig}` must implement `{$trait_path}`, for any lifetime `'{$lifetime_1}`... +infer_actual_impl_expl_expected_other_nothing = {$leading_ellipsis -> [true] ... *[false] {""} -}closure with signature `{$ty_or_sig}` must implement `{$trait_path}`, for some specific lifetime `'{$lifetime_1}`... -infer_actual_impl_expl_expected_signature_nothing = {$leading_ellipsis -> +}`{$ty_or_sig}` must implement `{$trait_path}` + +infer_actual_impl_expl_expected_other_some = {$leading_ellipsis -> [true] ... *[false] {""} -}closure with signature `{$ty_or_sig}` must implement `{$trait_path}` -infer_actual_impl_expl_expected_passive_two = {$leading_ellipsis -> +}`{$ty_or_sig}` must implement `{$trait_path}`, for some specific lifetime `'{$lifetime_1}`... +infer_actual_impl_expl_expected_other_two = {$leading_ellipsis -> [true] ... *[false] {""} -}`{$trait_path}` would have to be implemented for the type `{$ty_or_sig}`, for any two lifetimes `'{$lifetime_1}` and `'{$lifetime_2}`... +}`{$ty_or_sig}` must implement `{$trait_path}`, for any two lifetimes `'{$lifetime_1}` and `'{$lifetime_2}`... infer_actual_impl_expl_expected_passive_any = {$leading_ellipsis -> [true] ... *[false] {""} }`{$trait_path}` would have to be implemented for the type `{$ty_or_sig}`, for any lifetime `'{$lifetime_1}`... -infer_actual_impl_expl_expected_passive_some = {$leading_ellipsis -> - [true] ... - *[false] {""} -}`{$trait_path}` would have to be implemented for the type `{$ty_or_sig}`, for some specific lifetime `'{$lifetime_1}`... infer_actual_impl_expl_expected_passive_nothing = {$leading_ellipsis -> [true] ... *[false] {""} }`{$trait_path}` would have to be implemented for the type `{$ty_or_sig}` -infer_actual_impl_expl_expected_other_two = {$leading_ellipsis -> +infer_actual_impl_expl_expected_passive_some = {$leading_ellipsis -> [true] ... *[false] {""} -}`{$ty_or_sig}` must implement `{$trait_path}`, for any two lifetimes `'{$lifetime_1}` and `'{$lifetime_2}`... -infer_actual_impl_expl_expected_other_any = {$leading_ellipsis -> +}`{$trait_path}` would have to be implemented for the type `{$ty_or_sig}`, for some specific lifetime `'{$lifetime_1}`... +infer_actual_impl_expl_expected_passive_two = {$leading_ellipsis -> [true] ... *[false] {""} -}`{$ty_or_sig}` must implement `{$trait_path}`, for any lifetime `'{$lifetime_1}`... -infer_actual_impl_expl_expected_other_some = {$leading_ellipsis -> +}`{$trait_path}` would have to be implemented for the type `{$ty_or_sig}`, for any two lifetimes `'{$lifetime_1}` and `'{$lifetime_2}`... +infer_actual_impl_expl_expected_signature_any = {$leading_ellipsis -> [true] ... *[false] {""} -}`{$ty_or_sig}` must implement `{$trait_path}`, for some specific lifetime `'{$lifetime_1}`... -infer_actual_impl_expl_expected_other_nothing = {$leading_ellipsis -> +}closure with signature `{$ty_or_sig}` must implement `{$trait_path}`, for any lifetime `'{$lifetime_1}`... +infer_actual_impl_expl_expected_signature_nothing = {$leading_ellipsis -> [true] ... *[false] {""} -}`{$ty_or_sig}` must implement `{$trait_path}` - -infer_actual_impl_expl_but_actually_implements_trait = ...but it actually implements `{$trait_path}`{$has_lifetime -> - [true] , for some specific lifetime `'{$lifetime}` - *[false] {""} -} -infer_actual_impl_expl_but_actually_implemented_for_ty = ...but `{$trait_path}` is actually implemented for the type `{$ty}`{$has_lifetime -> - [true] , for some specific lifetime `'{$lifetime}` +}closure with signature `{$ty_or_sig}` must implement `{$trait_path}` +infer_actual_impl_expl_expected_signature_some = {$leading_ellipsis -> + [true] ... *[false] {""} -} -infer_actual_impl_expl_but_actually_ty_implements = ...but `{$ty}` actually implements `{$trait_path}`{$has_lifetime -> - [true] , for some specific lifetime `'{$lifetime}` +}closure with signature `{$ty_or_sig}` must implement `{$trait_path}`, for some specific lifetime `'{$lifetime_1}`... +infer_actual_impl_expl_expected_signature_two = {$leading_ellipsis -> + [true] ... *[false] {""} -} - -infer_trait_placeholder_mismatch = implementation of `{$trait_def_id}` is not general enough - .label_satisfy = doesn't satisfy where-clause - .label_where = due to a where-clause on `{$def_id}`... - .label_dup = implementation of `{$trait_def_id}` is not general enough - -infer_trait_impl_diff = `impl` item signature doesn't match `trait` item signature - .found = found `{$found}` - .expected = expected `{$expected}` - .expected_found = expected signature `{$expected}` - {" "}found signature `{$found}` - -infer_tid_rel_help = verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output -infer_tid_consider_borrowing = consider borrowing this type parameter in the trait -infer_tid_param_help = the lifetime requirements from the `impl` do not correspond to the requirements in the `trait` +}closure with signature `{$ty_or_sig}` must implement `{$trait_path}`, for any two lifetimes `'{$lifetime_1}` and `'{$lifetime_2}`... +infer_ascribe_user_type_prove_predicate = ...so that the where clause holds -infer_dtcs_has_lifetime_req_label = this has an implicit `'static` lifetime requirement -infer_dtcs_introduces_requirement = calling this method introduces the `impl`'s `'static` requirement -infer_dtcs_has_req_note = the used `impl` has a `'static` requirement -infer_dtcs_suggestion = consider relaxing the implicit `'static` requirement +infer_await_both_futures = consider `await`ing on both `Future`s +infer_await_future = consider `await`ing on the `Future` +infer_await_note = calling an async function returns a future +infer_borrowed_too_long = a value of type `{$ty}` is borrowed for too long infer_but_calling_introduces = {$has_param_name -> [true] `{$param_name}` *[false] `fn` parameter @@ -314,6 +101,77 @@ infer_but_needs_to_satisfy = {$has_param_name -> .used_here = ...is used here... .introduced_by_bound = `'static` lifetime requirement introduced by this bound +infer_compare_impl_item_obligation = ...so that the definition in impl matches the definition from the trait +infer_consider_specifying_length = consider specifying the actual array length +infer_data_flows = ...but data{$label_var1_exists -> + [true] {" "}from `{$label_var1}` + *[false] -> {""} +} flows{$label_var2_exists -> + [true] {" "}into `{$label_var2}` + *[false] -> {""} +} here + +infer_data_lifetime_flow = ...but data with one lifetime flows into the other here +infer_data_returned = ...but data{$label_var1_exists -> + [true] {" "}from `{$label_var1}` + *[false] {""} +} is returned here + +infer_declared_different = this parameter and the return type are declared with different lifetimes... +infer_declared_multiple = this type is declared with multiple lifetimes... +infer_does_not_outlive_static_from_impl = ...does not necessarily outlive the static lifetime introduced by the compatible `impl` +infer_dtcs_has_lifetime_req_label = this has an implicit `'static` lifetime requirement +infer_dtcs_has_req_note = the used `impl` has a `'static` requirement +infer_dtcs_introduces_requirement = calling this method introduces the `impl`'s `'static` requirement +infer_dtcs_suggestion = consider relaxing the implicit `'static` requirement + +infer_explicit_lifetime_required_sugg_with_ident = add explicit lifetime `{$named}` to the type of `{$simple_ident}` + +infer_explicit_lifetime_required_sugg_with_param_type = add explicit lifetime `{$named}` to type + +infer_explicit_lifetime_required_with_ident = explicit lifetime required in the type of `{$simple_ident}` + .label = lifetime `{$named}` required + +infer_explicit_lifetime_required_with_param_type = explicit lifetime required in parameter type + .label = lifetime `{$named}` required + +infer_fn_consider_casting = consider casting the fn item to a fn pointer: `{$casting}` + +infer_fn_uniq_types = different fn items have unique types, even if their signatures are the same +infer_fps_cast = consider casting to a fn pointer +infer_fps_cast_both = consider casting both fn items to fn pointers using `as {$expected_sig}` + +infer_fps_items_are_distinct = fn items are distinct from fn pointers +infer_fps_remove_ref = consider removing the reference +infer_fps_use_ref = consider using a reference +infer_fulfill_req_lifetime = the type `{$ty}` does not fulfill the required lifetime +infer_implicit_static_lifetime_note = this has an implicit `'static` lifetime requirement +infer_implicit_static_lifetime_suggestion = consider relaxing the implicit `'static` requirement +infer_label_bad = {$bad_kind -> + *[other] cannot infer type + [more_info] cannot infer {$prefix_kind -> + *[type] type for {$prefix} + [const_with_param] the value of const parameter + [const] the value of the constant + } `{$name}`{$has_parent -> + [true] {" "}declared on the {$parent_prefix} `{$parent_name}` + *[false] {""} + } +} + +infer_lf_bound_not_satisfied = lifetime bound not satisfied +infer_lifetime_mismatch = lifetime mismatch + +infer_lifetime_param_suggestion = consider introducing a named lifetime parameter{$is_impl -> + [true] {" "}and update trait if needed + *[false] {""} +} +infer_lifetime_param_suggestion_elided = each elided lifetime in input position becomes a distinct lifetime + +infer_meant_byte_literal = if you meant to write a byte literal, prefix with `b` +infer_meant_char_literal = if you meant to write a `char` literal, use single quotes +infer_meant_str_literal = if you meant to write a `str` literal, use double quotes +infer_mismatched_static_lifetime = incompatible lifetime on type infer_more_targeted = {$has_param_name -> [true] `{$param_name}` *[false] `fn` parameter @@ -322,72 +180,215 @@ infer_more_targeted = {$has_param_name -> *[false] an anonymous lifetime `'_` } but calling `{$ident}` introduces an implicit `'static` lifetime requirement -infer_ril_introduced_here = `'static` requirement introduced here -infer_ril_introduced_by = requirement introduced by this return type -infer_ril_because_of = because of this returned expression -infer_ril_static_introduced_by = "`'static` lifetime requirement introduced by the return type +infer_msl_introduces_static = introduces a `'static` lifetime requirement +infer_msl_trait_note = this has an implicit `'static` lifetime requirement +infer_msl_trait_sugg = consider relaxing the implicit `'static` requirement +infer_msl_unmet_req = because this has an unmet lifetime requirement +infer_need_type_info_in_generator = + type inside {$generator_kind -> + [async_block] `async` block + [async_closure] `async` closure + [async_fn] `async fn` body + *[generator] generator + } must be known in this context -infer_where_remove = remove the `where` clause -infer_where_copy_predicates = copy the `where` clause predicates from the trait -infer_srs_remove_and_box = consider removing this semicolon and boxing the expressions -infer_srs_remove = consider removing this semicolon -infer_srs_add = consider returning the local binding `{$ident}` -infer_srs_add_one = consider returning one of these bindings +infer_nothing = {""} -infer_await_both_futures = consider `await`ing on both `Future`s -infer_await_future = consider `await`ing on the `Future` -infer_await_note = calling an async function returns a future +infer_oc_cant_coerce = cannot coerce intrinsics to function pointers +infer_oc_closure_selfref = closure/generator type that references itself +infer_oc_const_compat = const not compatible with trait +infer_oc_fn_main_correct_type = `main` function has wrong type +infer_oc_fn_start_correct_type = `#[start]` function has wrong type +infer_oc_generic = mismatched types +infer_oc_if_else_different = `if` and `else` have incompatible types +infer_oc_intrinsic_correct_type = intrinsic has wrong type +infer_oc_match_compat = `match` arms have incompatible types +infer_oc_method_compat = method not compatible with trait +infer_oc_method_correct_type = mismatched `self` parameter type +infer_oc_no_diverge = `else` clause of `let...else` does not diverge +infer_oc_no_else = `if` may be missing an `else` clause +infer_oc_try_compat = `?` operator has incompatible types +infer_oc_type_compat = type not compatible with trait +infer_opaque_captures_lifetime = hidden type for `{$opaque_ty}` captures lifetime that does not appear in bounds + .label = opaque type defined here + +infer_opaque_hidden_type = + opaque type's hidden type cannot be another opaque type from the same scope + .label = one of the two opaque types used here has to be outside its defining scope + .opaque_type = opaque type whose hidden type is being assigned + .hidden_type = opaque type being used as hidden type + +infer_outlives_bound = lifetime of the source pointer does not outlive lifetime bound of the object type +infer_outlives_content = lifetime of reference outlives lifetime of borrowed content... infer_prlf_defined_with_sub = the lifetime `{$sub_symbol}` defined here... infer_prlf_defined_without_sub = the lifetime defined here... -infer_prlf_must_outlive_with_sup = ...must outlive the lifetime `{$sup_symbol}` defined here -infer_prlf_must_outlive_without_sup = ...must outlive the lifetime defined here infer_prlf_known_limitation = this is a known limitation that will be removed in the future (see issue #100013 <https://github.com/rust-lang/rust/issues/100013> for more information) -infer_opaque_captures_lifetime = hidden type for `{$opaque_ty}` captures lifetime that does not appear in bounds - .label = opaque type defined here +infer_prlf_must_outlive_with_sup = ...must outlive the lifetime `{$sup_symbol}` defined here +infer_prlf_must_outlive_without_sup = ...must outlive the lifetime defined here +infer_reborrow = ...so that reference does not outlive borrowed content +infer_reborrow_upvar = ...so that closure can access `{$name}` +infer_ref_longer_than_data = in type `{$ty}`, reference has a longer lifetime than the data it references -infer_fps_use_ref = consider using a reference -infer_fps_remove_ref = consider removing the reference -infer_fps_cast = consider casting to a fn pointer -infer_fps_items_are_distinct = fn items are distinct from fn pointers -infer_fps_cast_both = consider casting both fn items to fn pointers using `as {$expected_sig}` +infer_reference_outlives_referent = ...so that the reference type `{$name}` does not outlive the data it points at +infer_region_explanation = {$pref_kind -> + *[should_not_happen] [{$pref_kind}] + [ref_valid_for] ...the reference is valid for + [content_valid_for] ...but the borrowed content is only valid for + [type_obj_valid_for] object type is valid for + [source_pointer_valid_for] source pointer is only valid for + [type_satisfy] type must satisfy + [type_outlive] type must outlive + [lf_param_instantiated_with] lifetime parameter instantiated with + [lf_param_must_outlive] but lifetime parameter must outlive + [lf_instantiated_with] lifetime instantiated with + [lf_must_outlive] but lifetime must outlive + [pointer_valid_for] the pointer is valid for + [data_valid_for] but the referenced data is only valid for + [empty] {""} +}{$pref_kind -> + [empty] {""} + *[other] {" "} +}{$desc_kind -> + *[should_not_happen] [{$desc_kind}] + [restatic] the static lifetime + [revar] lifetime {$desc_arg} + [as_defined] the lifetime `{$desc_arg}` as defined here + [as_defined_anon] the anonymous lifetime as defined here + [defined_here] the anonymous lifetime defined here + [defined_here_reg] the lifetime `{$desc_arg}` as defined here +}{$suff_kind -> + *[should_not_happen] [{$suff_kind}] + [empty]{""} + [continues] ... + [req_by_binding] {" "}as required by this binding +} -infer_fn_uniq_types = different fn items have unique types, even if their signatures are the same -infer_fn_consider_casting = consider casting the fn item to a fn pointer: `{$casting}` +infer_relate_object_bound = ...so that it can be closed over into an object +infer_relate_param_bound = ...so that the type `{$name}` will meet its required lifetime bounds{$continues -> + [true] ... + *[false] {""} +} +infer_relate_param_bound_2 = ...that is required by this bound +infer_relate_region_param_bound = ...so that the declared lifetime parameter bounds are satisfied +infer_ril_because_of = because of this returned expression +infer_ril_introduced_by = requirement introduced by this return type +infer_ril_introduced_here = `'static` requirement introduced here +infer_ril_static_introduced_by = "`'static` lifetime requirement introduced by the return type infer_sarwa_option = you can convert from `&Option<T>` to `Option<&T>` using `.as_ref()` infer_sarwa_result = you can convert from `&Result<T, E>` to `Result<&T, &E>` using `.as_ref()` -infer_suggest_accessing_field = you might have meant to use field `{$name}` whose type is `{$ty}` +infer_sbfrit_box_return_expr = if you change the return type to expect trait objects, box the returned expressions infer_sbfrit_change_return_type = you could change the return type to be a boxed trait object -infer_sbfrit_box_return_expr = if you change the return type to expect trait objects, box the returned expressions +infer_source_kind_closure_return = + try giving this closure an explicit return type -infer_stp_wrap_one = try wrapping the pattern in `{$variant}` +# generator_kind may need to be translated +infer_source_kind_fully_qualified = + try using a fully qualified path to specify the expected types + +infer_source_kind_subdiag_generic_label = + cannot infer {$is_type -> + [true] type + *[false] the value + } of the {$is_type -> + [true] type + *[false] const + } {$parent_exists -> + [true] parameter `{$param_name}` declared on the {$parent_prefix} `{$parent_name}` + *[false] parameter {$param_name} + } + +infer_source_kind_subdiag_generic_suggestion = + consider specifying the generic {$arg_count -> + [one] argument + *[other] arguments + } + +infer_source_kind_subdiag_let = {$kind -> + [with_pattern] consider giving `{$name}` an explicit type + [closure] consider giving this closure parameter an explicit type + *[other] consider giving this pattern a type +}{$x_kind -> + [has_name] , where the {$prefix_kind -> + *[type] type for {$prefix} + [const_with_param] value of const parameter + [const] value of the constant + } `{$arg_name}` is specified + [underscore] , where the placeholders `_` are specified + *[empty] {""} +} + +infer_srs_add = consider returning the local binding `{$ident}` +infer_srs_add_one = consider returning one of these bindings + +infer_srs_remove = consider removing this semicolon +infer_srs_remove_and_box = consider removing this semicolon and boxing the expressions infer_stp_wrap_many = try wrapping the pattern in a variant of `{$path}` -infer_tuple_trailing_comma = use a trailing comma to create a tuple with one element +infer_stp_wrap_one = try wrapping the pattern in `{$variant}` +infer_subtype = ...so that the {$requirement -> + [method_compat] method type is compatible with trait + [type_compat] associated type is compatible with trait + [const_compat] const is compatible with trait + [expr_assignable] expression is assignable + [if_else_different] `if` and `else` have incompatible types + [no_else] `if` missing an `else` returns `()` + [fn_main_correct_type] `main` function has the correct type + [fn_start_correct_type] `#[start]` function has the correct type + [intrinsic_correct_type] intrinsic has the correct type + [method_correct_type] method receiver has the correct type + *[other] types are compatible +} +infer_subtype_2 = ...so that {$requirement -> + [method_compat] method type is compatible with trait + [type_compat] associated type is compatible with trait + [const_compat] const is compatible with trait + [expr_assignable] expression is assignable + [if_else_different] `if` and `else` have incompatible types + [no_else] `if` missing an `else` returns `()` + [fn_main_correct_type] `main` function has the correct type + [fn_start_correct_type] `#[start]` function has the correct type + [intrinsic_correct_type] intrinsic has the correct type + [method_correct_type] method receiver has the correct type + *[other] types are compatible +} -infer_oc_method_compat = method not compatible with trait -infer_oc_type_compat = type not compatible with trait -infer_oc_const_compat = const not compatible with trait -infer_oc_try_compat = `?` operator has incompatible types -infer_oc_match_compat = `match` arms have incompatible types -infer_oc_if_else_different = `if` and `else` have incompatible types -infer_oc_no_else = `if` may be missing an `else` clause -infer_oc_no_diverge = `else` clause of `let...else` does not diverge -infer_oc_fn_main_correct_type = `main` function has wrong type -infer_oc_fn_start_correct_type = `#[start]` function has wrong type -infer_oc_intrinsic_correct_type = intrinsic has wrong type -infer_oc_method_correct_type = mismatched `self` parameter type -infer_oc_closure_selfref = closure/generator type that references itself -infer_oc_cant_coerce = cannot coerce intrinsics to function pointers -infer_oc_generic = mismatched types +infer_suggest_accessing_field = you might have meant to use field `{$name}` whose type is `{$ty}` + +infer_suggest_add_let_for_letchains = consider adding `let` + +infer_tid_consider_borrowing = consider borrowing this type parameter in the trait +infer_tid_param_help = the lifetime requirements from the `impl` do not correspond to the requirements in the `trait` + +infer_tid_rel_help = verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output +infer_trait_impl_diff = `impl` item signature doesn't match `trait` item signature + .found = found `{$found}` + .expected = expected `{$expected}` + .expected_found = expected signature `{$expected}` + {" "}found signature `{$found}` + +infer_trait_placeholder_mismatch = implementation of `{$trait_def_id}` is not general enough + .label_satisfy = doesn't satisfy where-clause + .label_where = due to a where-clause on `{$def_id}`... + .label_dup = implementation of `{$trait_def_id}` is not general enough -infer_meant_byte_literal = if you meant to write a byte literal, prefix with `b` -infer_meant_char_literal = if you meant to write a `char` literal, use single quotes -infer_meant_str_literal = if you meant to write a `str` literal, use double quotes -infer_consider_specifying_length = consider specifying the actual array length infer_try_cannot_convert = `?` operator cannot convert from `{$found}` to `{$expected}` + +infer_tuple_trailing_comma = use a trailing comma to create a tuple with one element + +infer_type_annotations_needed = {$source_kind -> + [closure] type annotations needed for the closure `{$source_name}` + [normal] type annotations needed for `{$source_name}` + *[other] type annotations needed +} + .label = type must be known at this point + +infer_types_declared_different = these two types are declared with different lifetimes... +infer_where_copy_predicates = copy the `where` clause predicates from the trait + +infer_where_remove = remove the `where` clause diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs index 0c8854e962a..6b2dd0a2b4f 100644 --- a/compiler/rustc_infer/src/infer/at.rs +++ b/compiler/rustc_infer/src/infer/at.rs @@ -70,8 +70,8 @@ impl<'tcx> InferCtxt<'tcx> { tcx: self.tcx, defining_use_anchor: self.defining_use_anchor, considering_regions: self.considering_regions, + skip_leak_check: self.skip_leak_check, inner: self.inner.clone(), - skip_leak_check: self.skip_leak_check.clone(), lexical_region_resolutions: self.lexical_region_resolutions.clone(), selection_cache: self.selection_cache.clone(), evaluation_cache: self.evaluation_cache.clone(), diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs index 427d05c8b4d..bf53a73f398 100644 --- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs +++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs @@ -771,7 +771,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { ) -> ty::Region<'tcx> { let var = self.canonical_var(info, r.into()); let br = ty::BoundRegion { var, kind: ty::BrAnon(None) }; - self.interner().mk_re_late_bound(self.binder_index, br) + ty::Region::new_late_bound(self.interner(), self.binder_index, br) } /// Given a type variable `ty_var` of the given kind, first check diff --git a/compiler/rustc_infer/src/infer/canonical/mod.rs b/compiler/rustc_infer/src/infer/canonical/mod.rs index 2abdd5b0aec..c8c318c3f02 100644 --- a/compiler/rustc_infer/src/infer/canonical/mod.rs +++ b/compiler/rustc_infer/src/infer/canonical/mod.rs @@ -141,7 +141,7 @@ impl<'tcx> InferCtxt<'tcx> { CanonicalVarKind::PlaceholderRegion(ty::PlaceholderRegion { universe, bound }) => { let universe_mapped = universe_map(universe); let placeholder_mapped = ty::PlaceholderRegion { universe: universe_mapped, bound }; - self.tcx.mk_re_placeholder(placeholder_mapped).into() + ty::Region::new_placeholder(self.tcx, placeholder_mapped).into() } CanonicalVarKind::Const(ui, ty) => self diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index de9afbbcaab..2cf8d8c702d 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -15,7 +15,7 @@ use crate::infer::canonical::{ use crate::infer::nll_relate::{TypeRelating, TypeRelatingDelegate}; use crate::infer::region_constraints::{Constraint, RegionConstraintData}; use crate::infer::{DefineOpaqueTypes, InferCtxt, InferOk, InferResult, NllRegionVariableOrigin}; -use crate::traits::query::{Fallible, NoSolution}; +use crate::traits::query::NoSolution; use crate::traits::{Obligation, ObligationCause, PredicateObligation}; use crate::traits::{PredicateObligations, TraitEngine, TraitEngineExt}; use rustc_data_structures::captures::Captures; @@ -57,7 +57,7 @@ impl<'tcx> InferCtxt<'tcx> { inference_vars: CanonicalVarValues<'tcx>, answer: T, fulfill_cx: &mut dyn TraitEngine<'tcx>, - ) -> Fallible<CanonicalQueryResponse<'tcx, T>> + ) -> Result<CanonicalQueryResponse<'tcx, T>, NoSolution> where T: Debug + TypeFoldable<TyCtxt<'tcx>>, Canonical<'tcx, QueryResponse<'tcx, T>>: ArenaAllocatable<'tcx>, @@ -668,14 +668,15 @@ pub fn make_query_region_constraints<'tcx>( let constraint = match *k { // Swap regions because we are going from sub (<=) to outlives // (>=). - Constraint::VarSubVar(v1, v2) => { - ty::OutlivesPredicate(tcx.mk_re_var(v2).into(), tcx.mk_re_var(v1)) - } + Constraint::VarSubVar(v1, v2) => ty::OutlivesPredicate( + ty::Region::new_var(tcx, v2).into(), + ty::Region::new_var(tcx, v1), + ), Constraint::VarSubReg(v1, r2) => { - ty::OutlivesPredicate(r2.into(), tcx.mk_re_var(v1)) + ty::OutlivesPredicate(r2.into(), ty::Region::new_var(tcx, v1)) } Constraint::RegSubVar(r1, v2) => { - ty::OutlivesPredicate(tcx.mk_re_var(v2).into(), r1) + ty::OutlivesPredicate(ty::Region::new_var(tcx, v2).into(), r1) } Constraint::RegSubReg(r1, r2) => ty::OutlivesPredicate(r2.into(), r1), }; @@ -719,7 +720,7 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for QueryTypeRelatingDelegate<'_, 'tcx> { } fn next_placeholder_region(&mut self, placeholder: ty::PlaceholderRegion) -> ty::Region<'tcx> { - self.infcx.tcx.mk_re_placeholder(placeholder) + ty::Region::new_placeholder(self.infcx.tcx, placeholder) } fn generalize_existential(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx> { diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 35c05e80bad..f8a253c8949 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -76,6 +76,7 @@ use rustc_middle::ty::{ }; use rustc_span::{sym, symbol::kw, BytePos, DesugaringKind, Pos, Span}; use rustc_target::spec::abi; +use std::borrow::Cow; use std::ops::{ControlFlow, Deref}; use std::path::PathBuf; use std::{cmp, fmt, iter}; @@ -1470,7 +1471,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { &self, diag: &mut Diagnostic, cause: &ObligationCause<'tcx>, - secondary_span: Option<(Span, String)>, + secondary_span: Option<(Span, Cow<'static, str>)>, mut values: Option<ValuePairs<'tcx>>, terr: TypeError<'tcx>, swap_secondary_and_primary: bool, @@ -1629,7 +1630,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } }; - let mut label_or_note = |span: Span, msg: &str| { + let mut label_or_note = |span: Span, msg: Cow<'static, str>| { if (prefer_label && is_simple_error) || &[span] == diag.span.primary_spans() { diag.span_label(span, msg); } else { @@ -1643,15 +1644,15 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { .. })) = values { - format!("expected this to be `{}`", expected) + Cow::from(format!("expected this to be `{}`", expected)) } else { - terr.to_string(self.tcx).to_string() + terr.to_string(self.tcx) }; - label_or_note(sp, &terr); - label_or_note(span, &msg); + label_or_note(sp, terr); + label_or_note(span, msg); } else { - label_or_note(span, &terr.to_string(self.tcx)); - label_or_note(sp, &msg); + label_or_note(span, terr.to_string(self.tcx)); + label_or_note(sp, msg); } } else { if let Some(values) = values @@ -1663,12 +1664,12 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let expected = with_forced_trimmed_paths!(e.sort_string(self.tcx)); let found = with_forced_trimmed_paths!(f.sort_string(self.tcx)); if expected == found { - label_or_note(span, &terr.to_string(self.tcx)); + label_or_note(span, terr.to_string(self.tcx)); } else { - label_or_note(span, &format!("expected {expected}, found {found}")); + label_or_note(span, Cow::from(format!("expected {expected}, found {found}"))); } } else { - label_or_note(span, &terr.to_string(self.tcx)); + label_or_note(span, terr.to_string(self.tcx)); } } diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs index c9c1f0aeaac..0b3bc1ce6b3 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs @@ -79,7 +79,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { sup_placeholder @ Region(Interned(RePlaceholder(_), _)), _, )) => self.try_report_trait_placeholder_mismatch( - Some(self.tcx().mk_re_var(*vid)), + Some(ty::Region::new_var(self.tcx(), *vid)), cause, Some(*sub_placeholder), Some(*sup_placeholder), @@ -95,7 +95,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { _, _, )) => self.try_report_trait_placeholder_mismatch( - Some(self.tcx().mk_re_var(*vid)), + Some(ty::Region::new_var(self.tcx(), *vid)), cause, Some(*sub_placeholder), None, @@ -111,7 +111,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { sup_placeholder @ Region(Interned(RePlaceholder(_), _)), _, )) => self.try_report_trait_placeholder_mismatch( - Some(self.tcx().mk_re_var(*vid)), + Some(ty::Region::new_var(self.tcx(), *vid)), cause, None, Some(*sup_placeholder), @@ -127,7 +127,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { sup_placeholder @ Region(Interned(RePlaceholder(_), _)), _, )) => self.try_report_trait_placeholder_mismatch( - Some(self.tcx().mk_re_var(*vid)), + Some(ty::Region::new_var(self.tcx(), *vid)), cause, None, Some(*sup_placeholder), @@ -141,7 +141,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { SubregionOrigin::Subtype(box TypeTrace { cause, values }), sup_placeholder @ Region(Interned(RePlaceholder(_), _)), )) => self.try_report_trait_placeholder_mismatch( - Some(self.tcx().mk_re_var(*vid)), + Some(ty::Region::new_var(self.tcx(), *vid)), cause, None, Some(*sup_placeholder), diff --git a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs index 421eb807a14..d1f110472c9 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs @@ -234,13 +234,13 @@ impl<T> Trait<T> for X { ); } (_, ty::Alias(ty::Projection | ty::Inherent, proj_ty)) if !tcx.is_impl_trait_in_trait(proj_ty.def_id) => { - let msg = format!( + let msg = || format!( "consider constraining the associated type `{}` to `{}`", values.found, values.expected, ); if !(self.suggest_constraining_opaque_associated_type( diag, - &msg, + msg, proj_ty, values.expected, ) || self.suggest_constraint( @@ -250,7 +250,7 @@ impl<T> Trait<T> for X { proj_ty, values.expected, )) { - diag.help(msg); + diag.help(msg()); diag.note( "for more information, visit \ https://doc.rust-lang.org/book/ch19-03-advanced-traits.html", @@ -308,7 +308,7 @@ impl<T> Trait<T> for X { fn suggest_constraint( &self, diag: &mut Diagnostic, - msg: &str, + msg: impl Fn() -> String, body_owner_def_id: DefId, proj_ty: &ty::AliasTy<'tcx>, ty: Ty<'tcx>, @@ -340,7 +340,7 @@ impl<T> Trait<T> for X { assoc, assoc_substs, ty, - msg, + &msg, false, ) { return true; @@ -374,10 +374,12 @@ impl<T> Trait<T> for X { ) { let tcx = self.tcx; - let msg = format!( - "consider constraining the associated type `{}` to `{}`", - values.expected, values.found - ); + let msg = || { + format!( + "consider constraining the associated type `{}` to `{}`", + values.expected, values.found + ) + }; let body_owner = tcx.hir().get_if_local(body_owner_def_id); let current_method_ident = body_owner.and_then(|n| n.ident()).map(|i| i.name); @@ -428,10 +430,11 @@ impl<T> Trait<T> for X { if callable_scope { diag.help(format!( "{} or calling a method that returns `{}`", - msg, values.expected + msg(), + values.expected )); } else { - diag.help(msg); + diag.help(msg()); } diag.note( "for more information, visit \ @@ -463,7 +466,7 @@ fn foo(&self) -> Self::T { String::new() } fn suggest_constraining_opaque_associated_type( &self, diag: &mut Diagnostic, - msg: &str, + msg: impl Fn() -> String, proj_ty: &ty::AliasTy<'tcx>, ty: Ty<'tcx>, ) -> bool { @@ -635,7 +638,7 @@ fn foo(&self) -> Self::T { String::new() } assoc: ty::AssocItem, assoc_substs: &[ty::GenericArg<'tcx>], ty: Ty<'tcx>, - msg: &str, + msg: impl Fn() -> String, is_bound_surely_present: bool, ) -> bool { // FIXME: we would want to call `resolve_vars_if_possible` on `ty` before suggesting. @@ -678,7 +681,7 @@ fn foo(&self) -> Self::T { String::new() } assoc: ty::AssocItem, assoc_substs: &[ty::GenericArg<'tcx>], ty: Ty<'tcx>, - msg: &str, + msg: impl Fn() -> String, ) -> bool { let tcx = self.tcx; @@ -693,7 +696,7 @@ fn foo(&self) -> Self::T { String::new() } let item_args = self.format_generic_args(assoc_substs); (span.shrink_to_hi(), format!("<{}{} = {}>", assoc.ident(tcx), item_args, ty)) }; - diag.span_suggestion_verbose(span, msg, sugg, MaybeIncorrect); + diag.span_suggestion_verbose(span, msg(), sugg, MaybeIncorrect); return true; } false diff --git a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs index c304cd25c9c..974bc2f1153 100644 --- a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs +++ b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs @@ -82,8 +82,10 @@ impl<'tcx> InferCtxt<'tcx> { let delegate = FnMutDelegate { regions: &mut |br: ty::BoundRegion| { - self.tcx - .mk_re_placeholder(ty::PlaceholderRegion { universe: next_universe, bound: br }) + ty::Region::new_placeholder( + self.tcx, + ty::PlaceholderRegion { universe: next_universe, bound: br }, + ) }, types: &mut |bound_ty: ty::BoundTy| { self.tcx.mk_placeholder(ty::PlaceholderType { @@ -103,13 +105,15 @@ impl<'tcx> InferCtxt<'tcx> { self.tcx.replace_bound_vars_uncached(binder, delegate) } - /// See [RegionConstraintCollector::leak_check][1]. + /// See [RegionConstraintCollector::leak_check][1]. We only check placeholder + /// leaking into `outer_universe`, i.e. placeholders which cannot be named by that + /// universe. /// /// [1]: crate::infer::region_constraints::RegionConstraintCollector::leak_check pub fn leak_check( &self, - overly_polymorphic: bool, - snapshot: &CombinedSnapshot<'tcx>, + outer_universe: ty::UniverseIndex, + only_consider_snapshot: Option<&CombinedSnapshot<'tcx>>, ) -> RelateResult<'tcx, ()> { // If the user gave `-Zno-leak-check`, or we have been // configured to skip the leak check, then skip the leak check @@ -117,15 +121,15 @@ impl<'tcx> InferCtxt<'tcx> { // subtyping errors that it would have caught will now be // caught later on, during region checking. However, we // continue to use it for a transition period. - if self.tcx.sess.opts.unstable_opts.no_leak_check || self.skip_leak_check.get() { + if self.tcx.sess.opts.unstable_opts.no_leak_check || self.skip_leak_check { return Ok(()); } self.inner.borrow_mut().unwrap_region_constraints().leak_check( self.tcx, - overly_polymorphic, + outer_universe, self.universe(), - snapshot, + only_consider_snapshot, ) } } 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 8482ae2aa38..485e34fe2bf 100644 --- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs +++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs @@ -347,7 +347,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { // name the placeholder, then the placeholder is // larger; otherwise, the only ancestor is `'static`. Err(placeholder) if empty_ui.can_name(placeholder.universe) => { - self.tcx().mk_re_placeholder(placeholder) + ty::Region::new_placeholder(self.tcx(), placeholder) } Err(_) => self.tcx().lifetimes.re_static, }; diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index cd99fc31212..447d4c9f84b 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -251,14 +251,13 @@ pub struct InferCtxt<'tcx> { /// solving is left to borrowck instead. pub considering_regions: bool, - pub inner: RefCell<InferCtxtInner<'tcx>>, - /// If set, this flag causes us to skip the 'leak check' during /// higher-ranked subtyping operations. This flag is a temporary one used /// to manage the removal of the leak-check: for the time being, we still run the - /// leak-check, but we issue warnings. This flag can only be set to true - /// when entering a snapshot. - skip_leak_check: Cell<bool>, + /// leak-check, but we issue warnings. + skip_leak_check: bool, + + pub inner: RefCell<InferCtxtInner<'tcx>>, /// Once region inference is done, the values for each variable. lexical_region_resolutions: RefCell<Option<LexicalRegionResolutions<'tcx>>>, @@ -543,6 +542,7 @@ pub struct InferCtxtBuilder<'tcx> { tcx: TyCtxt<'tcx>, defining_use_anchor: DefiningAnchor, considering_regions: bool, + skip_leak_check: bool, /// Whether we are in coherence mode. intercrate: bool, } @@ -557,6 +557,7 @@ impl<'tcx> TyCtxtInferExt<'tcx> for TyCtxt<'tcx> { tcx: self, defining_use_anchor: DefiningAnchor::Error, considering_regions: true, + skip_leak_check: false, intercrate: false, } } @@ -584,6 +585,11 @@ impl<'tcx> InferCtxtBuilder<'tcx> { self } + pub fn skip_leak_check(mut self, skip_leak_check: bool) -> Self { + self.skip_leak_check = skip_leak_check; + self + } + /// Given a canonical value `C` as a starting point, create an /// inference context that contains each of the bound values /// within instantiated as a fresh variable. The `f` closure is @@ -605,11 +611,18 @@ impl<'tcx> InferCtxtBuilder<'tcx> { } pub fn build(&mut self) -> InferCtxt<'tcx> { - let InferCtxtBuilder { tcx, defining_use_anchor, considering_regions, intercrate } = *self; + let InferCtxtBuilder { + tcx, + defining_use_anchor, + considering_regions, + skip_leak_check, + intercrate, + } = *self; InferCtxt { tcx, defining_use_anchor, considering_regions, + skip_leak_check, inner: RefCell::new(InferCtxtInner::new()), lexical_region_resolutions: RefCell::new(None), selection_cache: Default::default(), @@ -619,7 +632,6 @@ impl<'tcx> InferCtxtBuilder<'tcx> { tainted_by_errors: Cell::new(None), err_count_on_creation: tcx.sess.err_count(), in_snapshot: Cell::new(false), - skip_leak_check: Cell::new(false), universe: Cell::new(ty::UniverseIndex::ROOT), intercrate, } @@ -815,32 +827,9 @@ impl<'tcx> InferCtxt<'tcx> { r } - /// If `should_skip` is true, then execute `f` then unroll any bindings it creates. - #[instrument(skip(self, f), level = "debug")] - pub fn probe_maybe_skip_leak_check<R, F>(&self, should_skip: bool, f: F) -> R - where - F: FnOnce(&CombinedSnapshot<'tcx>) -> R, - { - let snapshot = self.start_snapshot(); - let was_skip_leak_check = self.skip_leak_check.get(); - if should_skip { - self.skip_leak_check.set(true); - } - let r = f(&snapshot); - self.rollback_to("probe", snapshot); - self.skip_leak_check.set(was_skip_leak_check); - r - } - - /// Scan the constraints produced since `snapshot` began and returns: - /// - /// - `None` -- if none of them involves "region outlives" constraints. - /// - `Some(true)` -- if there are `'a: 'b` constraints where `'a` or `'b` is a placeholder. - /// - `Some(false)` -- if there are `'a: 'b` constraints but none involve placeholders. - pub fn region_constraints_added_in_snapshot( - &self, - snapshot: &CombinedSnapshot<'tcx>, - ) -> Option<bool> { + /// Scan the constraints produced since `snapshot` and check whether + /// we added any region constraints. + pub fn region_constraints_added_in_snapshot(&self, snapshot: &CombinedSnapshot<'tcx>) -> bool { self.inner .borrow_mut() .unwrap_region_constraints() @@ -1065,7 +1054,7 @@ impl<'tcx> InferCtxt<'tcx> { ) -> ty::Region<'tcx> { let region_var = self.inner.borrow_mut().unwrap_region_constraints().new_region_var(universe, origin); - self.tcx.mk_re_var(region_var) + ty::Region::new_var(self.tcx, region_var) } /// Return the universe that the region `r` was created in. For diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs index 9d5ec228d82..105a3f08c82 100644 --- a/compiler/rustc_infer/src/infer/opaque_types.rs +++ b/compiler/rustc_infer/src/infer/opaque_types.rs @@ -533,17 +533,29 @@ impl<'tcx> InferCtxt<'tcx> { // these are the same span, but not in cases like `-> (impl // Foo, impl Bar)`. let span = cause.span; - let prev = self.inner.borrow_mut().opaque_types().register( - opaque_type_key, - OpaqueHiddenType { ty: hidden_ty, span }, - origin, - ); - let mut obligations = if let Some(prev) = prev { - self.at(&cause, param_env) - .eq_exp(DefineOpaqueTypes::Yes, a_is_expected, prev, hidden_ty)? - .obligations + let mut obligations = if self.intercrate { + // During intercrate we do not define opaque types but instead always + // force ambiguity unless the hidden type is known to not implement + // our trait. + vec![traits::Obligation::new( + self.tcx, + cause.clone(), + param_env, + ty::PredicateKind::Ambiguous, + )] } else { - Vec::new() + let prev = self.inner.borrow_mut().opaque_types().register( + opaque_type_key, + OpaqueHiddenType { ty: hidden_ty, span }, + origin, + ); + if let Some(prev) = prev { + self.at(&cause, param_env) + .eq_exp(DefineOpaqueTypes::Yes, a_is_expected, prev, hidden_ty)? + .obligations + } else { + Vec::new() + } }; self.add_item_bounds_for_hidden_type( diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs index c2bf0f3db25..59ae2ce6c60 100644 --- a/compiler/rustc_infer/src/infer/outlives/verify.rs +++ b/compiler/rustc_infer/src/infer/outlives/verify.rs @@ -293,7 +293,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { ) -> impl Iterator<Item = ty::Region<'tcx>> { let tcx = self.tcx; let bounds = tcx.item_bounds(alias_ty.def_id); - trace!("{:#?}", bounds.0); + trace!("{:#?}", bounds.skip_binder()); bounds .subst_iter(tcx, alias_ty.substs) .filter_map(|p| p.to_opt_type_outlives()) 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 89cfc9ea3d1..dd65f66ccd1 100644 --- a/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs +++ b/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs @@ -3,7 +3,6 @@ use crate::infer::CombinedSnapshot; use rustc_data_structures::{ fx::FxIndexMap, graph::{scc::Sccs, vec_graph::VecGraph}, - undo_log::UndoLogs, }; use rustc_index::Idx; use rustc_middle::ty::error::TypeError; @@ -13,7 +12,9 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { /// Searches new universes created during `snapshot`, looking for /// placeholders that may "leak" out from the universes they are contained /// in. If any leaking placeholders are found, then an `Err` is returned - /// (typically leading to the snapshot being reversed). + /// (typically leading to the snapshot being reversed). This algorithm + /// only looks at placeholders which cannot be named by `outer_universe`, + /// as this is the universe we're currently checking for a leak. /// /// The leak check *used* to be the only way we had to handle higher-ranked /// obligations. Now that we have integrated universes into the region @@ -55,6 +56,12 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { /// * if they must also be equal to a placeholder P, and U cannot name P, report an error, as that /// indicates `P: R` and `R` is in an incompatible universe /// + /// To improve performance and for the old trait solver caching to be sound, this takes + /// an optional snapshot in which case we only look at region constraints added in that + /// snapshot. If we were to not do that the `leak_check` during evaluation can rely on + /// region constraints added outside of that evaluation. As that is not reflected in the + /// cache key this would be unsound. + /// /// # Historical note /// /// Older variants of the leak check used to report errors for these @@ -62,36 +69,21 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { /// /// * R: P1, even if R cannot name P1, because R = 'static is a valid sol'n /// * R: P1, R: P2, as above + #[instrument(level = "debug", skip(self, tcx, only_consider_snapshot), ret)] pub fn leak_check( &mut self, tcx: TyCtxt<'tcx>, - overly_polymorphic: bool, + outer_universe: ty::UniverseIndex, max_universe: ty::UniverseIndex, - snapshot: &CombinedSnapshot<'tcx>, + only_consider_snapshot: Option<&CombinedSnapshot<'tcx>>, ) -> RelateResult<'tcx, ()> { - debug!( - "leak_check(max_universe={:?}, snapshot.universe={:?}, overly_polymorphic={:?})", - max_universe, snapshot.universe, overly_polymorphic - ); - - assert!(UndoLogs::<super::UndoLog<'_>>::in_snapshot(&self.undo_log)); - - let universe_at_start_of_snapshot = snapshot.universe; - if universe_at_start_of_snapshot == max_universe { + if outer_universe == max_universe { return Ok(()); } - let mini_graph = - &MiniGraph::new(tcx, self.undo_log.region_constraints(), &self.storage.data.verifys); + let mini_graph = &MiniGraph::new(tcx, &self, only_consider_snapshot); - let mut leak_check = LeakCheck::new( - tcx, - universe_at_start_of_snapshot, - max_universe, - overly_polymorphic, - mini_graph, - self, - ); + let mut leak_check = LeakCheck::new(tcx, outer_universe, max_universe, mini_graph, self); leak_check.assign_placeholder_values()?; leak_check.propagate_scc_value()?; Ok(()) @@ -100,9 +92,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { struct LeakCheck<'me, 'tcx> { tcx: TyCtxt<'tcx>, - universe_at_start_of_snapshot: ty::UniverseIndex, - /// Only used when reporting region errors. - overly_polymorphic: bool, + outer_universe: ty::UniverseIndex, mini_graph: &'me MiniGraph<'tcx>, rcc: &'me RegionConstraintCollector<'me, 'tcx>, @@ -130,17 +120,15 @@ struct LeakCheck<'me, 'tcx> { impl<'me, 'tcx> LeakCheck<'me, 'tcx> { fn new( tcx: TyCtxt<'tcx>, - universe_at_start_of_snapshot: ty::UniverseIndex, + outer_universe: ty::UniverseIndex, max_universe: ty::UniverseIndex, - overly_polymorphic: bool, mini_graph: &'me MiniGraph<'tcx>, rcc: &'me RegionConstraintCollector<'me, 'tcx>, ) -> Self { let dummy_scc_universe = SccUniverse { universe: max_universe, region: None }; Self { tcx, - universe_at_start_of_snapshot, - overly_polymorphic, + outer_universe, mini_graph, rcc, scc_placeholders: IndexVec::from_elem_n(None, mini_graph.sccs.num_sccs()), @@ -165,7 +153,7 @@ impl<'me, 'tcx> LeakCheck<'me, 'tcx> { // Detect those SCCs that directly contain a placeholder if let ty::RePlaceholder(placeholder) = **region { - if self.universe_at_start_of_snapshot.cannot_name(placeholder.universe) { + if self.outer_universe.cannot_name(placeholder.universe) { self.assign_scc_value(scc, placeholder)?; } } @@ -280,7 +268,7 @@ impl<'me, 'tcx> LeakCheck<'me, 'tcx> { placeholder1: ty::PlaceholderRegion, placeholder2: ty::PlaceholderRegion, ) -> TypeError<'tcx> { - self.error(placeholder1, self.tcx.mk_re_placeholder(placeholder2)) + self.error(placeholder1, ty::Region::new_placeholder(self.tcx, placeholder2)) } fn error( @@ -289,11 +277,7 @@ impl<'me, 'tcx> LeakCheck<'me, 'tcx> { other_region: ty::Region<'tcx>, ) -> TypeError<'tcx> { debug!("error: placeholder={:?}, other_region={:?}", placeholder, other_region); - if self.overly_polymorphic { - TypeError::RegionsOverlyPolymorphic(placeholder.bound.kind, other_region) - } else { - TypeError::RegionsInsufficientlyPolymorphic(placeholder.bound.kind, other_region) - } + TypeError::RegionsInsufficientlyPolymorphic(placeholder.bound.kind, other_region) } } @@ -379,56 +363,70 @@ struct MiniGraph<'tcx> { } impl<'tcx> MiniGraph<'tcx> { - fn new<'a>( + fn new( tcx: TyCtxt<'tcx>, - undo_log: impl Iterator<Item = &'a UndoLog<'tcx>>, - verifys: &[Verify<'tcx>], - ) -> Self - where - 'tcx: 'a, - { + region_constraints: &RegionConstraintCollector<'_, 'tcx>, + only_consider_snapshot: Option<&CombinedSnapshot<'tcx>>, + ) -> Self { let mut nodes = FxIndexMap::default(); let mut edges = Vec::new(); // Note that if `R2: R1`, we get a callback `r1, r2`, so `target` is first parameter. - Self::iterate_undo_log(tcx, undo_log, verifys, |target, source| { - let source_node = Self::add_node(&mut nodes, source); - let target_node = Self::add_node(&mut nodes, target); - edges.push((source_node, target_node)); - }); + Self::iterate_region_constraints( + tcx, + region_constraints, + only_consider_snapshot, + |target, source| { + let source_node = Self::add_node(&mut nodes, source); + let target_node = Self::add_node(&mut nodes, target); + edges.push((source_node, target_node)); + }, + ); let graph = VecGraph::new(nodes.len(), edges); let sccs = Sccs::new(&graph); Self { nodes, sccs } } /// Invokes `each_edge(R1, R2)` for each edge where `R2: R1` - fn iterate_undo_log<'a>( + fn iterate_region_constraints( tcx: TyCtxt<'tcx>, - undo_log: impl Iterator<Item = &'a UndoLog<'tcx>>, - verifys: &[Verify<'tcx>], + region_constraints: &RegionConstraintCollector<'_, 'tcx>, + only_consider_snapshot: Option<&CombinedSnapshot<'tcx>>, mut each_edge: impl FnMut(ty::Region<'tcx>, ty::Region<'tcx>), - ) where - 'tcx: 'a, - { - for undo_entry in undo_log { - match undo_entry { - &AddConstraint(Constraint::VarSubVar(a, b)) => { - each_edge(tcx.mk_re_var(a), tcx.mk_re_var(b)); - } - &AddConstraint(Constraint::RegSubVar(a, b)) => { - each_edge(a, tcx.mk_re_var(b)); - } - &AddConstraint(Constraint::VarSubReg(a, b)) => { - each_edge(tcx.mk_re_var(a), b); - } - &AddConstraint(Constraint::RegSubReg(a, b)) => { - each_edge(a, b); + ) { + let mut each_constraint = |constraint| match constraint { + &Constraint::VarSubVar(a, b) => { + each_edge(ty::Region::new_var(tcx, a), ty::Region::new_var(tcx, b)); + } + &Constraint::RegSubVar(a, b) => { + each_edge(a, ty::Region::new_var(tcx, b)); + } + &Constraint::VarSubReg(a, b) => { + each_edge(ty::Region::new_var(tcx, a), b); + } + &Constraint::RegSubReg(a, b) => { + each_edge(a, b); + } + }; + + if let Some(snapshot) = only_consider_snapshot { + for undo_entry in + region_constraints.undo_log.region_constraints_in_snapshot(&snapshot.undo_snapshot) + { + match undo_entry { + AddConstraint(constraint) => { + each_constraint(constraint); + } + &AddVerify(i) => span_bug!( + region_constraints.data().verifys[i].origin.span(), + "we never add verifications while doing higher-ranked things", + ), + &AddCombination(..) | &AddVar(..) => {} } - &AddVerify(i) => span_bug!( - verifys[i].origin.span(), - "we never add verifications while doing higher-ranked things", - ), - &AddCombination(..) | &AddVar(..) => {} + } + } else { + for (constraint, _origin) in ®ion_constraints.data().constraints { + each_constraint(constraint) } } } diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs index c7a307b89e4..613da8a0b45 100644 --- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs +++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs @@ -400,7 +400,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { data } - pub(super) fn data(&self) -> &RegionConstraintData<'tcx> { + pub fn data(&self) -> &RegionConstraintData<'tcx> { &self.data } @@ -610,13 +610,13 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { let resolved = ut .probe_value(root_vid) .get_value_ignoring_universes() - .unwrap_or_else(|| tcx.mk_re_var(root_vid)); + .unwrap_or_else(|| ty::Region::new_var(tcx, root_vid)); // Don't resolve a variable to a region that it cannot name. if self.var_universe(vid).can_name(self.universe(resolved)) { resolved } else { - tcx.mk_re_var(vid) + ty::Region::new_var(tcx, vid) } } @@ -637,7 +637,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { ) -> Region<'tcx> { let vars = TwoRegions { a, b }; if let Some(&c) = self.combine_map(t).get(&vars) { - return tcx.mk_re_var(c); + return ty::Region::new_var(tcx, c); } let a_universe = self.universe(a); let b_universe = self.universe(b); @@ -645,7 +645,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { let c = self.new_region_var(c_universe, MiscVariable(origin.span())); self.combine_map(t).insert(vars, c); self.undo_log.push(AddCombination(t, vars)); - let new_r = tcx.mk_re_var(c); + let new_r = ty::Region::new_var(tcx, c); for old_r in [a, b] { match t { Glb => self.make_subregion(origin.clone(), new_r, old_r), @@ -683,15 +683,10 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { } /// See `InferCtxt::region_constraints_added_in_snapshot`. - pub fn region_constraints_added_in_snapshot(&self, mark: &Snapshot<'tcx>) -> Option<bool> { + pub fn region_constraints_added_in_snapshot(&self, mark: &Snapshot<'tcx>) -> bool { self.undo_log .region_constraints_in_snapshot(mark) - .map(|&elt| match elt { - AddConstraint(constraint) => Some(constraint.involves_placeholders()), - _ => None, - }) - .max() - .unwrap_or(None) + .any(|&elt| matches!(elt, AddConstraint(_))) } #[inline] diff --git a/compiler/rustc_infer/src/infer/undo_log.rs b/compiler/rustc_infer/src/infer/undo_log.rs index 955c54e8515..25d06b21ec8 100644 --- a/compiler/rustc_infer/src/infer/undo_log.rs +++ b/compiler/rustc_infer/src/infer/undo_log.rs @@ -138,11 +138,9 @@ impl<'tcx> InferCtxtInner<'tcx> { } if self.undo_log.num_open_snapshots == 1 { - // The root snapshot. It's safe to clear the undo log because - // there's no snapshot further out that we might need to roll back - // to. + // After the root snapshot the undo log should be empty. assert!(snapshot.undo_len == 0); - self.undo_log.logs.clear(); + assert!(self.undo_log.logs.is_empty()); } self.undo_log.num_open_snapshots -= 1; @@ -183,15 +181,6 @@ impl<'tcx> InferCtxtUndoLogs<'tcx> { self.logs[s.undo_len..].iter().any(|log| matches!(log, UndoLog::OpaqueTypes(..))) } - pub(crate) fn region_constraints( - &self, - ) -> impl Iterator<Item = &'_ region_constraints::UndoLog<'tcx>> + Clone { - self.logs.iter().filter_map(|log| match log { - UndoLog::RegionConstraintCollector(log) => Some(log), - _ => None, - }) - } - fn assert_open_snapshot(&self, snapshot: &Snapshot<'tcx>) { // Failures here may indicate a failure to follow a stack discipline. assert!(self.logs.len() >= snapshot.undo_len); diff --git a/compiler/rustc_interface/messages.ftl b/compiler/rustc_interface/messages.ftl index 37994899a20..be1a75f020b 100644 --- a/compiler/rustc_interface/messages.ftl +++ b/compiler/rustc_interface/messages.ftl @@ -1,33 +1,43 @@ -interface_ferris_identifier = - Ferris cannot be used as an identifier - .suggestion = try using their name instead +interface_cant_emit_mir = + could not emit MIR: {$error} interface_emoji_identifier = identifiers cannot contain emoji: `{$ident}` -interface_mixed_bin_crate = - cannot mix `bin` crate type with others - -interface_mixed_proc_macro_crate = - cannot mix `proc-macro` crate type with others - interface_error_writing_dependencies = error writing dependencies to `{$path}`: {$error} -interface_input_file_would_be_overwritten = - the input file "{$path}" would be overwritten by the generated executable +interface_failed_writing_file = + failed to write file {$path}: {$error}" + +interface_ferris_identifier = + Ferris cannot be used as an identifier + .suggestion = try using their name instead interface_generated_file_conflicts_with_directory = the generated executable for the input file "{$input_path}" conflicts with the existing directory "{$dir_path}" -interface_temps_dir_error = - failed to find or create the directory specified by `--temps-dir` +interface_ignoring_extra_filename = ignoring -C extra-filename flag due to -o flag + +interface_ignoring_out_dir = ignoring --out-dir flag due to -o flag + +interface_input_file_would_be_overwritten = + the input file "{$path}" would be overwritten by the generated executable + +interface_mixed_bin_crate = + cannot mix `bin` crate type with others + +interface_mixed_proc_macro_crate = + cannot mix `proc-macro` crate type with others + +interface_multiple_output_types_adaption = + due to multiple output types requested, the explicitly specified output file name will be adapted for each output type interface_out_dir_error = failed to find or create the directory specified by `--out-dir` -interface_cant_emit_mir = - could not emit MIR: {$error} +interface_proc_macro_crate_panic_abort = + building proc macro crate with `panic=abort` may crash the compiler should the proc-macro panic interface_rustc_error_fatal = fatal error triggered by #[rustc_error] @@ -35,18 +45,8 @@ interface_rustc_error_fatal = interface_rustc_error_unexpected_annotation = unexpected annotation used with `#[rustc_error(...)]`! -interface_failed_writing_file = - failed to write file {$path}: {$error}" - -interface_proc_macro_crate_panic_abort = - building proc macro crate with `panic=abort` may crash the compiler should the proc-macro panic +interface_temps_dir_error = + failed to find or create the directory specified by `--temps-dir` interface_unsupported_crate_type_for_target = dropping unsupported crate type `{$crate_type}` for target `{$target_triple}` - -interface_multiple_output_types_adaption = - due to multiple output types requested, the explicitly specified output file name will be adapted for each output type - -interface_ignoring_extra_filename = ignoring -C extra-filename flag due to -o flag - -interface_ignoring_out_dir = ignoring --out-dir flag due to -o flag diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index e1658d3ff82..e707ac41a05 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -5,6 +5,202 @@ lint_array_into_iter = .use_explicit_into_iter_suggestion = or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value +lint_atomic_ordering_fence = memory fences cannot have `Relaxed` ordering + .help = consider using ordering modes `Acquire`, `Release`, `AcqRel` or `SeqCst` + +lint_atomic_ordering_invalid = `{$method}`'s failure ordering may not be `Release` or `AcqRel`, since a failed `{$method}` does not result in a write + .label = invalid failure ordering + .help = consider using `Acquire` or `Relaxed` failure ordering instead + +lint_atomic_ordering_load = atomic loads cannot have `Release` or `AcqRel` ordering + .help = consider using ordering modes `Acquire`, `SeqCst` or `Relaxed` + +lint_atomic_ordering_store = atomic stores cannot have `Acquire` or `AcqRel` ordering + .help = consider using ordering modes `Release`, `SeqCst` or `Relaxed` + +lint_bad_attribute_argument = bad attribute argument + +lint_bad_opt_access = {$msg} + +lint_builtin_allow_internal_unsafe = + `allow_internal_unsafe` allows defining macros using unsafe without triggering the `unsafe_code` lint at their call site + +lint_builtin_anonymous_params = anonymous parameters are deprecated and will be removed in the next edition + .suggestion = try naming the parameter or explicitly ignoring it + +lint_builtin_asm_labels = avoid using named labels in inline assembly + +lint_builtin_box_pointers = type uses owned (Box type) pointers: {$ty} + +lint_builtin_clashing_extern_diff_name = `{$this}` redeclares `{$orig}` with a different signature + .previous_decl_label = `{$orig}` previously declared here + .mismatch_label = this signature doesn't match the previous declaration + +lint_builtin_clashing_extern_same_name = `{$this}` redeclared with a different signature + .previous_decl_label = `{$orig}` previously declared here + .mismatch_label = this signature doesn't match the previous declaration +lint_builtin_const_no_mangle = const items should never be `#[no_mangle]` + .suggestion = try a static value + +lint_builtin_decl_unsafe_fn = declaration of an `unsafe` function +lint_builtin_decl_unsafe_method = declaration of an `unsafe` method +lint_builtin_deprecated_attr_default_suggestion = remove this attribute + +lint_builtin_deprecated_attr_link = use of deprecated attribute `{$name}`: {$reason}. See {$link} + .msg_suggestion = {$msg} + .default_suggestion = remove this attribute +lint_builtin_deprecated_attr_used = use of deprecated attribute `{$name}`: no longer used. +lint_builtin_deref_nullptr = dereferencing a null pointer + .label = this code causes undefined behavior when executed + +lint_builtin_ellipsis_inclusive_range_patterns = `...` range patterns are deprecated + .suggestion = use `..=` for an inclusive range + +lint_builtin_explicit_outlives = outlives requirements can be inferred + .suggestion = remove {$count -> + [one] this bound + *[other] these bounds + } + +lint_builtin_export_name_fn = declaration of a function with `export_name` +lint_builtin_export_name_method = declaration of a method with `export_name` + +lint_builtin_export_name_static = declaration of a static with `export_name` +lint_builtin_impl_unsafe_method = implementation of an `unsafe` method + +lint_builtin_incomplete_features = the feature `{$name}` is incomplete and may not be safe to use and/or cause compiler crashes + .note = see issue #{$n} <https://github.com/rust-lang/rust/issues/{$n}> for more information + .help = consider using `min_{$name}` instead, which is more stable and complete + +lint_builtin_keyword_idents = `{$kw}` is a keyword in the {$next} edition + .suggestion = you can use a raw identifier to stay compatible + +lint_builtin_link_section_fn = declaration of a function with `link_section` + +lint_builtin_link_section_static = declaration of a static with `link_section` + +lint_builtin_missing_copy_impl = type could implement `Copy`; consider adding `impl Copy` + +lint_builtin_missing_debug_impl = + type does not implement `{$debug}`; consider adding `#[derive(Debug)]` or a manual implementation + +lint_builtin_missing_doc = missing documentation for {$article} {$desc} + +lint_builtin_mutable_transmutes = + transmuting &T to &mut T is undefined behavior, even if the reference is unused, consider instead using an UnsafeCell + +lint_builtin_no_mangle_fn = declaration of a `no_mangle` function +lint_builtin_no_mangle_generic = functions generic over types or consts must be mangled + .suggestion = remove this attribute + +lint_builtin_no_mangle_method = declaration of a `no_mangle` method +lint_builtin_no_mangle_static = declaration of a `no_mangle` static +lint_builtin_non_shorthand_field_patterns = the `{$ident}:` in this pattern is redundant + .suggestion = use shorthand field pattern + +lint_builtin_overridden_symbol_name = + the linker's behavior with multiple libraries exporting duplicate symbol names is undefined and Rust cannot provide guarantees when you manually override them + +lint_builtin_overridden_symbol_section = + the program's behavior with overridden link sections on items is unpredictable and Rust cannot provide guarantees when you manually override them + +lint_builtin_special_module_name_used_lib = found module declaration for lib.rs + .note = lib.rs is the root of this crate's library target + .help = to refer to it from other targets, use the library's name as the path + +lint_builtin_special_module_name_used_main = found module declaration for main.rs + .note = a binary crate cannot be used as library + +lint_builtin_trivial_bounds = {$predicate_kind_name} bound {$predicate} does not depend on any type or lifetime parameters + +lint_builtin_type_alias_bounds_help = use fully disambiguated paths (i.e., `<T as Trait>::Assoc`) to refer to associated types in type aliases + +lint_builtin_type_alias_generic_bounds = bounds on generic parameters are not enforced in type aliases + .suggestion = the bound will not be checked when the type alias is used, and should be removed + +lint_builtin_type_alias_where_clause = where clauses are not enforced in type aliases + .suggestion = the clause will not be checked when the type alias is used, and should be removed + +lint_builtin_unexpected_cli_config_name = unexpected `{$name}` as condition name + .help = was set with `--cfg` but isn't in the `--check-cfg` expected names + +lint_builtin_unexpected_cli_config_value = unexpected condition value `{$value}` for condition name `{$name}` + .help = was set with `--cfg` but isn't in the `--check-cfg` expected values + +lint_builtin_unnameable_test_items = cannot test inner items + +lint_builtin_unpermitted_type_init_label = this code causes undefined behavior when executed +lint_builtin_unpermitted_type_init_label_suggestion = help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done + +lint_builtin_unpermitted_type_init_uninit = the type `{$ty}` does not permit being left uninitialized + +lint_builtin_unpermitted_type_init_zeroed = the type `{$ty}` does not permit zero-initialization +lint_builtin_unreachable_pub = unreachable `pub` {$what} + .suggestion = consider restricting its visibility + .help = or consider exporting it for use by other crates + +lint_builtin_unsafe_block = usage of an `unsafe` block + +lint_builtin_unsafe_impl = implementation of an `unsafe` trait + +lint_builtin_unsafe_trait = declaration of an `unsafe` trait + +lint_builtin_unstable_features = unstable feature + +lint_builtin_unused_doc_comment = unused doc comment + .label = rustdoc does not generate documentation for {$kind} + .plain_help = use `//` for a plain comment + .block_help = use `/* */` for a plain comment + +lint_builtin_while_true = denote infinite loops with `loop {"{"} ... {"}"}` + .suggestion = use `loop` + +lint_check_name_deprecated = lint name `{$lint_name}` is deprecated and does not have an effect anymore. Use: {$new_name} + +lint_check_name_unknown = unknown lint: `{$lint_name}` + .help = did you mean: `{$suggestion}` + +lint_check_name_unknown_tool = unknown lint tool: `{$tool_name}` + +lint_check_name_warning = {$msg} + +lint_command_line_source = `forbid` lint level was set on command line + +lint_confusable_identifier_pair = identifier pair considered confusable between `{$existing_sym}` and `{$sym}` + .label = this is where the previous identifier occurred + +lint_cstring_ptr = getting the inner pointer of a temporary `CString` + .as_ptr_label = this pointer will be invalid + .unwrap_label = this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + .note = pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + .help = for more information, see https://doc.rust-lang.org/reference/destructors.html + +lint_default_hash_types = prefer `{$preferred}` over `{$used}`, it has better performance + .note = a `use rustc_data_structures::fx::{$preferred}` may be necessary + +lint_default_source = `forbid` lint level is the default for {$id} + +lint_deprecated_lint_name = + lint name `{$name}` is deprecated and may not have an effect in the future. + .suggestion = change it to + +lint_diag_out_of_impl = + diagnostics should only be created in `IntoDiagnostic`/`AddToDiagnostic` impls + +lint_drop_glue = + types that do not implement `Drop` can still have drop glue, consider instead using `{$needs_drop}` to detect whether a type is trivially dropped + +lint_drop_trait_constraints = + bounds on `{$predicate}` are most likely incorrect, consider instead using `{$needs_drop}` to detect whether a type can be trivially dropped + +lint_dropping_copy_types = calls to `std::mem::drop` with a value that implements `Copy` does nothing + .label = argument has type `{$arg_ty}` + .note = use `let _ = ...` to ignore the expression or result + +lint_dropping_references = calls to `std::mem::drop` with a reference instead of an owned value does nothing + .label = argument has type `{$arg_ty}` + .note = use `let _ = ...` to ignore the expression or result + lint_enum_intrinsics_mem_discriminant = the return value of `mem::discriminant` is unspecified when called with a non-enum type .note = the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `{$ty_param}`, which is not an enum. @@ -24,49 +220,12 @@ lint_for_loops_over_fallibles = .use_while_let = to check pattern in a loop use `while let` .use_question_mark = consider unwrapping the `Result` with `?` to iterate over its contents -lint_map_unit_fn = `Iterator::map` call that discard the iterator's values - .note = `Iterator::map`, like many of the methods on `Iterator`, gets executed lazily, meaning that its effects won't be visible until it is iterated - .function_label = this function returns `()`, which is likely not what you wanted - .argument_label = called `Iterator::map` with callable that returns `()` - .map_label = after this call to map, the resulting iterator is `impl Iterator<Item = ()>`, which means the only information carried by the iterator is the number of items - .suggestion = you might have meant to use `Iterator::for_each` - -lint_non_binding_let_on_sync_lock = - non-binding let on a synchronization lock - -lint_non_binding_let_on_drop_type = - non-binding let on a type that implements `Drop` - -lint_non_binding_let_suggestion = - consider binding to an unused variable to avoid immediately dropping the value - -lint_non_binding_let_multi_suggestion = - consider immediately dropping the value - -lint_deprecated_lint_name = - lint name `{$name}` is deprecated and may not have an effect in the future. - .suggestion = change it to - -lint_renamed_or_removed_lint = {$msg} - .suggestion = use the new name - -lint_suspicious_double_ref_op = - using `.{$call}()` on a double reference, which returns `{$ty}` instead of {$op -> - *[should_not_happen] [{$op}] - [deref] dereferencing - [borrow] borrowing - [clone] cloning - } the inner type - -lint_unknown_lint = - unknown lint: `{$name}` - .suggestion = did you mean - -lint_ignored_unless_crate_specified = {$level}({$name}) is ignored unless specified at crate level - -lint_unknown_gated_lint = - unknown lint: `{$name}` - .note = the `{$name}` lint is unstable +lint_forgetting_copy_types = calls to `std::mem::forget` with a value that implements `Copy` does nothing + .label = argument has type `{$arg_ty}` + .note = use `let _ = ...` to ignore the expression or result +lint_forgetting_references = calls to `std::mem::forget` with a reference instead of an owned value does nothing + .label = argument has type `{$arg_ty}` + .note = use `let _ = ...` to ignore the expression or result lint_hidden_unicode_codepoints = unicode codepoint changing visible direction of text present in {$label} .label = this {$label} contains {$count -> @@ -81,56 +240,119 @@ lint_hidden_unicode_codepoints = unicode codepoint changing visible direction of .suggestion_escape = if you want to keep them but make them visible in your source code, you can escape them .no_suggestion_note_escape = if you want to keep them but make them visible in your source code, you can escape them: {$escaped} -lint_default_hash_types = prefer `{$preferred}` over `{$used}`, it has better performance - .note = a `use rustc_data_structures::fx::{$preferred}` may be necessary +lint_identifier_non_ascii_char = identifier contains non-ASCII characters -lint_query_instability = using `{$query}` can result in unstable query results - .note = if you believe this case to be fine, allow this lint and add a comment explaining your rationale +lint_identifier_uncommon_codepoints = identifier contains uncommon Unicode codepoints -lint_tykind_kind = usage of `ty::TyKind::<kind>` - .suggestion = try using `ty::<kind>` directly +lint_ignored_unless_crate_specified = {$level}({$name}) is ignored unless specified at crate level -lint_tykind = usage of `ty::TyKind` - .help = try using `Ty` instead +lint_improper_ctypes = `extern` {$desc} uses type `{$ty}`, which is not FFI-safe + .label = not FFI-safe + .note = the type is defined here -lint_ty_qualified = usage of qualified `ty::{$ty}` - .suggestion = try importing it and using it unqualified +lint_improper_ctypes_128bit = 128-bit integers don't currently have a known stable ABI -lint_lintpass_by_hand = implementing `LintPass` by hand - .help = try using `declare_lint_pass!` or `impl_lint_pass!` instead +lint_improper_ctypes_array_help = consider passing a pointer to the array -lint_non_existent_doc_keyword = found non-existing keyword `{$keyword}` used in `#[doc(keyword = "...")]` - .help = only existing keywords are allowed in core/std +lint_improper_ctypes_array_reason = passing raw arrays by value is not FFI-safe +lint_improper_ctypes_box = box cannot be represented as a single pointer -lint_diag_out_of_impl = - diagnostics should only be created in `IntoDiagnostic`/`AddToDiagnostic` impls +lint_improper_ctypes_char_help = consider using `u32` or `libc::wchar_t` instead -lint_untranslatable_diag = diagnostics should be created using translatable messages +lint_improper_ctypes_char_reason = the `char` type has no C equivalent +lint_improper_ctypes_dyn = trait objects have no C equivalent -lint_trivial_untranslatable_diag = diagnostic with static strings only +lint_improper_ctypes_enum_phantomdata = this enum contains a PhantomData field -lint_bad_opt_access = {$msg} +lint_improper_ctypes_enum_repr_help = + consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum -lint_cstring_ptr = getting the inner pointer of a temporary `CString` - .as_ptr_label = this pointer will be invalid - .unwrap_label = this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime - .note = pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned - .help = for more information, see https://doc.rust-lang.org/reference/destructors.html +lint_improper_ctypes_enum_repr_reason = enum has no representation hint +lint_improper_ctypes_fnptr_help = consider using an `extern fn(...) -> ...` function pointer instead -lint_multiple_supertrait_upcastable = `{$ident}` is object-safe and has multiple supertraits +lint_improper_ctypes_fnptr_reason = this function pointer has Rust-specific calling convention +lint_improper_ctypes_non_exhaustive = this enum is non-exhaustive +lint_improper_ctypes_non_exhaustive_variant = this enum has non-exhaustive variants -lint_identifier_non_ascii_char = identifier contains non-ASCII characters +lint_improper_ctypes_only_phantomdata = composed only of `PhantomData` -lint_identifier_uncommon_codepoints = identifier contains uncommon Unicode codepoints +lint_improper_ctypes_opaque = opaque types have no C equivalent -lint_confusable_identifier_pair = identifier pair considered confusable between `{$existing_sym}` and `{$sym}` - .label = this is where the previous identifier occurred +lint_improper_ctypes_slice_help = consider using a raw pointer instead + +lint_improper_ctypes_slice_reason = slices have no C equivalent +lint_improper_ctypes_str_help = consider using `*const u8` and a length instead + +lint_improper_ctypes_str_reason = string slices have no C equivalent +lint_improper_ctypes_struct_fieldless_help = consider adding a member to this struct + +lint_improper_ctypes_struct_fieldless_reason = this struct has no fields +lint_improper_ctypes_struct_layout_help = consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct + +lint_improper_ctypes_struct_layout_reason = this struct has unspecified layout +lint_improper_ctypes_struct_non_exhaustive = this struct is non-exhaustive +lint_improper_ctypes_struct_zst = this struct contains only zero-sized fields + +lint_improper_ctypes_tuple_help = consider using a struct instead + +lint_improper_ctypes_tuple_reason = tuples have unspecified layout +lint_improper_ctypes_union_fieldless_help = consider adding a member to this union + +lint_improper_ctypes_union_fieldless_reason = this union has no fields +lint_improper_ctypes_union_layout_help = consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this union + +lint_improper_ctypes_union_layout_reason = this union has unspecified layout +lint_improper_ctypes_union_non_exhaustive = this union is non-exhaustive + +# FIXME: we should ordinalize $valid_up_to when we add support for doing so +lint_invalid_from_utf8_checked = calls to `{$method}` with a invalid literal always return an error + .label = the literal was valid UTF-8 up to the {$valid_up_to} bytes + +# FIXME: we should ordinalize $valid_up_to when we add support for doing so +lint_invalid_from_utf8_unchecked = calls to `{$method}` with a invalid literal are undefined behavior + .label = the literal was valid UTF-8 up to the {$valid_up_to} bytes + +lint_lintpass_by_hand = implementing `LintPass` by hand + .help = try using `declare_lint_pass!` or `impl_lint_pass!` instead + +lint_malformed_attribute = malformed lint attribute input + +lint_map_unit_fn = `Iterator::map` call that discard the iterator's values + .note = `Iterator::map`, like many of the methods on `Iterator`, gets executed lazily, meaning that its effects won't be visible until it is iterated + .function_label = this function returns `()`, which is likely not what you wanted + .argument_label = called `Iterator::map` with callable that returns `()` + .map_label = after this call to map, the resulting iterator is `impl Iterator<Item = ()>`, which means the only information carried by the iterator is the number of items + .suggestion = you might have meant to use `Iterator::for_each` lint_mixed_script_confusables = the usage of Script Group `{$set}` in this crate consists solely of mixed script confusables .includes_note = the usage includes {$includes} .note = please recheck to make sure their usages are indeed what you want +lint_multiple_supertrait_upcastable = `{$ident}` is object-safe and has multiple supertraits + +lint_node_source = `forbid` level set here + .note = {$reason} + +lint_non_binding_let_multi_suggestion = + consider immediately dropping the value + +lint_non_binding_let_on_drop_type = + non-binding let on a type that implements `Drop` + +lint_non_binding_let_on_sync_lock = + non-binding let on a synchronization lock + +lint_non_binding_let_suggestion = + consider binding to an unused variable to avoid immediately dropping the value + +lint_non_camel_case_type = {$sort} `{$name}` should have an upper camel case name + .suggestion = convert the identifier to upper camel case + .label = should have an UpperCamelCase name + +lint_non_existent_doc_keyword = found non-existing keyword `{$keyword}` used in `#[doc(keyword = "...")]` + .help = only existing keywords are allowed in core/std + lint_non_fmt_panic = panic message is not a string literal .note = this usage of `{$name}!()` is deprecated; it will be a hard error in Rust 2021 .more_info_note = for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html> @@ -144,6 +366,14 @@ lint_non_fmt_panic = panic message is not a string literal *[false] use } std::panic::panic_any instead +lint_non_fmt_panic_braces = + panic message contains {$count -> + [one] a brace + *[other] braces + } + .note = this message is not used as a format string, but will be in Rust 2021 + .suggestion = add a "{"{"}{"}"}" format string to use the message literally + lint_non_fmt_panic_unused = panic message contains {$count -> [one] an unused @@ -159,18 +389,6 @@ lint_non_fmt_panic_unused = } .add_fmt_suggestion = or add a "{"{"}{"}"}" format string to use the message literally -lint_non_fmt_panic_braces = - panic message contains {$count -> - [one] a brace - *[other] braces - } - .note = this message is not used as a format string, but will be in Rust 2021 - .suggestion = add a "{"{"}{"}"}" format string to use the message literally - -lint_non_camel_case_type = {$sort} `{$name}` should have an upper camel case name - .suggestion = convert the identifier to upper camel case - .label = should have an UpperCamelCase name - lint_non_snake_case = {$sort} `{$name}` should have a snake case name .rename_or_convert_suggestion = rename the identifier or convert it to a snake case raw identifier .cannot_convert_note = `{$sc}` cannot be used as a raw identifier @@ -187,29 +405,13 @@ lint_noop_method_call = call to `.{$method}()` on a reference in this situation .label = unnecessary method call .note = the type `{$receiver_ty}` which `{$method}` is being called on is the same as the type returned from `{$method}`, so the method call does not do anything and can be removed -lint_pass_by_value = passing `{$ty}` by reference - .suggestion = try passing by value - -lint_redundant_semicolons = - unnecessary trailing {$multiple -> - [true] semicolons - *[false] semicolon - } - .suggestion = remove {$multiple -> - [true] these semicolons - *[false] this semicolon - } - -lint_drop_trait_constraints = - bounds on `{$predicate}` are most likely incorrect, consider instead using `{$needs_drop}` to detect whether a type can be trivially dropped - -lint_drop_glue = - types that do not implement `Drop` can still have drop glue, consider instead using `{$needs_drop}` to detect whether a type is trivially dropped - -lint_range_endpoint_out_of_range = range endpoint is out of range for `{$ty}` +lint_only_cast_u8_to_char = only `u8` can be cast into `char` + .suggestion = use a `char` literal instead -lint_range_use_inclusive_range = use an inclusive range instead +lint_opaque_hidden_inferred_bound = opaque type `{$ty}` does not satisfy its associated type bounds + .specifically = this associated type bound is unsatisfied for `{$proj_ty}` +lint_opaque_hidden_inferred_bound_sugg = add this bound lint_overflowing_bin_hex = literal out of range for `{$ty}` .negative_note = the literal `{$lit}` (decimal `{$dec}`) does not fit into the type `{$ty}` @@ -222,96 +424,92 @@ lint_overflowing_int = literal out of range for `{$ty}` .note = the literal `{$lit}` does not fit into the type `{$ty}` whose range is `{$min}..={$max}` .help = consider using the type `{$suggestion_ty}` instead -lint_only_cast_u8_to_char = only `u8` can be cast into `char` - .suggestion = use a `char` literal instead - -lint_overflowing_uint = literal out of range for `{$ty}` - .note = the literal `{$lit}` does not fit into the type `{$ty}` whose range is `{$min}..={$max}` - lint_overflowing_literal = literal out of range for `{$ty}` .note = the literal `{$lit}` does not fit into the type `{$ty}` and will be converted to `{$ty}::INFINITY` -lint_unused_comparisons = comparison is useless due to type limits - -lint_improper_ctypes = `extern` {$desc} uses type `{$ty}`, which is not FFI-safe - .label = not FFI-safe - .note = the type is defined here - -lint_improper_ctypes_opaque = opaque types have no C equivalent +lint_overflowing_uint = literal out of range for `{$ty}` + .note = the literal `{$lit}` does not fit into the type `{$ty}` whose range is `{$min}..={$max}` -lint_improper_ctypes_fnptr_reason = this function pointer has Rust-specific calling convention -lint_improper_ctypes_fnptr_help = consider using an `extern fn(...) -> ...` function pointer instead +lint_overruled_attribute = {$lint_level}({$lint_source}) incompatible with previous forbid + .label = overruled by previous forbid -lint_improper_ctypes_tuple_reason = tuples have unspecified layout -lint_improper_ctypes_tuple_help = consider using a struct instead +lint_pass_by_value = passing `{$ty}` by reference + .suggestion = try passing by value -lint_improper_ctypes_str_reason = string slices have no C equivalent -lint_improper_ctypes_str_help = consider using `*const u8` and a length instead +lint_path_statement_drop = path statement drops value + .suggestion = use `drop` to clarify the intent -lint_improper_ctypes_dyn = trait objects have no C equivalent +lint_path_statement_no_effect = path statement with no effect -lint_improper_ctypes_slice_reason = slices have no C equivalent -lint_improper_ctypes_slice_help = consider using a raw pointer instead +lint_query_instability = using `{$query}` can result in unstable query results + .note = if you believe this case to be fine, allow this lint and add a comment explaining your rationale -lint_improper_ctypes_128bit = 128-bit integers don't currently have a known stable ABI +lint_range_endpoint_out_of_range = range endpoint is out of range for `{$ty}` -lint_improper_ctypes_char_reason = the `char` type has no C equivalent -lint_improper_ctypes_char_help = consider using `u32` or `libc::wchar_t` instead +lint_range_use_inclusive_range = use an inclusive range instead -lint_improper_ctypes_non_exhaustive = this enum is non-exhaustive -lint_improper_ctypes_non_exhaustive_variant = this enum has non-exhaustive variants -lint_improper_ctypes_enum_repr_reason = enum has no representation hint -lint_improper_ctypes_enum_repr_help = - consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum +lint_reason_must_be_string_literal = reason must be a string literal -lint_improper_ctypes_struct_fieldless_reason = this struct has no fields -lint_improper_ctypes_struct_fieldless_help = consider adding a member to this struct +lint_reason_must_come_last = reason in lint attribute must come last -lint_improper_ctypes_union_fieldless_reason = this union has no fields -lint_improper_ctypes_union_fieldless_help = consider adding a member to this union +lint_redundant_semicolons = + unnecessary trailing {$multiple -> + [true] semicolons + *[false] semicolon + } + .suggestion = remove {$multiple -> + [true] these semicolons + *[false] this semicolon + } -lint_improper_ctypes_struct_non_exhaustive = this struct is non-exhaustive -lint_improper_ctypes_union_non_exhaustive = this union is non-exhaustive +lint_renamed_or_removed_lint = {$msg} + .suggestion = use the new name -lint_improper_ctypes_struct_layout_reason = this struct has unspecified layout -lint_improper_ctypes_struct_layout_help = consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct +lint_requested_level = requested on the command line with `{$level} {$lint_name}` -lint_improper_ctypes_union_layout_reason = this union has unspecified layout -lint_improper_ctypes_union_layout_help = consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this union +lint_supertrait_as_deref_target = `{$t}` implements `Deref` with supertrait `{$target_principal}` as target + .label = target type is set here -lint_improper_ctypes_box = box cannot be represented as a single pointer +lint_suspicious_double_ref_op = + using `.{$call}()` on a double reference, which returns `{$ty}` instead of {$op -> + *[should_not_happen] [{$op}] + [deref] dereferencing + [borrow] borrowing + [clone] cloning + } the inner type -lint_improper_ctypes_enum_phantomdata = this enum contains a PhantomData field +lint_trivial_untranslatable_diag = diagnostic with static strings only -lint_improper_ctypes_struct_zst = this struct contains only zero-sized fields +lint_ty_qualified = usage of qualified `ty::{$ty}` + .suggestion = try importing it and using it unqualified -lint_improper_ctypes_array_reason = passing raw arrays by value is not FFI-safe -lint_improper_ctypes_array_help = consider passing a pointer to the array +lint_tykind = usage of `ty::TyKind` + .help = try using `Ty` instead -lint_improper_ctypes_only_phantomdata = composed only of `PhantomData` +lint_tykind_kind = usage of `ty::TyKind::<kind>` + .suggestion = try using `ty::<kind>` directly -lint_variant_size_differences = - enum variant is more than three times larger ({$largest} bytes) than the next largest +lint_ungated_async_fn_track_caller = `#[track_caller]` on async functions is a no-op + .label = this function will not propagate the caller location -lint_atomic_ordering_load = atomic loads cannot have `Release` or `AcqRel` ordering - .help = consider using ordering modes `Acquire`, `SeqCst` or `Relaxed` +lint_unknown_gated_lint = + unknown lint: `{$name}` + .note = the `{$name}` lint is unstable -lint_atomic_ordering_store = atomic stores cannot have `Acquire` or `AcqRel` ordering - .help = consider using ordering modes `Release`, `SeqCst` or `Relaxed` +lint_unknown_lint = + unknown lint: `{$name}` + .suggestion = did you mean -lint_atomic_ordering_fence = memory fences cannot have `Relaxed` ordering - .help = consider using ordering modes `Acquire`, `Release`, `AcqRel` or `SeqCst` +lint_unknown_tool_in_scoped_lint = unknown tool name `{$tool_name}` found in scoped lint: `{$tool_name}::{$lint_name}` + .help = add `#![register_tool({$tool_name})]` to the crate root -lint_atomic_ordering_invalid = `{$method}`'s failure ordering may not be `Release` or `AcqRel`, since a failed `{$method}` does not result in a write - .label = invalid failure ordering - .help = consider using `Acquire` or `Relaxed` failure ordering instead +lint_unsupported_group = `{$lint_group}` lint group is not supported with ´--force-warn´ -lint_unused_op = unused {$op} that must be used - .label = the {$op} produces a value - .suggestion = use `let _ = ...` to ignore the resulting value +lint_untranslatable_diag = diagnostics should be created using translatable messages -lint_unused_result = unused result of type `{$ty}` +lint_unused_allocation = unnecessary allocation, use `&` instead +lint_unused_allocation_mut = unnecessary allocation, use `&mut` instead lint_unused_closure = unused {$pre}{$count -> @@ -320,219 +518,28 @@ lint_unused_closure = }{$post} that must be used .note = closures are lazy and do nothing unless called -lint_unused_generator = - unused {$pre}{$count -> - [one] generator - *[other] generator - }{$post} that must be used - .note = generators are lazy and do nothing unless resumed +lint_unused_comparisons = comparison is useless due to type limits lint_unused_def = unused {$pre}`{$def}`{$post} that must be used .suggestion = use `let _ = ...` to ignore the resulting value -lint_path_statement_drop = path statement drops value - .suggestion = use `drop` to clarify the intent - -lint_path_statement_no_effect = path statement with no effect - lint_unused_delim = unnecessary {$delim} around {$item} .suggestion = remove these {$delim} -lint_unused_import_braces = braces around {$node} is unnecessary - -lint_unused_allocation = unnecessary allocation, use `&` instead -lint_unused_allocation_mut = unnecessary allocation, use `&mut` instead - -lint_builtin_while_true = denote infinite loops with `loop {"{"} ... {"}"}` - .suggestion = use `loop` - -lint_builtin_box_pointers = type uses owned (Box type) pointers: {$ty} - -lint_builtin_non_shorthand_field_patterns = the `{$ident}:` in this pattern is redundant - .suggestion = use shorthand field pattern - -lint_builtin_overridden_symbol_name = - the linker's behavior with multiple libraries exporting duplicate symbol names is undefined and Rust cannot provide guarantees when you manually override them - -lint_builtin_overridden_symbol_section = - the program's behavior with overridden link sections on items is unpredictable and Rust cannot provide guarantees when you manually override them - -lint_builtin_allow_internal_unsafe = - `allow_internal_unsafe` allows defining macros using unsafe without triggering the `unsafe_code` lint at their call site - -lint_builtin_unsafe_block = usage of an `unsafe` block - -lint_builtin_unsafe_trait = declaration of an `unsafe` trait - -lint_builtin_unsafe_impl = implementation of an `unsafe` trait - -lint_builtin_no_mangle_fn = declaration of a `no_mangle` function -lint_builtin_export_name_fn = declaration of a function with `export_name` -lint_builtin_link_section_fn = declaration of a function with `link_section` - -lint_builtin_no_mangle_static = declaration of a `no_mangle` static -lint_builtin_export_name_static = declaration of a static with `export_name` -lint_builtin_link_section_static = declaration of a static with `link_section` - -lint_builtin_no_mangle_method = declaration of a `no_mangle` method -lint_builtin_export_name_method = declaration of a method with `export_name` - -lint_builtin_decl_unsafe_fn = declaration of an `unsafe` function -lint_builtin_decl_unsafe_method = declaration of an `unsafe` method -lint_builtin_impl_unsafe_method = implementation of an `unsafe` method - -lint_builtin_missing_doc = missing documentation for {$article} {$desc} - -lint_builtin_missing_copy_impl = type could implement `Copy`; consider adding `impl Copy` - -lint_builtin_missing_debug_impl = - type does not implement `{$debug}`; consider adding `#[derive(Debug)]` or a manual implementation - -lint_builtin_anonymous_params = anonymous parameters are deprecated and will be removed in the next edition - .suggestion = try naming the parameter or explicitly ignoring it - -lint_builtin_deprecated_attr_link = use of deprecated attribute `{$name}`: {$reason}. See {$link} - .msg_suggestion = {$msg} - .default_suggestion = remove this attribute -lint_builtin_deprecated_attr_used = use of deprecated attribute `{$name}`: no longer used. -lint_builtin_deprecated_attr_default_suggestion = remove this attribute - -lint_builtin_unused_doc_comment = unused doc comment - .label = rustdoc does not generate documentation for {$kind} - .plain_help = use `//` for a plain comment - .block_help = use `/* */` for a plain comment - -lint_builtin_no_mangle_generic = functions generic over types or consts must be mangled - .suggestion = remove this attribute - -lint_builtin_const_no_mangle = const items should never be `#[no_mangle]` - .suggestion = try a static value - -lint_builtin_mutable_transmutes = - transmuting &T to &mut T is undefined behavior, even if the reference is unused, consider instead using an UnsafeCell - -lint_builtin_unstable_features = unstable feature - -lint_ungated_async_fn_track_caller = `#[track_caller]` on async functions is a no-op - .label = this function will not propagate the caller location - -lint_builtin_unreachable_pub = unreachable `pub` {$what} - .suggestion = consider restricting its visibility - .help = or consider exporting it for use by other crates - -lint_builtin_unexpected_cli_config_name = unexpected `{$name}` as condition name - .help = was set with `--cfg` but isn't in the `--check-cfg` expected names - -lint_builtin_unexpected_cli_config_value = unexpected condition value `{$value}` for condition name `{$name}` - .help = was set with `--cfg` but isn't in the `--check-cfg` expected values - -lint_builtin_type_alias_bounds_help = use fully disambiguated paths (i.e., `<T as Trait>::Assoc`) to refer to associated types in type aliases - -lint_builtin_type_alias_where_clause = where clauses are not enforced in type aliases - .suggestion = the clause will not be checked when the type alias is used, and should be removed - -lint_builtin_type_alias_generic_bounds = bounds on generic parameters are not enforced in type aliases - .suggestion = the bound will not be checked when the type alias is used, and should be removed - -lint_builtin_trivial_bounds = {$predicate_kind_name} bound {$predicate} does not depend on any type or lifetime parameters - -lint_builtin_ellipsis_inclusive_range_patterns = `...` range patterns are deprecated - .suggestion = use `..=` for an inclusive range - -lint_builtin_unnameable_test_items = cannot test inner items - -lint_builtin_keyword_idents = `{$kw}` is a keyword in the {$next} edition - .suggestion = you can use a raw identifier to stay compatible - -lint_builtin_explicit_outlives = outlives requirements can be inferred - .suggestion = remove {$count -> - [one] this bound - *[other] these bounds - } - -lint_builtin_incomplete_features = the feature `{$name}` is incomplete and may not be safe to use and/or cause compiler crashes - .note = see issue #{$n} <https://github.com/rust-lang/rust/issues/{$n}> for more information - .help = consider using `min_{$name}` instead, which is more stable and complete - -lint_builtin_unpermitted_type_init_zeroed = the type `{$ty}` does not permit zero-initialization -lint_builtin_unpermitted_type_init_uninit = the type `{$ty}` does not permit being left uninitialized - -lint_builtin_unpermitted_type_init_label = this code causes undefined behavior when executed -lint_builtin_unpermitted_type_init_label_suggestion = help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done - -lint_builtin_clashing_extern_same_name = `{$this}` redeclared with a different signature - .previous_decl_label = `{$orig}` previously declared here - .mismatch_label = this signature doesn't match the previous declaration -lint_builtin_clashing_extern_diff_name = `{$this}` redeclares `{$orig}` with a different signature - .previous_decl_label = `{$orig}` previously declared here - .mismatch_label = this signature doesn't match the previous declaration - -lint_builtin_deref_nullptr = dereferencing a null pointer - .label = this code causes undefined behavior when executed - -lint_builtin_asm_labels = avoid using named labels in inline assembly - -lint_builtin_special_module_name_used_lib = found module declaration for lib.rs - .note = lib.rs is the root of this crate's library target - .help = to refer to it from other targets, use the library's name as the path - -lint_builtin_special_module_name_used_main = found module declaration for main.rs - .note = a binary crate cannot be used as library - -lint_supertrait_as_deref_target = `{$t}` implements `Deref` with supertrait `{$target_principal}` as target - .label = target type is set here - -lint_overruled_attribute = {$lint_level}({$lint_source}) incompatible with previous forbid - .label = overruled by previous forbid - -lint_default_source = `forbid` lint level is the default for {$id} - -lint_node_source = `forbid` level set here - .note = {$reason} - -lint_command_line_source = `forbid` lint level was set on command line - -lint_malformed_attribute = malformed lint attribute input - -lint_bad_attribute_argument = bad attribute argument - -lint_reason_must_be_string_literal = reason must be a string literal - -lint_reason_must_come_last = reason in lint attribute must come last - -lint_unknown_tool_in_scoped_lint = unknown tool name `{$tool_name}` found in scoped lint: `{$tool_name}::{$lint_name}` - .help = add `#![register_tool({$tool_name})]` to the crate root - -lint_unsupported_group = `{$lint_group}` lint group is not supported with ´--force-warn´ - -lint_requested_level = requested on the command line with `{$level} {$lint_name}` - -lint_check_name_unknown = unknown lint: `{$lint_name}` - .help = did you mean: `{$suggestion}` - -lint_check_name_unknown_tool = unknown lint tool: `{$tool_name}` - -lint_check_name_warning = {$msg} - -lint_check_name_deprecated = lint name `{$lint_name}` is deprecated and does not have an effect anymore. Use: {$new_name} - -lint_opaque_hidden_inferred_bound = opaque type `{$ty}` does not satisfy its associated type bounds - .specifically = this associated type bound is unsatisfied for `{$proj_ty}` - -lint_opaque_hidden_inferred_bound_sugg = add this bound +lint_unused_generator = + unused {$pre}{$count -> + [one] generator + *[other] generator + }{$post} that must be used + .note = generators are lazy and do nothing unless resumed -lint_dropping_references = calls to `std::mem::drop` with a reference instead of an owned value does nothing - .label = argument has type `{$arg_ty}` - .note = use `let _ = ...` to ignore the expression or result +lint_unused_import_braces = braces around {$node} is unnecessary -lint_dropping_copy_types = calls to `std::mem::drop` with a value that implements `Copy` does nothing - .label = argument has type `{$arg_ty}` - .note = use `let _ = ...` to ignore the expression or result +lint_unused_op = unused {$op} that must be used + .label = the {$op} produces a value + .suggestion = use `let _ = ...` to ignore the resulting value -lint_forgetting_references = calls to `std::mem::forget` with a reference instead of an owned value does nothing - .label = argument has type `{$arg_ty}` - .note = use `let _ = ...` to ignore the expression or result +lint_unused_result = unused result of type `{$ty}` -lint_forgetting_copy_types = calls to `std::mem::forget` with a value that implements `Copy` does nothing - .label = argument has type `{$arg_ty}` - .note = use `let _ = ...` to ignore the expression or result +lint_variant_size_differences = + enum variant is more than three times larger ({$largest} bytes) than the next largest diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 1d0c43e95e0..947530a1b65 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -952,6 +952,10 @@ pub trait LintContext: Sized { db.span_label(first_reexport_span, format!("the name `{}` in the {} namespace is first re-exported here", name, namespace)); db.span_label(duplicate_reexport_span, format!("but the name `{}` in the {} namespace is also re-exported here", name, namespace)); } + BuiltinLintDiagnostics::HiddenGlobReexports { name, namespace, glob_reexport_span, private_item_span } => { + db.span_label(glob_reexport_span, format!("the name `{}` in the {} namespace is supposed to be publicly re-exported here", name, namespace)); + db.span_label(private_item_span, "but the private item here shadows it"); + } } // Rewrap `db`, and pass control to the user. decorate(db) diff --git a/compiler/rustc_lint/src/errors.rs b/compiler/rustc_lint/src/errors.rs index bbae3d368f4..68167487a1b 100644 --- a/compiler/rustc_lint/src/errors.rs +++ b/compiler/rustc_lint/src/errors.rs @@ -39,7 +39,7 @@ impl AddToDiagnostic for OverruledAttributeSub { diag.span_label(span, fluent::lint_node_source); if let Some(rationale) = reason { #[allow(rustc::untranslatable_diagnostic)] - diag.note(rationale.as_str()); + diag.note(rationale.to_string()); } } OverruledAttributeSub::CommandLineSource => { diff --git a/compiler/rustc_lint/src/invalid_from_utf8.rs b/compiler/rustc_lint/src/invalid_from_utf8.rs new file mode 100644 index 00000000000..3291286ad67 --- /dev/null +++ b/compiler/rustc_lint/src/invalid_from_utf8.rs @@ -0,0 +1,118 @@ +use std::str::Utf8Error; + +use rustc_ast::{BorrowKind, LitKind}; +use rustc_hir::{Expr, ExprKind}; +use rustc_span::source_map::Spanned; +use rustc_span::sym; + +use crate::lints::InvalidFromUtf8Diag; +use crate::{LateContext, LateLintPass, LintContext}; + +declare_lint! { + /// The `invalid_from_utf8_unchecked` lint checks for calls to + /// `std::str::from_utf8_unchecked` and `std::str::from_utf8_unchecked_mut` + /// with an invalid UTF-8 literal. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// # #[allow(unused)] + /// unsafe { + /// std::str::from_utf8_unchecked(b"Ru\x82st"); + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Creating such a `str` would result in undefined behavior as per documentation + /// for `std::str::from_utf8_unchecked` and `std::str::from_utf8_unchecked_mut`. + pub INVALID_FROM_UTF8_UNCHECKED, + Deny, + "using a non UTF-8 literal in `std::str::from_utf8_unchecked`" +} + +declare_lint! { + /// The `invalid_from_utf8` lint checks for calls to + /// `std::str::from_utf8` and `std::str::from_utf8_mut` + /// with an invalid UTF-8 literal. + /// + /// ### Example + /// + /// ```rust + /// # #[allow(unused)] + /// std::str::from_utf8(b"Ru\x82st"); + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Trying to create such a `str` would always return an error as per documentation + /// for `std::str::from_utf8` and `std::str::from_utf8_mut`. + pub INVALID_FROM_UTF8, + Warn, + "using a non UTF-8 literal in `std::str::from_utf8`" +} + +declare_lint_pass!(InvalidFromUtf8 => [INVALID_FROM_UTF8_UNCHECKED, INVALID_FROM_UTF8]); + +impl<'tcx> LateLintPass<'tcx> for InvalidFromUtf8 { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { + if let ExprKind::Call(path, [arg]) = expr.kind + && let ExprKind::Path(ref qpath) = path.kind + && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id() + && let Some(diag_item) = cx.tcx.get_diagnostic_name(def_id) + && [sym::str_from_utf8, sym::str_from_utf8_mut, + sym::str_from_utf8_unchecked, sym::str_from_utf8_unchecked_mut].contains(&diag_item) + { + let lint = |utf8_error: Utf8Error| { + let label = arg.span; + let method = diag_item.as_str().strip_prefix("str_").unwrap(); + let method = format!("std::str::{method}"); + let valid_up_to = utf8_error.valid_up_to(); + let is_unchecked_variant = diag_item.as_str().contains("unchecked"); + + cx.emit_spanned_lint( + if is_unchecked_variant { INVALID_FROM_UTF8_UNCHECKED } else { INVALID_FROM_UTF8 }, + expr.span, + if is_unchecked_variant { + InvalidFromUtf8Diag::Unchecked { method, valid_up_to, label } + } else { + InvalidFromUtf8Diag::Checked { method, valid_up_to, label } + } + ) + }; + + match &arg.kind { + ExprKind::Lit(Spanned { node: lit, .. }) => { + if let LitKind::ByteStr(bytes, _) = &lit + && let Err(utf8_error) = std::str::from_utf8(bytes) + { + lint(utf8_error); + } + }, + ExprKind::AddrOf(BorrowKind::Ref, _, Expr { kind: ExprKind::Array(args), .. }) => { + let elements = args.iter().map(|e|{ + match &e.kind { + ExprKind::Lit(Spanned { node: lit, .. }) => match lit { + LitKind::Byte(b) => Some(*b), + LitKind::Int(b, _) => Some(*b as u8), + _ => None + } + _ => None + } + }).collect::<Option<Vec<_>>>(); + + if let Some(elements) = elements + && let Err(utf8_error) = std::str::from_utf8(&elements) + { + lint(utf8_error); + } + } + _ => {} + } + } + } +} diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index b92ed11f38a..8376835f52c 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -242,7 +242,9 @@ impl LintLevelsProvider for LintLevelQueryMap<'_> { struct QueryMapExpectationsWrapper<'tcx> { tcx: TyCtxt<'tcx>, + /// HirId of the currently investigated element. cur: HirId, + /// Level map for `cur`. specs: ShallowLintLevelMap, expectations: Vec<(LintExpectationId, LintExpectation)>, unstable_to_stable_ids: FxHashMap<LintExpectationId, LintExpectationId>, @@ -255,11 +257,11 @@ impl LintLevelsProvider for QueryMapExpectationsWrapper<'_> { self.specs.specs.get(&self.cur.local_id).unwrap_or(&self.empty) } fn insert(&mut self, id: LintId, lvl: LevelAndSource) { - let specs = self.specs.specs.get_mut_or_insert_default(self.cur.local_id); - specs.clear(); - specs.insert(id, lvl); + self.specs.specs.get_mut_or_insert_default(self.cur.local_id).insert(id, lvl); } fn get_lint_level(&self, lint: &'static Lint, _: &Session) -> LevelAndSource { + // We cannot use `tcx.lint_level_at_node` because we want to know in which order the + // attributes have been inserted, in particular whether an `expect` follows a `forbid`. self.specs.lint_level_id_at_node(self.tcx, LintId::of(lint), self.cur) } fn push_expectation(&mut self, id: LintExpectationId, expectation: LintExpectation) { @@ -355,7 +357,9 @@ impl<'tcx> Visitor<'tcx> for LintLevelsBuilder<'_, LintLevelQueryMap<'tcx>> { impl<'tcx> LintLevelsBuilder<'_, QueryMapExpectationsWrapper<'tcx>> { fn add_id(&mut self, hir_id: HirId) { + // Change both the `HirId` and the associated specs. self.provider.cur = hir_id; + self.provider.specs.specs.clear(); self.add(self.provider.tcx.hir().attrs(hir_id), hir_id == hir::CRATE_HIR_ID, Some(hir_id)); } } diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index dfddfe09ab3..c62109b2986 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -60,6 +60,7 @@ mod expect; mod for_loops_over_fallibles; pub mod hidden_unicode_codepoints; mod internal; +mod invalid_from_utf8; mod late; mod let_underscore; mod levels; @@ -102,6 +103,7 @@ use enum_intrinsics_non_enums::EnumIntrinsicsNonEnums; use for_loops_over_fallibles::*; use hidden_unicode_codepoints::*; use internal::*; +use invalid_from_utf8::*; use let_underscore::*; use map_unit_fn::*; use methods::*; @@ -207,6 +209,7 @@ late_lint_methods!( HardwiredLints: HardwiredLints, ImproperCTypesDeclarations: ImproperCTypesDeclarations, ImproperCTypesDefinitions: ImproperCTypesDefinitions, + InvalidFromUtf8: InvalidFromUtf8, VariantSizeDifferences: VariantSizeDifferences, BoxPointers: BoxPointers, PathStatements: PathStatements, diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index de1c2be2875..746abebeb37 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -699,6 +699,25 @@ pub struct ForgetCopyDiag<'a> { pub label: Span, } +// invalid_from_utf8.rs +#[derive(LintDiagnostic)] +pub enum InvalidFromUtf8Diag { + #[diag(lint_invalid_from_utf8_unchecked)] + Unchecked { + method: String, + valid_up_to: usize, + #[label] + label: Span, + }, + #[diag(lint_invalid_from_utf8_checked)] + Checked { + method: String, + valid_up_to: usize, + #[label] + label: Span, + }, +} + // hidden_unicode_codepoints.rs #[derive(LintDiagnostic)] #[diag(lint_hidden_unicode_codepoints)] @@ -1527,7 +1546,7 @@ impl<'a> DecorateLint<'a, ()> for UnusedDef<'_, '_> { diag.set_arg("def", self.cx.tcx.def_path_str(self.def_id)); // check for #[must_use = "..."] if let Some(note) = self.note { - diag.note(note.as_str()); + diag.note(note.to_string()); } if let Some(sugg) = self.suggestion { diag.subdiagnostic(sugg); diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 6e9dc880a7d..1507087bdd4 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -3272,6 +3272,43 @@ declare_lint! { "ambiguous glob re-exports", } +declare_lint! { + /// The `hidden_glob_reexports` lint detects cases where glob re-export items are shadowed by + /// private items. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(hidden_glob_reexports)] + /// + /// pub mod upstream { + /// mod inner { pub struct Foo {}; pub struct Bar {}; } + /// pub use self::inner::*; + /// struct Foo {} // private item shadows `inner::Foo` + /// } + /// + /// // mod downstream { + /// // fn test() { + /// // let _ = crate::upstream::Foo; // inaccessible + /// // } + /// // } + /// + /// pub fn main() {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// This was previously accepted without any errors or warnings but it could silently break a + /// crate's downstream user code. If the `struct Foo` was added, `dep::inner::Foo` would + /// silently become inaccessible and trigger a "`struct `Foo` is private`" visibility error at + /// the downstream use site. + pub HIDDEN_GLOB_REEXPORTS, + Warn, + "name introduced by a private item shadows a name introduced by a public glob re-export", +} + declare_lint_pass! { /// Does nothing as a lint pass, but registers some `Lint`s /// that are used by other parts of the compiler. @@ -3304,6 +3341,7 @@ declare_lint_pass! { FORBIDDEN_LINT_GROUPS, FUNCTION_ITEM_REFERENCES, FUZZY_PROVENANCE_CASTS, + HIDDEN_GLOB_REEXPORTS, ILL_FORMED_ATTRIBUTE_INPUT, ILLEGAL_FLOATING_POINT_LITERAL_PATTERN, IMPLIED_BOUNDS_ENTAILMENT, diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index e27e322db88..5a5031b7919 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -540,6 +540,16 @@ pub enum BuiltinLintDiagnostics { /// Span where the same name is also re-exported. duplicate_reexport_span: Span, }, + HiddenGlobReexports { + /// The name of the local binding which shadows the glob re-export. + name: String, + /// The namespace for which the shadowing occurred in. + namespace: String, + /// The glob reexport that is shadowed by the local binding. + glob_reexport_span: Span, + /// The local binding that shadows the glob reexport. + private_item_span: Span, + }, } /// Lints that are buffered up early on in the `Session` before the diff --git a/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h index 05890628378..af6f4d5eaf9 100644 --- a/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h +++ b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h @@ -96,6 +96,7 @@ enum LLVMRustAttribute { AllocatedPointer = 38, AllocAlign = 39, #endif + SanitizeSafeStack = 40, }; typedef struct OpaqueRustString *RustStringRef; diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 49acd71b3e1..ea04899ab68 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -234,6 +234,8 @@ static Attribute::AttrKind fromRust(LLVMRustAttribute Kind) { case AllocAlign: return Attribute::AllocAlign; #endif + case SanitizeSafeStack: + return Attribute::SafeStack; } report_fatal_error("bad AttributeKind"); } diff --git a/compiler/rustc_metadata/messages.ftl b/compiler/rustc_metadata/messages.ftl index 79b8b417257..6d8601b9e2b 100644 --- a/compiler/rustc_metadata/messages.ftl +++ b/compiler/rustc_metadata/messages.ftl @@ -1,288 +1,288 @@ -metadata_rlib_required = - crate `{$crate_name}` required to be available in rlib format, but was not found in this form - -metadata_lib_required = - crate `{$crate_name}` required to be available in {$kind} format, but was not found in this form +metadata_as_needed_compatibility = + linking modifier `as-needed` is only compatible with `dylib` and `framework` linking kinds -metadata_rustc_lib_required = - crate `{$crate_name}` required to be available in {$kind} format, but was not found in this form - .note = only .rmeta files are distributed for `rustc_private` crates other than `rustc_driver` - .help = try adding `extern crate rustc_driver;` at the top level of this crate +metadata_bad_panic_strategy = + the linked panic runtime `{$runtime}` is not compiled with this crate's panic strategy `{$strategy}` -metadata_crate_dep_multiple = - cannot satisfy dependencies so `{$crate_name}` only shows up once - .help = having upstream crates all available in one format will likely make this go away +metadata_bundle_needs_static = + linking modifier `bundle` is only compatible with `static` linking kind -metadata_two_panic_runtimes = - cannot link together two panic runtimes: {$prev_name} and {$cur_name} +metadata_cannot_find_crate = + can't find crate for `{$crate_name}`{$add_info} -metadata_bad_panic_strategy = - the linked panic runtime `{$runtime}` is not compiled with this crate's panic strategy `{$strategy}` +metadata_cant_find_crate = + can't find crate -metadata_required_panic_strategy = - the crate `{$crate_name}` requires panic strategy `{$found_strategy}` which is incompatible with this crate's strategy of `{$desired_strategy}` +metadata_compiler_missing_profiler = + the compiler may have been built without the profiler runtime -metadata_incompatible_panic_in_drop_strategy = - the crate `{$crate_name}` is compiled with the panic-in-drop strategy `{$found_strategy}` which is incompatible with this crate's strategy of `{$desired_strategy}` +metadata_conflicting_alloc_error_handler = + the `#[alloc_error_handler]` in {$other_crate_name} conflicts with allocation error handler in: {$crate_name} -metadata_multiple_names_in_link = - multiple `name` arguments in a single `#[link]` attribute +metadata_conflicting_global_alloc = + the `#[global_allocator]` in {$other_crate_name} conflicts with global allocator in: {$crate_name} -metadata_multiple_kinds_in_link = - multiple `kind` arguments in a single `#[link]` attribute +metadata_consider_building_std = + consider building the standard library from source with `cargo build -Zbuild-std` -metadata_link_name_form = - link name must be of the form `name = "string"` +metadata_consider_downloading_target = + consider downloading the target with `rustup target add {$locator_triple}` -metadata_link_kind_form = - link kind must be of the form `kind = "string"` +metadata_crate_dep_multiple = + cannot satisfy dependencies so `{$crate_name}` only shows up once + .help = having upstream crates all available in one format will likely make this go away -metadata_link_modifiers_form = - link modifiers must be of the form `modifiers = "string"` +metadata_crate_location_unknown_type = + extern location for {$crate_name} is of an unknown type: {$path} -metadata_link_cfg_form = - link cfg must be of the form `cfg(/* predicate */)` +metadata_crate_not_panic_runtime = + the crate `{$crate_name}` is not a panic runtime -metadata_wasm_import_form = - wasm import module must be of the form `wasm_import_module = "string"` +metadata_dl_error = + {$err} metadata_empty_link_name = link name must not be empty .label = empty link name -metadata_link_framework_apple = - link kind `framework` is only supported on Apple targets +metadata_empty_renaming_target = + an empty renaming target was specified for library `{$lib_name}` -metadata_framework_only_windows = - link kind `raw-dylib` is only supported on Windows targets +metadata_extern_location_not_exist = + extern location for {$crate_name} does not exist: {$location} -metadata_unknown_link_kind = - unknown link kind `{$kind}`, expected one of: static, dylib, framework, raw-dylib - .label = unknown link kind +metadata_extern_location_not_file = + extern location for {$crate_name} is not a file: {$location} -metadata_multiple_link_modifiers = - multiple `modifiers` arguments in a single `#[link]` attribute +metadata_fail_create_file_encoder = + failed to create file encoder: {$err} -metadata_multiple_cfgs = - multiple `cfg` arguments in a single `#[link]` attribute +metadata_fail_seek_file = + failed to seek the file: {$err} -metadata_link_cfg_single_predicate = - link cfg must have a single predicate argument +metadata_fail_write_file = + failed to write to the file: {$err} -metadata_multiple_wasm_import = - multiple `wasm_import_module` arguments in a single `#[link]` attribute +metadata_failed_create_encoded_metadata = + failed to create encoded metadata from file: {$err} -metadata_unexpected_link_arg = - unexpected `#[link]` argument, expected one of: name, kind, modifiers, cfg, wasm_import_module, import_name_type +metadata_failed_create_file = + failed to create the file {$filename}: {$err} -metadata_invalid_link_modifier = - invalid linking modifier syntax, expected '+' or '-' prefix before one of: bundle, verbatim, whole-archive, as-needed +metadata_failed_create_tempdir = + couldn't create a temp dir: {$err} -metadata_multiple_modifiers = - multiple `{$modifier}` modifiers in a single `modifiers` argument +metadata_failed_write_error = + failed to write {$filename}: {$err} -metadata_bundle_needs_static = - linking modifier `bundle` is only compatible with `static` linking kind +metadata_found_crate_versions = + the following crate versions were found:{$found_crates} -metadata_whole_archive_needs_static = - linking modifier `whole-archive` is only compatible with `static` linking kind +metadata_found_staticlib = + found staticlib `{$crate_name}` instead of rlib or dylib{$add_info} + .help = please recompile that crate using --crate-type lib -metadata_as_needed_compatibility = - linking modifier `as-needed` is only compatible with `dylib` and `framework` linking kinds +metadata_framework_only_windows = + link kind `raw-dylib` is only supported on Windows targets -metadata_unknown_link_modifier = - unknown linking modifier `{$modifier}`, expected one of: bundle, verbatim, whole-archive, as-needed +metadata_global_alloc_required = + no global memory allocator found but one is required; link to std or add `#[global_allocator]` to a static item that implements the GlobalAlloc trait + +metadata_import_name_type_form = + import name type must be of the form `import_name_type = "string"` + +metadata_import_name_type_raw = + import name type can only be used with link kind `raw-dylib` + +metadata_import_name_type_x86 = + import name type is only supported on x86 + +metadata_incompatible_panic_in_drop_strategy = + the crate `{$crate_name}` is compiled with the panic-in-drop strategy `{$found_strategy}` which is incompatible with this crate's strategy of `{$desired_strategy}` + +metadata_incompatible_rustc = + found crate `{$crate_name}` compiled by an incompatible version of rustc{$add_info} + .help = please recompile that crate using this compiler ({$rustc_version}) (consider running `cargo clean` first) metadata_incompatible_wasm_link = `wasm_import_module` is incompatible with other arguments in `#[link]` attributes -metadata_link_requires_name = - `#[link]` attribute requires a `name = "string"` argument - .label = missing `name` argument +metadata_install_missing_components = + maybe you need to install the missing components with: `rustup component add rust-src rustc-dev llvm-tools-preview` -metadata_raw_dylib_no_nul = - link name must not contain NUL characters if link kind is `raw-dylib` +metadata_invalid_link_modifier = + invalid linking modifier syntax, expected '+' or '-' prefix before one of: bundle, verbatim, whole-archive, as-needed -metadata_link_ordinal_raw_dylib = - `#[link_ordinal]` is only supported if link kind is `raw-dylib` +metadata_invalid_meta_files = + found invalid metadata files for crate `{$crate_name}`{$add_info} + +metadata_lib_filename_form = + file name should be lib*.rlib or {$dll_prefix}*{$dll_suffix} metadata_lib_framework_apple = library kind `framework` is only supported on Apple targets -metadata_empty_renaming_target = - an empty renaming target was specified for library `{$lib_name}` +metadata_lib_required = + crate `{$crate_name}` required to be available in {$kind} format, but was not found in this form -metadata_renaming_no_link = - renaming of the library `{$lib_name}` was specified, however this crate contains no `#[link(...)]` attributes referencing this library +metadata_link_cfg_form = + link cfg must be of the form `cfg(/* predicate */)` -metadata_multiple_renamings = - multiple renamings were specified for library `{$lib_name}` +metadata_link_cfg_single_predicate = + link cfg must have a single predicate argument -metadata_no_link_mod_override = - overriding linking modifiers from command line is not supported +metadata_link_framework_apple = + link kind `framework` is only supported on Apple targets -metadata_unsupported_abi_i686 = - ABI not supported by `#[link(kind = "raw-dylib")]` on i686 +metadata_link_kind_form = + link kind must be of the form `kind = "string"` -metadata_unsupported_abi = - ABI not supported by `#[link(kind = "raw-dylib")]` on this architecture +metadata_link_modifiers_form = + link modifiers must be of the form `modifiers = "string"` -metadata_fail_create_file_encoder = - failed to create file encoder: {$err} +metadata_link_name_form = + link name must be of the form `name = "string"` -metadata_fail_seek_file = - failed to seek the file: {$err} +metadata_link_ordinal_raw_dylib = + `#[link_ordinal]` is only supported if link kind is `raw-dylib` -metadata_fail_write_file = - failed to write to the file: {$err} +metadata_link_requires_name = + `#[link]` attribute requires a `name = "string"` argument + .label = missing `name` argument -metadata_crate_not_panic_runtime = - the crate `{$crate_name}` is not a panic runtime +metadata_missing_native_library = + could not find native static library `{$libname}`, perhaps an -L flag is missing? -metadata_no_panic_strategy = - the crate `{$crate_name}` does not have the panic strategy `{$strategy}` +metadata_multiple_candidates = + multiple candidates for `{$flavor}` dependency `{$crate_name}` found -metadata_profiler_builtins_needs_core = - `profiler_builtins` crate (required by compiler options) is not compatible with crate attribute `#![no_core]` +metadata_multiple_cfgs = + multiple `cfg` arguments in a single `#[link]` attribute -metadata_not_profiler_runtime = - the crate `{$crate_name}` is not a profiler runtime +metadata_multiple_import_name_type = + multiple `import_name_type` arguments in a single `#[link]` attribute -metadata_no_multiple_global_alloc = - cannot define multiple global allocators - .label = cannot define a new global allocator +metadata_multiple_kinds_in_link = + multiple `kind` arguments in a single `#[link]` attribute -metadata_prev_global_alloc = - previous global allocator defined here +metadata_multiple_link_modifiers = + multiple `modifiers` arguments in a single `#[link]` attribute -metadata_no_multiple_alloc_error_handler = - cannot define multiple allocation error handlers - .label = cannot define a new allocation error handler +metadata_multiple_modifiers = + multiple `{$modifier}` modifiers in a single `modifiers` argument -metadata_prev_alloc_error_handler = - previous allocation error handler defined here +metadata_multiple_names_in_link = + multiple `name` arguments in a single `#[link]` attribute -metadata_conflicting_global_alloc = - the `#[global_allocator]` in {$other_crate_name} conflicts with global allocator in: {$crate_name} +metadata_multiple_renamings = + multiple renamings were specified for library `{$lib_name}` -metadata_conflicting_alloc_error_handler = - the `#[alloc_error_handler]` in {$other_crate_name} conflicts with allocation error handler in: {$crate_name} +metadata_multiple_wasm_import = + multiple `wasm_import_module` arguments in a single `#[link]` attribute -metadata_global_alloc_required = - no global memory allocator found but one is required; link to std or add `#[global_allocator]` to a static item that implements the GlobalAlloc trait +metadata_newer_crate_version = + found possibly newer version of crate `{$crate_name}`{$add_info} + .note = perhaps that crate needs to be recompiled? -metadata_no_transitive_needs_dep = - the crate `{$crate_name}` cannot depend on a crate that needs {$needs_crate_name}, but it depends on `{$deps_crate_name}` +metadata_no_crate_with_triple = + couldn't find crate `{$crate_name}` with expected target triple {$locator_triple}{$add_info} -metadata_failed_write_error = - failed to write {$filename}: {$err} +metadata_no_dylib_plugin = + plugin `{$crate_name}` only found in rlib format, but must be available in dylib format -metadata_missing_native_library = - could not find native static library `{$libname}`, perhaps an -L flag is missing? +metadata_no_link_mod_override = + overriding linking modifiers from command line is not supported -metadata_only_provide_library_name = only provide the library name `{$suggested_name}`, not the full filename +metadata_no_multiple_alloc_error_handler = + cannot define multiple allocation error handlers + .label = cannot define a new allocation error handler -metadata_failed_create_tempdir = - couldn't create a temp dir: {$err} +metadata_no_multiple_global_alloc = + cannot define multiple global allocators + .label = cannot define a new global allocator -metadata_failed_create_file = - failed to create the file {$filename}: {$err} +metadata_no_panic_strategy = + the crate `{$crate_name}` does not have the panic strategy `{$strategy}` -metadata_failed_create_encoded_metadata = - failed to create encoded metadata from file: {$err} +metadata_no_transitive_needs_dep = + the crate `{$crate_name}` cannot depend on a crate that needs {$needs_crate_name}, but it depends on `{$deps_crate_name}` metadata_non_ascii_name = cannot load a crate with a non-ascii name `{$crate_name}` -metadata_extern_location_not_exist = - extern location for {$crate_name} does not exist: {$location} - -metadata_extern_location_not_file = - extern location for {$crate_name} is not a file: {$location} - -metadata_multiple_candidates = - multiple candidates for `{$flavor}` dependency `{$crate_name}` found +metadata_not_profiler_runtime = + the crate `{$crate_name}` is not a profiler runtime -metadata_symbol_conflicts_current = - the current crate is indistinguishable from one of its dependencies: it has the same crate-name `{$crate_name}` and was compiled with the same `-C metadata` arguments. This will result in symbol conflicts between the two. +metadata_only_provide_library_name = only provide the library name `{$suggested_name}`, not the full filename -metadata_symbol_conflicts_others = - found two different crates with name `{$crate_name}` that are not distinguished by differing `-C metadata`. This will result in symbol conflicts between the two. +metadata_prev_alloc_error_handler = + previous allocation error handler defined here -metadata_stable_crate_id_collision = - found crates (`{$crate_name0}` and `{$crate_name1}`) with colliding StableCrateId values. +metadata_prev_global_alloc = + previous global allocator defined here -metadata_dl_error = - {$err} +metadata_profiler_builtins_needs_core = + `profiler_builtins` crate (required by compiler options) is not compatible with crate attribute `#![no_core]` -metadata_newer_crate_version = - found possibly newer version of crate `{$crate_name}`{$add_info} - .note = perhaps that crate needs to be recompiled? +metadata_raw_dylib_no_nul = + link name must not contain NUL characters if link kind is `raw-dylib` -metadata_found_crate_versions = - the following crate versions were found:{$found_crates} +metadata_renaming_no_link = + renaming of the library `{$lib_name}` was specified, however this crate contains no `#[link(...)]` attributes referencing this library -metadata_no_crate_with_triple = - couldn't find crate `{$crate_name}` with expected target triple {$locator_triple}{$add_info} +metadata_required_panic_strategy = + the crate `{$crate_name}` requires panic strategy `{$found_strategy}` which is incompatible with this crate's strategy of `{$desired_strategy}` -metadata_found_staticlib = - found staticlib `{$crate_name}` instead of rlib or dylib{$add_info} - .help = please recompile that crate using --crate-type lib +metadata_rlib_required = + crate `{$crate_name}` required to be available in rlib format, but was not found in this form -metadata_incompatible_rustc = - found crate `{$crate_name}` compiled by an incompatible version of rustc{$add_info} - .help = please recompile that crate using this compiler ({$rustc_version}) (consider running `cargo clean` first) +metadata_rustc_lib_required = + crate `{$crate_name}` required to be available in {$kind} format, but was not found in this form + .note = only .rmeta files are distributed for `rustc_private` crates other than `rustc_driver` + .help = try adding `extern crate rustc_driver;` at the top level of this crate -metadata_invalid_meta_files = - found invalid metadata files for crate `{$crate_name}`{$add_info} +metadata_stable_crate_id_collision = + found crates (`{$crate_name0}` and `{$crate_name1}`) with colliding StableCrateId values. -metadata_cannot_find_crate = - can't find crate for `{$crate_name}`{$add_info} +metadata_std_required = + `std` is required by `{$current_crate}` because it does not declare `#![no_std]` -metadata_no_dylib_plugin = - plugin `{$crate_name}` only found in rlib format, but must be available in dylib format +metadata_symbol_conflicts_current = + the current crate is indistinguishable from one of its dependencies: it has the same crate-name `{$crate_name}` and was compiled with the same `-C metadata` arguments. This will result in symbol conflicts between the two. -metadata_target_not_installed = - the `{$locator_triple}` target may not be installed +metadata_symbol_conflicts_others = + found two different crates with name `{$crate_name}` that are not distinguished by differing `-C metadata`. This will result in symbol conflicts between the two. metadata_target_no_std_support = the `{$locator_triple}` target may not support the standard library -metadata_consider_downloading_target = - consider downloading the target with `rustup target add {$locator_triple}` - -metadata_std_required = - `std` is required by `{$current_crate}` because it does not declare `#![no_std]` - -metadata_consider_building_std = - consider building the standard library from source with `cargo build -Zbuild-std` - -metadata_compiler_missing_profiler = - the compiler may have been built without the profiler runtime +metadata_target_not_installed = + the `{$locator_triple}` target may not be installed -metadata_install_missing_components = - maybe you need to install the missing components with: `rustup component add rust-src rustc-dev llvm-tools-preview` +metadata_two_panic_runtimes = + cannot link together two panic runtimes: {$prev_name} and {$cur_name} -metadata_cant_find_crate = - can't find crate +metadata_unexpected_link_arg = + unexpected `#[link]` argument, expected one of: name, kind, modifiers, cfg, wasm_import_module, import_name_type -metadata_crate_location_unknown_type = - extern location for {$crate_name} is of an unknown type: {$path} +metadata_unknown_import_name_type = + unknown import name type `{$import_name_type}`, expected one of: decorated, noprefix, undecorated -metadata_lib_filename_form = - file name should be lib*.rlib or {$dll_prefix}*{$dll_suffix} +metadata_unknown_link_kind = + unknown link kind `{$kind}`, expected one of: static, dylib, framework, raw-dylib + .label = unknown link kind -metadata_multiple_import_name_type = - multiple `import_name_type` arguments in a single `#[link]` attribute +metadata_unknown_link_modifier = + unknown linking modifier `{$modifier}`, expected one of: bundle, verbatim, whole-archive, as-needed -metadata_import_name_type_form = - import name type must be of the form `import_name_type = "string"` +metadata_unsupported_abi = + ABI not supported by `#[link(kind = "raw-dylib")]` on this architecture -metadata_import_name_type_x86 = - import name type is only supported on x86 +metadata_unsupported_abi_i686 = + ABI not supported by `#[link(kind = "raw-dylib")]` on i686 -metadata_unknown_import_name_type = - unknown import name type `{$import_name_type}`, expected one of: decorated, noprefix, undecorated +metadata_wasm_import_form = + wasm import module must be of the form `wasm_import_module = "string"` -metadata_import_name_type_raw = - import name type can only be used with link kind `raw-dylib` +metadata_whole_archive_needs_static = + linking modifier `whole-archive` is only compatible with `static` linking kind diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs index ceb348f3469..a89d7b464e2 100644 --- a/compiler/rustc_metadata/src/locator.rs +++ b/compiler/rustc_metadata/src/locator.rs @@ -666,31 +666,30 @@ impl<'a> CrateLocator<'a> { return None; } - let root = metadata.get_root(); - if root.is_proc_macro_crate() != self.is_proc_macro { + let header = metadata.get_header(); + if header.is_proc_macro_crate != self.is_proc_macro { info!( "Rejecting via proc macro: expected {} got {}", - self.is_proc_macro, - root.is_proc_macro_crate(), + self.is_proc_macro, header.is_proc_macro_crate, ); return None; } - if self.exact_paths.is_empty() && self.crate_name != root.name() { + if self.exact_paths.is_empty() && self.crate_name != header.name { info!("Rejecting via crate name"); return None; } - if root.triple() != &self.triple { - info!("Rejecting via crate triple: expected {} got {}", self.triple, root.triple()); + if header.triple != self.triple { + info!("Rejecting via crate triple: expected {} got {}", self.triple, header.triple); self.crate_rejections.via_triple.push(CrateMismatch { path: libpath.to_path_buf(), - got: root.triple().to_string(), + got: header.triple.to_string(), }); return None; } - let hash = root.hash(); + let hash = header.hash; if let Some(expected_hash) = self.hash { if hash != expected_hash { info!("Rejecting via hash: expected {} got {}", expected_hash, hash); diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index cc4e60cf6ac..09e24e012af 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -74,6 +74,7 @@ pub(crate) struct CrateMetadata { blob: MetadataBlob, // --- Some data pre-decoded from the metadata blob, usually for performance --- + /// Data about the top-level items in a crate, as well as various crate-level metadata. root: CrateRoot, /// Trait impl data. /// FIXME: Used only from queries and can use query cache, @@ -449,7 +450,7 @@ impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for SyntaxContext { You need to explicitly pass `(crate_metadata_ref, tcx)` to `decode` instead of just `crate_metadata_ref`."); }; - let cname = cdata.root.name; + let cname = cdata.root.name(); rustc_span::hygiene::decode_syntax_context(decoder, &cdata.hygiene_context, |_, id| { debug!("SpecializedDecoder<SyntaxContext>: decoding {}", id); cdata @@ -564,7 +565,7 @@ impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for Span { let cnum = u32::decode(decoder); panic!( "Decoding of crate {:?} tried to access proc-macro dep {:?}", - decoder.cdata().root.name, + decoder.cdata().root.header.name, cnum ); } @@ -671,6 +672,16 @@ impl MetadataBlob { .decode(self) } + pub(crate) fn get_header(&self) -> CrateHeader { + let slice = &self.blob()[..]; + let offset = METADATA_HEADER.len(); + + let pos_bytes = slice[offset..][..4].try_into().unwrap(); + let pos = u32::from_be_bytes(pos_bytes) as usize; + + LazyValue::<CrateHeader>::from_position(NonZeroUsize::new(pos).unwrap()).decode(self) + } + pub(crate) fn get_root(&self) -> CrateRoot { let slice = &self.blob()[..]; let offset = METADATA_HEADER.len(); @@ -684,8 +695,8 @@ impl MetadataBlob { pub(crate) fn list_crate_metadata(&self, out: &mut dyn io::Write) -> io::Result<()> { let root = self.get_root(); writeln!(out, "Crate info:")?; - writeln!(out, "name {}{}", root.name, root.extra_filename)?; - writeln!(out, "hash {} stable_crate_id {:?}", root.hash, root.stable_crate_id)?; + writeln!(out, "name {}{}", root.name(), root.extra_filename)?; + writeln!(out, "hash {} stable_crate_id {:?}", root.hash(), root.stable_crate_id)?; writeln!(out, "proc_macro {:?}", root.proc_macro_data.is_some())?; writeln!(out, "=External Dependencies=")?; @@ -709,21 +720,17 @@ impl CrateRoot { } pub(crate) fn name(&self) -> Symbol { - self.name + self.header.name } pub(crate) fn hash(&self) -> Svh { - self.hash + self.header.hash } pub(crate) fn stable_crate_id(&self) -> StableCrateId { self.stable_crate_id } - pub(crate) fn triple(&self) -> &TargetTriple { - &self.triple - } - pub(crate) fn decode_crate_deps<'a>( &self, metadata: &'a MetadataBlob, @@ -794,7 +801,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { bug!( "CrateMetadata::def_kind({:?}): id not found, in crate {:?} with number {}", item_id, - self.root.name, + self.root.name(), self.cnum, ) }) @@ -851,7 +858,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } else { tcx.arena.alloc_from_iter(lazy.decode((self, tcx))) }; - ty::EarlyBinder(&*output) + ty::EarlyBinder::bind(&*output) } fn get_variant( @@ -1702,11 +1709,11 @@ impl CrateMetadata { } pub(crate) fn name(&self) -> Symbol { - self.root.name + self.root.header.name } pub(crate) fn hash(&self) -> Svh { - self.root.hash + self.root.header.hash } fn num_def_ids(&self) -> usize { diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 7425963d30f..3d8991d99b5 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -317,9 +317,9 @@ provide! { tcx, def_id, other, cdata, } native_libraries => { cdata.get_native_libraries(tcx.sess).collect() } foreign_modules => { cdata.get_foreign_modules(tcx.sess).map(|m| (m.def_id, m)).collect() } - crate_hash => { cdata.root.hash } + crate_hash => { cdata.root.header.hash } crate_host_hash => { cdata.host_hash } - crate_name => { cdata.root.name } + crate_name => { cdata.root.header.name } extra_filename => { cdata.root.extra_filename.clone() } @@ -581,7 +581,7 @@ impl CrateStore for CStore { } fn crate_name(&self, cnum: CrateNum) -> Symbol { - self.get_crate_data(cnum).root.name + self.get_crate_data(cnum).root.header.name } fn stable_crate_id(&self, cnum: CrateNum) -> StableCrateId { diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index f067bca4b0b..c673eb5afc7 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -662,10 +662,13 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let root = stat!("final", || { let attrs = tcx.hir().krate_attrs(); self.lazy(CrateRoot { - name: tcx.crate_name(LOCAL_CRATE), + header: CrateHeader { + name: tcx.crate_name(LOCAL_CRATE), + triple: tcx.sess.opts.target_triple.clone(), + hash: tcx.crate_hash(LOCAL_CRATE), + is_proc_macro_crate: proc_macro_data.is_some(), + }, extra_filename: tcx.sess.opts.cg.extra_filename.clone(), - triple: tcx.sess.opts.target_triple.clone(), - hash: tcx.crate_hash(LOCAL_CRATE), stable_crate_id: tcx.def_path_hash(LOCAL_CRATE.as_def_id()).stable_crate_id(), required_panic_strategy: tcx.required_panic_strategy(LOCAL_CRATE), panic_in_drop_strategy: tcx.sess.opts.unstable_opts.panic_in_drop, @@ -1727,7 +1730,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { ty::Closure(_, substs) => { let constness = self.tcx.constness(def_id.to_def_id()); self.tables.constness.set_some(def_id.to_def_id().index, constness); - record!(self.tables.fn_sig[def_id.to_def_id()] <- ty::EarlyBinder(substs.as_closure().sig())); + record!(self.tables.fn_sig[def_id.to_def_id()] <- ty::EarlyBinder::bind(substs.as_closure().sig())); } _ => bug!("closure that is neither generator nor closure"), diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 97e67fcf8fd..ce2fe70a8b2 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -56,7 +56,7 @@ pub(crate) fn rustc_version(cfg_version: &'static str) -> String { /// Metadata encoding version. /// N.B., increment this if you change the format of metadata such that /// the rustc version can't be found to compare with `rustc_version()`. -const METADATA_VERSION: u8 = 7; +const METADATA_VERSION: u8 = 8; /// Metadata header which includes `METADATA_VERSION`. /// @@ -199,7 +199,27 @@ pub(crate) struct ProcMacroData { macros: LazyArray<DefIndex>, } -/// Serialized metadata for a crate. +/// Serialized crate metadata. +/// +/// This contains just enough information to determine if we should load the `CrateRoot` or not. +/// Prefer [`CrateRoot`] whenever possible to avoid ICEs when using `omit-git-hash` locally. +/// See #76720 for more details. +/// +/// If you do modify this struct, also bump the [`METADATA_VERSION`] constant. +#[derive(MetadataEncodable, MetadataDecodable)] +pub(crate) struct CrateHeader { + pub(crate) triple: TargetTriple, + pub(crate) hash: Svh, + pub(crate) name: Symbol, + /// Whether this is the header for a proc-macro crate. + /// + /// This is separate from [`ProcMacroData`] to avoid having to update [`METADATA_VERSION`] every + /// time ProcMacroData changes. + pub(crate) is_proc_macro_crate: bool, +} + +/// Serialized `.rmeta` data for a crate. +/// /// When compiling a proc-macro crate, we encode many of /// the `LazyArray<T>` fields as `Lazy::empty()`. This serves two purposes: /// @@ -217,10 +237,10 @@ pub(crate) struct ProcMacroData { /// to being unused. #[derive(MetadataEncodable, MetadataDecodable)] pub(crate) struct CrateRoot { - name: Symbol, - triple: TargetTriple, + /// A header used to detect if this is the right crate to load. + header: CrateHeader, + extra_filename: String, - hash: Svh, stable_crate_id: StableCrateId, required_panic_strategy: Option<PanicStrategy>, panic_in_drop_strategy: PanicStrategy, @@ -465,6 +485,7 @@ trivially_parameterized_over_tcx! { RawDefId, TraitImpls, IncoherentImpls, + CrateHeader, CrateRoot, CrateDep, AttrFlags, diff --git a/compiler/rustc_middle/messages.ftl b/compiler/rustc_middle/messages.ftl index 64d511c261a..3d581daa925 100644 --- a/compiler/rustc_middle/messages.ftl +++ b/compiler/rustc_middle/messages.ftl @@ -1,45 +1,45 @@ +middle_cannot_be_normalized = + unable to determine layout for `{$ty}` because `{$failure_ty}` cannot be normalized + +middle_conflict_types = + this expression supplies two conflicting concrete types for the same opaque type + +middle_const_eval_non_int = + constant evaluation of enum discriminant resulted in non-integer + +middle_const_not_used_in_type_alias = + const parameter `{$ct}` is part of concrete type but not used in parameter list for the `impl Trait` type alias + +middle_cycle = + a cycle occurred during layout computation + middle_drop_check_overflow = overflow while adding drop-check rules for {$ty} .note = overflowed on {$overflow_ty} +middle_limit_invalid = + `limit` must be a non-negative integer + .label = {$error_str} + middle_opaque_hidden_type_mismatch = concrete type differs from previous defining opaque type use .label = expected `{$self_ty}`, got `{$other_ty}` -middle_conflict_types = - this expression supplies two conflicting concrete types for the same opaque type - middle_previous_use_here = previous use here -middle_limit_invalid = - `limit` must be a non-negative integer - .label = {$error_str} - middle_recursion_limit_reached = reached the recursion limit finding the struct tail for `{$ty}` .help = consider increasing the recursion limit by adding a `#![recursion_limit = "{$suggested_limit}"]` -middle_const_eval_non_int = - constant evaluation of enum discriminant resulted in non-integer - -middle_unknown_layout = - the type `{$ty}` has an unknown layout - -middle_values_too_big = - values of the type `{$ty}` are too big for the current architecture - -middle_cannot_be_normalized = - unable to determine layout for `{$ty}` because `{$failure_ty}` cannot be normalized - -middle_cycle = - a cycle occurred during layout computation +middle_requires_lang_item = requires `{$name}` lang_item middle_strict_coherence_needs_negative_coherence = to use `strict_coherence` on this trait, the `with_negative_coherence` feature must be enabled .label = due to this attribute -middle_requires_lang_item = requires `{$name}` lang_item +middle_unknown_layout = + the type `{$ty}` has an unknown layout -middle_const_not_used_in_type_alias = - const parameter `{$ct}` is part of concrete type but not used in parameter list for the `impl Trait` type alias +middle_values_too_big = + values of the type `{$ty}` are too big for the current architecture diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs index 56171314944..29dae67bfca 100644 --- a/compiler/rustc_middle/src/infer/canonical.rs +++ b/compiler/rustc_middle/src/infer/canonical.rs @@ -415,7 +415,7 @@ impl<'tcx> CanonicalVarValues<'tcx> { var: ty::BoundVar::from_usize(i), kind: ty::BrAnon(None), }; - tcx.mk_re_late_bound(ty::INNERMOST, br).into() + ty::Region::new_late_bound(tcx, ty::INNERMOST, br).into() } CanonicalVarKind::Const(_, ty) | CanonicalVarKind::PlaceholderConst(_, ty) => tcx diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs index 14343ac1108..caf3fc26039 100644 --- a/compiler/rustc_middle/src/lint.rs +++ b/compiler/rustc_middle/src/lint.rs @@ -251,7 +251,7 @@ pub fn explain_lint_level_source( } LintLevelSource::Node { name: lint_attr_name, span, reason, .. } => { if let Some(rationale) = reason { - err.note(rationale.as_str()); + err.note(rationale.to_string()); } err.span_note_once(span, "the lint level is defined here"); if lint_attr_name.as_str() != name { diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index 6354c0aabde..60844c17e47 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -104,7 +104,7 @@ pub fn report_unstable( suggestion: Option<(Span, String, String, Applicability)>, is_soft: bool, span: Span, - soft_handler: impl FnOnce(&'static Lint, Span, &str), + soft_handler: impl FnOnce(&'static Lint, Span, String), ) { let msg = match reason { Some(r) => format!("use of unstable library feature '{}': {}", feature, r), @@ -112,7 +112,7 @@ pub fn report_unstable( }; if is_soft { - soft_handler(SOFT_UNSTABLE, span, &msg) + soft_handler(SOFT_UNSTABLE, span, msg) } else { let mut err = feature_err_issue(&sess.parse_sess, feature, span, GateIssue::Library(issue), msg); @@ -225,7 +225,7 @@ pub fn deprecation_message_and_lint( pub fn early_report_deprecation( lint_buffer: &mut LintBuffer, - message: &str, + message: String, suggestion: Option<Symbol>, lint: &'static Lint, span: Span, @@ -241,7 +241,7 @@ pub fn early_report_deprecation( fn late_report_deprecation( tcx: TyCtxt<'_>, - message: &str, + message: String, suggestion: Option<Symbol>, lint: &'static Lint, span: Span, @@ -396,7 +396,7 @@ impl<'tcx> TyCtxt<'tcx> { late_report_deprecation( self, - &deprecation_message( + deprecation_message( is_in_effect, depr_attr.since, depr_attr.note, @@ -619,7 +619,7 @@ impl<'tcx> TyCtxt<'tcx> { allow_unstable: AllowUnstable, unmarked: impl FnOnce(Span, DefId), ) -> bool { - let soft_handler = |lint, span, msg: &_| { + let soft_handler = |lint, span, msg: String| { self.struct_span_lint_hir(lint, id.unwrap_or(hir::CRATE_HIR_ID), span, msg, |lint| lint) }; let eval_result = diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 5c71910a955..63cdba7f327 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -476,7 +476,7 @@ impl<'tcx> Body<'tcx> { /// Returns the return type; it always return first element from `local_decls` array. #[inline] pub fn bound_return_ty(&self) -> ty::EarlyBinder<Ty<'tcx>> { - ty::EarlyBinder(self.local_decls[RETURN_PLACE].ty) + ty::EarlyBinder::bind(self.local_decls[RETURN_PLACE].ty) } /// Gets the location of the terminator for the given block. diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index ff54ec56a29..f31b343c947 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -334,10 +334,7 @@ impl<'tcx> CodegenUnit<'tcx> { } pub fn modify_size_estimate(&mut self, delta: usize) { - assert!(self.size_estimate.is_some()); - if let Some(size_estimate) = self.size_estimate { - self.size_estimate = Some(size_estimate + delta); - } + *self.size_estimate.as_mut().unwrap() += delta; } pub fn contains_item(&self, item: &MonoItem<'tcx>) -> bool { diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index 53fd2dd23a7..a15c419da7a 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -413,7 +413,7 @@ impl<'tcx> ClosureOutlivesSubjectTy<'tcx> { ty::ReVar(vid) => { let br = ty::BoundRegion { var: ty::BoundVar::new(vid.index()), kind: ty::BrAnon(None) }; - tcx.mk_re_late_bound(depth, br) + ty::Region::new_late_bound(tcx, depth, br) } _ => bug!("unexpected region in ClosureOutlivesSubjectTy: {r:?}"), }); diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index 21faf1958e9..3e474c1d377 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -220,6 +220,11 @@ pub enum BorrowKind { /// immutable, but not aliasable. This solves the problem. For /// simplicity, we don't give users the way to express this /// borrow, it's just used when translating closures. + /// + // FIXME(#112072): This is wrong. Unique borrows are mutable borrows except + // that they do not require their pointee to be marked as a mutable. + // They should still be treated as mutable borrows in every other way, + // e.g. for variance or overlap checking. Unique, /// Data is mutable and not aliasable. @@ -603,7 +608,11 @@ pub enum TerminatorKind<'tcx> { /// > The drop glue is executed if, among all statements executed within this `Body`, an assignment to /// > the place or one of its "parents" occurred more recently than a move out of it. This does not /// > consider indirect assignments. - Drop { place: Place<'tcx>, target: BasicBlock, unwind: UnwindAction }, + /// + /// The `replace` flag indicates whether this terminator was created as part of an assignment. + /// This should only be used for diagnostic purposes, and does not have any operational + /// meaning. + Drop { place: Place<'tcx>, target: BasicBlock, unwind: UnwindAction, replace: bool }, /// Roughly speaking, evaluates the `func` operand and the arguments, and starts execution of /// the referred to function. The operand types must match the argument types of the function. diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs index 2c6126cdd29..561ef371b09 100644 --- a/compiler/rustc_middle/src/mir/terminator.rs +++ b/compiler/rustc_middle/src/mir/terminator.rs @@ -105,7 +105,7 @@ pub struct Terminator<'tcx> { pub kind: TerminatorKind<'tcx>, } -pub type Successors<'a> = impl Iterator<Item = BasicBlock> + 'a; +pub type Successors<'a> = impl DoubleEndedIterator<Item = BasicBlock> + 'a; pub type SuccessorsMut<'a> = iter::Chain<std::option::IntoIter<&'a mut BasicBlock>, slice::IterMut<'a, BasicBlock>>; diff --git a/compiler/rustc_middle/src/mir/traversal.rs b/compiler/rustc_middle/src/mir/traversal.rs index 7d247eeb656..99ead14139a 100644 --- a/compiler/rustc_middle/src/mir/traversal.rs +++ b/compiler/rustc_middle/src/mir/traversal.rs @@ -149,7 +149,7 @@ impl<'a, 'tcx> Postorder<'a, 'tcx> { // B C // | | // | | - // D | + // | D // \ / // \ / // E @@ -159,26 +159,26 @@ impl<'a, 'tcx> Postorder<'a, 'tcx> { // // When the first call to `traverse_successor` happens, the following happens: // - // [(B, [D]), // `B` taken from the successors of `A`, pushed to the - // // top of the stack along with the successors of `B` - // (A, [C])] + // [(C, [D]), // `C` taken from the successors of `A`, pushed to the + // // top of the stack along with the successors of `C` + // (A, [B])] // - // [(D, [E]), // `D` taken from successors of `B`, pushed to stack - // (B, []), - // (A, [C])] + // [(D, [E]), // `D` taken from successors of `C`, pushed to stack + // (C, []), + // (A, [B])] // // [(E, []), // `E` taken from successors of `D`, pushed to stack // (D, []), - // (B, []), - // (A, [C])] + // (C, []), + // (A, [B])] // // Now that the top of the stack has no successors we can traverse, each item will - // be popped off during iteration until we get back to `A`. This yields [E, D, B]. + // be popped off during iteration until we get back to `A`. This yields [E, D, C]. // - // When we yield `B` and call `traverse_successor`, we push `C` to the stack, but + // When we yield `C` and call `traverse_successor`, we push `B` to the stack, but // since we've already visited `E`, that child isn't added to the stack. The last - // two iterations yield `C` and finally `A` for a final traversal of [E, D, B, C, A] - while let Some(&mut (_, ref mut iter)) = self.visit_stack.last_mut() && let Some(bb) = iter.next() { + // two iterations yield `B` and finally `A` for a final traversal of [E, D, C, B, A] + while let Some(&mut (_, ref mut iter)) = self.visit_stack.last_mut() && let Some(bb) = iter.next_back() { if self.visited.insert(bb) { if let Some(term) = &self.basic_blocks[bb].terminator { self.visit_stack.push((bb, term.successors())); diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 596dd80bf48..8d44e929afd 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -504,6 +504,7 @@ macro_rules! make_mir_visitor { place, target: _, unwind: _, + replace: _, } => { self.visit_place( place, @@ -649,8 +650,8 @@ macro_rules! make_mir_visitor { BorrowKind::Shallow => PlaceContext::NonMutatingUse( NonMutatingUseContext::ShallowBorrow ), - BorrowKind::Unique => PlaceContext::NonMutatingUse( - NonMutatingUseContext::UniqueBorrow + BorrowKind::Unique => PlaceContext::MutatingUse( + MutatingUseContext::Borrow ), BorrowKind::Mut { .. } => PlaceContext::MutatingUse(MutatingUseContext::Borrow), @@ -1264,8 +1265,6 @@ pub enum NonMutatingUseContext { SharedBorrow, /// Shallow borrow. ShallowBorrow, - /// Unique borrow. - UniqueBorrow, /// AddressOf for *const pointer. AddressOf, /// PlaceMention statement. @@ -1344,9 +1343,7 @@ impl PlaceContext { matches!( self, PlaceContext::NonMutatingUse( - NonMutatingUseContext::SharedBorrow - | NonMutatingUseContext::ShallowBorrow - | NonMutatingUseContext::UniqueBorrow + NonMutatingUseContext::SharedBorrow | NonMutatingUseContext::ShallowBorrow ) | PlaceContext::MutatingUse(MutatingUseContext::Borrow) ) } diff --git a/compiler/rustc_middle/src/traits/query.rs b/compiler/rustc_middle/src/traits/query.rs index c4f8718754f..eae5a280e11 100644 --- a/compiler/rustc_middle/src/traits/query.rs +++ b/compiler/rustc_middle/src/traits/query.rs @@ -95,8 +95,6 @@ pub type CanonicalTypeOpNormalizeGoal<'tcx, T> = #[derive(Copy, Clone, Debug, HashStable, PartialEq, Eq)] pub struct NoSolution; -pub type Fallible<T> = Result<T, NoSolution>; - impl<'tcx> From<TypeError<'tcx>> for NoSolution { fn from(_: TypeError<'tcx>) -> NoSolution { NoSolution diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index 7c5c030c276..e067d2a984f 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -573,7 +573,7 @@ impl<'tcx> AdtDef<'tcx> { /// Due to normalization being eager, this applies even if /// the associated type is behind a pointer (e.g., issue #31299). pub fn sized_constraint(self, tcx: TyCtxt<'tcx>) -> ty::EarlyBinder<&'tcx [Ty<'tcx>]> { - ty::EarlyBinder(tcx.adt_sized_constraint(self.did())) + ty::EarlyBinder::bind(tcx.adt_sized_constraint(self.did())) } } diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index 7fc75674da5..76f52bc34ed 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -264,7 +264,7 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for mir::Place<'tcx> { impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for ty::Region<'tcx> { fn decode(decoder: &mut D) -> Self { - decoder.interner().mk_region_from_kind(Decodable::decode(decoder)) + ty::Region::new_from_kind(decoder.interner(), Decodable::decode(decoder)) } } diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index 1a4bd14815f..aecb46556b0 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -254,5 +254,5 @@ pub fn const_param_default(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBind "`const_param_default` expected a generic parameter with a constant" ), }; - ty::EarlyBinder(Const::from_anon_const(tcx, default_def_id)) + ty::EarlyBinder::bind(Const::from_anon_const(tcx, default_def_id)) } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 2bde55bc4fd..77725f0b3b6 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -115,6 +115,16 @@ impl<'tcx> Interner for TyCtxt<'tcx> { type FreeRegion = ty::FreeRegion; type RegionVid = ty::RegionVid; type PlaceholderRegion = ty::PlaceholderRegion; + + fn ty_and_mut_to_parts( + TypeAndMut { ty, mutbl }: TypeAndMut<'tcx>, + ) -> (Self::Ty, Self::Mutability) { + (ty, mutbl) + } + + fn mutability_is_mut(mutbl: Self::Mutability) -> bool { + mutbl.is_mut() + } } type InternedSet<'tcx, T> = ShardedHashMap<InternedInSet<'tcx, T>, ()>; @@ -713,30 +723,6 @@ impl<'tcx> TyCtxt<'tcx> { self.mk_ty_from_kind(Error(reported)) } - /// Constructs a `RegionKind::ReError` lifetime. - #[track_caller] - pub fn mk_re_error(self, reported: ErrorGuaranteed) -> Region<'tcx> { - self.intern_region(ty::ReError(reported)) - } - - /// Constructs a `RegionKind::ReError` lifetime and registers a `delay_span_bug` to ensure it - /// gets used. - #[track_caller] - pub fn mk_re_error_misc(self) -> Region<'tcx> { - self.mk_re_error_with_message( - DUMMY_SP, - "RegionKind::ReError constructed but no error reported", - ) - } - - /// Constructs a `RegionKind::ReError` lifetime and registers a `delay_span_bug` with the given - /// `msg` to ensure it gets used. - #[track_caller] - pub fn mk_re_error_with_message<S: Into<MultiSpan>>(self, span: S, msg: &str) -> Region<'tcx> { - let reported = self.sess.delay_span_bug(span, msg); - self.mk_re_error(reported) - } - /// Like [TyCtxt::ty_error] but for constants, with current `ErrorGuaranteed` #[track_caller] pub fn const_error(self, ty: Ty<'tcx>, reported: ErrorGuaranteed) -> Const<'tcx> { @@ -759,7 +745,7 @@ impl<'tcx> TyCtxt<'tcx> { self, ty: Ty<'tcx>, span: S, - msg: &str, + msg: &'static str, ) -> Const<'tcx> { let reported = self.sess.delay_span_bug(span, msg); self.mk_const(ty::ConstKind::Error(reported), ty) @@ -1515,9 +1501,9 @@ macro_rules! direct_interners { // Functions with a `mk_` prefix are intended for use outside this file and // crate. Functions with an `intern_` prefix are intended for use within this -// file only, and have a corresponding `mk_` function. +// crate only, and have a corresponding `mk_` function. direct_interners! { - region: intern_region(RegionKind<'tcx>): Region -> Region<'tcx>, + region: pub(crate) intern_region(RegionKind<'tcx>): Region -> Region<'tcx>, const_: intern_const(ConstData<'tcx>): Const -> Const<'tcx>, const_allocation: pub mk_const_alloc(Allocation): ConstAllocation -> ConstAllocation<'tcx>, layout: pub mk_layout(LayoutS): Layout -> Layout<'tcx>, @@ -1992,7 +1978,7 @@ impl<'tcx> TyCtxt<'tcx> { pub fn mk_param_from_def(self, param: &ty::GenericParamDef) -> GenericArg<'tcx> { match param.kind { GenericParamDefKind::Lifetime => { - self.mk_re_early_bound(param.to_early_bound_region_data()).into() + ty::Region::new_early_bound(self, param.to_early_bound_region_data()).into() } GenericParamDefKind::Type { .. } => self.mk_ty_param(param.index, param.name).into(), GenericParamDefKind::Const { .. } => self @@ -2032,65 +2018,6 @@ impl<'tcx> TyCtxt<'tcx> { self.mk_alias(ty::Opaque, self.mk_alias_ty(def_id, substs)) } - #[inline] - pub fn mk_re_early_bound(self, early_bound_region: ty::EarlyBoundRegion) -> Region<'tcx> { - self.intern_region(ty::ReEarlyBound(early_bound_region)) - } - - #[inline] - pub fn mk_re_late_bound( - self, - debruijn: ty::DebruijnIndex, - bound_region: ty::BoundRegion, - ) -> Region<'tcx> { - // Use a pre-interned one when possible. - if let ty::BoundRegion { var, kind: ty::BrAnon(None) } = bound_region - && let Some(inner) = self.lifetimes.re_late_bounds.get(debruijn.as_usize()) - && let Some(re) = inner.get(var.as_usize()).copied() - { - re - } else { - self.intern_region(ty::ReLateBound(debruijn, bound_region)) - } - } - - #[inline] - pub fn mk_re_free(self, scope: DefId, bound_region: ty::BoundRegionKind) -> Region<'tcx> { - self.intern_region(ty::ReFree(ty::FreeRegion { scope, bound_region })) - } - - #[inline] - pub fn mk_re_var(self, v: ty::RegionVid) -> Region<'tcx> { - // Use a pre-interned one when possible. - self.lifetimes - .re_vars - .get(v.as_usize()) - .copied() - .unwrap_or_else(|| self.intern_region(ty::ReVar(v))) - } - - #[inline] - pub fn mk_re_placeholder(self, placeholder: ty::PlaceholderRegion) -> Region<'tcx> { - self.intern_region(ty::RePlaceholder(placeholder)) - } - - // Avoid this in favour of more specific `mk_re_*` methods, where possible, - // to avoid the cost of the `match`. - pub fn mk_region_from_kind(self, kind: ty::RegionKind<'tcx>) -> Region<'tcx> { - match kind { - ty::ReEarlyBound(region) => self.mk_re_early_bound(region), - ty::ReLateBound(debruijn, region) => self.mk_re_late_bound(debruijn, region), - ty::ReFree(ty::FreeRegion { scope, bound_region }) => { - self.mk_re_free(scope, bound_region) - } - ty::ReStatic => self.lifetimes.re_static, - ty::ReVar(vid) => self.mk_re_var(vid), - ty::RePlaceholder(region) => self.mk_re_placeholder(region), - ty::ReErased => self.lifetimes.re_erased, - ty::ReError(reported) => self.mk_re_error(reported), - } - } - pub fn mk_place_field(self, place: Place<'tcx>, f: FieldIdx, ty: Ty<'tcx>) -> Place<'tcx> { self.mk_place_elem(place, PlaceElem::Field(f, ty)) } diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index 6a29063b80d..9c91b778403 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -1,5 +1,6 @@ //! Diagnostics related methods for `Ty`. +use std::borrow::Cow; use std::ops::ControlFlow; use crate::ty::{ @@ -384,22 +385,18 @@ pub fn suggest_constraining_type_params<'a>( if suggestions.len() == 1 { let (span, suggestion, msg) = suggestions.pop().unwrap(); - - let s; let msg = match msg { SuggestChangingConstraintsMessage::RestrictBoundFurther => { - "consider further restricting this bound" + Cow::from("consider further restricting this bound") } SuggestChangingConstraintsMessage::RestrictType { ty } => { - s = format!("consider restricting type parameter `{}`", ty); - &s + Cow::from(format!("consider restricting type parameter `{}`", ty)) } SuggestChangingConstraintsMessage::RestrictTypeFurther { ty } => { - s = format!("consider further restricting type parameter `{}`", ty); - &s + Cow::from(format!("consider further restricting type parameter `{}`", ty)) } SuggestChangingConstraintsMessage::RemovingQSized => { - "consider removing the `?Sized` bound to make the type parameter `Sized`" + Cow::from("consider removing the `?Sized` bound to make the type parameter `Sized`") } }; diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index 49ab9b79e96..66293f19eef 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -45,7 +45,6 @@ pub enum TypeError<'tcx> { RegionsDoesNotOutlive(Region<'tcx>, Region<'tcx>), RegionsInsufficientlyPolymorphic(BoundRegionKind, Region<'tcx>), - RegionsOverlyPolymorphic(BoundRegionKind, Region<'tcx>), RegionsPlaceholderMismatch, Sorts(ExpectedFound<Ty<'tcx>>), @@ -74,7 +73,6 @@ impl TypeError<'_> { match self { TypeError::RegionsDoesNotOutlive(_, _) | TypeError::RegionsInsufficientlyPolymorphic(_, _) - | TypeError::RegionsOverlyPolymorphic(_, _) | TypeError::RegionsPlaceholderMismatch => true, _ => false, } @@ -98,11 +96,6 @@ impl<'tcx> TypeError<'tcx> { } } - let br_string = |br: ty::BoundRegionKind| match br { - ty::BrNamed(_, name) => format!(" {}", name), - _ => String::new(), - }; - match self { CyclicTy(_) => "cyclic type of infinite size".into(), CyclicConst(_) => "encountered a self-referencing constant".into(), @@ -144,11 +137,6 @@ impl<'tcx> TypeError<'tcx> { RegionsInsufficientlyPolymorphic(..) => { "one type is more general than the other".into() } - RegionsOverlyPolymorphic(br, _) => format!( - "expected concrete lifetime, found bound lifetime parameter{}", - br_string(br) - ) - .into(), RegionsPlaceholderMismatch => "one type is more general than the other".into(), ArgumentSorts(values, _) | Sorts(values) => { let expected = values.expected.sort_string(tcx); @@ -228,7 +216,6 @@ impl<'tcx> TypeError<'tcx> { | FieldMisMatch(..) | RegionsDoesNotOutlive(..) | RegionsInsufficientlyPolymorphic(..) - | RegionsOverlyPolymorphic(..) | RegionsPlaceholderMismatch | Traits(_) | ProjectionMismatched(_) diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index 25890eb15cd..149ce29b8d9 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -213,7 +213,7 @@ where // debruijn index. Then we adjust it to the // correct depth. assert_eq!(debruijn1, ty::INNERMOST); - self.tcx.mk_re_late_bound(debruijn, br) + ty::Region::new_late_bound(self.tcx, debruijn, br) } else { region } @@ -328,7 +328,7 @@ impl<'tcx> TyCtxt<'tcx> { T: TypeFoldable<TyCtxt<'tcx>>, { self.replace_late_bound_regions_uncached(value, |br| { - self.mk_re_free(all_outlive_scope, br.kind) + ty::Region::new_free(self, all_outlive_scope, br.kind) }) } @@ -341,7 +341,8 @@ impl<'tcx> TyCtxt<'tcx> { value, FnMutDelegate { regions: &mut |r: ty::BoundRegion| { - self.mk_re_late_bound( + ty::Region::new_late_bound( + self, ty::INNERMOST, ty::BoundRegion { var: shift_bv(r.var), kind: r.kind }, ) @@ -383,7 +384,7 @@ impl<'tcx> TyCtxt<'tcx> { .or_insert_with(|| ty::BoundVariableKind::Region(ty::BrAnon(None))) .expect_region(); let br = ty::BoundRegion { var, kind }; - self.tcx.mk_re_late_bound(ty::INNERMOST, br) + ty::Region::new_late_bound(self.tcx, ty::INNERMOST, br) } fn replace_ty(&mut self, bt: ty::BoundTy) -> Ty<'tcx> { let entry = self.map.entry(bt.var); @@ -451,7 +452,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for Shifter<'tcx> { match *r { ty::ReLateBound(debruijn, br) if debruijn >= self.current_index => { let debruijn = debruijn.shifted_in(self.amount); - self.tcx.mk_re_late_bound(debruijn, br) + ty::Region::new_late_bound(self.tcx, debruijn, br) } _ => r, } @@ -492,7 +493,7 @@ pub fn shift_region<'tcx>( ) -> ty::Region<'tcx> { match *region { ty::ReLateBound(debruijn, br) if amount > 0 => { - tcx.mk_re_late_bound(debruijn.shifted_in(amount), br) + ty::Region::new_late_bound(tcx, debruijn.shifted_in(amount), br) } _ => region, } diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs index b0ffe78299d..30f92b91cb7 100644 --- a/compiler/rustc_middle/src/ty/generics.rs +++ b/compiler/rustc_middle/src/ty/generics.rs @@ -100,7 +100,7 @@ impl GenericParamDef { preceding_substs: &[ty::GenericArg<'tcx>], ) -> ty::GenericArg<'tcx> { match &self.kind { - ty::GenericParamDefKind::Lifetime => tcx.mk_re_error_misc().into(), + ty::GenericParamDefKind::Lifetime => ty::Region::new_error_misc(tcx).into(), ty::GenericParamDefKind::Type { .. } => tcx.ty_error_misc().into(), ty::GenericParamDefKind::Const { .. } => { tcx.const_error_misc(tcx.type_of(self.def_id).subst(tcx, preceding_substs)).into() @@ -343,7 +343,7 @@ impl<'tcx> GenericPredicates<'tcx> { substs: SubstsRef<'tcx>, ) -> impl Iterator<Item = (Predicate<'tcx>, Span)> + DoubleEndedIterator + ExactSizeIterator { - EarlyBinder(self.predicates).subst_iter_copied(tcx, substs) + EarlyBinder::bind(self.predicates).subst_iter_copied(tcx, substs) } #[instrument(level = "debug", skip(self, tcx))] @@ -358,7 +358,7 @@ impl<'tcx> GenericPredicates<'tcx> { } instantiated .predicates - .extend(self.predicates.iter().map(|(p, _)| EarlyBinder(*p).subst(tcx, substs))); + .extend(self.predicates.iter().map(|(p, _)| EarlyBinder::bind(*p).subst(tcx, substs))); instantiated.spans.extend(self.predicates.iter().map(|(_, sp)| *sp)); } diff --git a/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs b/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs index ac42d6e0510..d48672b2baa 100644 --- a/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs +++ b/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs @@ -158,7 +158,7 @@ impl<'tcx> InhabitedPredicate<'tcx> { fn subst_opt(self, tcx: TyCtxt<'tcx>, substs: ty::SubstsRef<'tcx>) -> Option<Self> { match self { Self::ConstIsZero(c) => { - let c = ty::EarlyBinder(c).subst(tcx, substs); + let c = ty::EarlyBinder::bind(c).subst(tcx, substs); let pred = match c.kind().try_to_target_usize(tcx) { Some(0) => Self::True, Some(1..) => Self::False, @@ -167,7 +167,7 @@ impl<'tcx> InhabitedPredicate<'tcx> { Some(pred) } Self::GenericType(t) => { - Some(ty::EarlyBinder(t).subst(tcx, substs).inhabited_predicate(tcx)) + Some(ty::EarlyBinder::bind(t).subst(tcx, substs).inhabited_predicate(tcx)) } Self::And(&[a, b]) => match a.subst_opt(tcx, substs) { None => b.subst_opt(tcx, substs).map(|b| a.and(tcx, b)), diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index a8d0dca37ff..72341e656e2 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -53,7 +53,6 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{ExpnId, ExpnKind, Span}; use rustc_target::abi::{Align, FieldIdx, Integer, IntegerType, VariantIdx}; pub use rustc_target::abi::{ReprFlags, ReprOptions}; -use rustc_type_ir::WithCachedTypeInfo; pub use subst::*; pub use vtable::*; @@ -145,6 +144,7 @@ mod opaque_types; mod parameterized; mod rvalue_scopes; mod structural_impls; +#[cfg_attr(not(bootstrap), allow(hidden_glob_reexports))] mod sty; mod typeck_results; @@ -764,7 +764,7 @@ impl<'tcx> Predicate<'tcx> { let shifted_pred = tcx.shift_bound_var_indices(trait_bound_vars.len(), bound_pred.skip_binder()); // 2) Self: Bar1<'a, '^0.1> -> T: Bar1<'^0.0, '^0.1> - let new = EarlyBinder(shifted_pred).subst(tcx, trait_ref.skip_binder().substs); + let new = EarlyBinder::bind(shifted_pred).subst(tcx, trait_ref.skip_binder().substs); // 3) ['x] + ['b] -> ['x, 'b] let bound_vars = tcx.mk_bound_variable_kinds_from_iter(trait_bound_vars.iter().chain(pred_bound_vars)); @@ -1496,7 +1496,7 @@ impl<'tcx> OpaqueHiddenType<'tcx> { /// identified by both a universe, as well as a name residing within that universe. Distinct bound /// regions/types/consts within the same universe simply have an unknown relationship to one /// another. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] #[derive(HashStable, TyEncodable, TyDecodable)] pub struct Placeholder<T> { pub universe: UniverseIndex, diff --git a/compiler/rustc_middle/src/ty/opaque_types.rs b/compiler/rustc_middle/src/ty/opaque_types.rs index 1b336b7bfc6..d1ed7be3d2e 100644 --- a/compiler/rustc_middle/src/ty/opaque_types.rs +++ b/compiler/rustc_middle/src/ty/opaque_types.rs @@ -141,7 +141,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReverseMapper<'tcx> { ) .emit(); - self.interner().mk_re_error(e) + ty::Region::new_error(self.interner(), e) } } } diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs index 64e7480e626..2de0a3f75dc 100644 --- a/compiler/rustc_middle/src/ty/print/mod.rs +++ b/compiler/rustc_middle/src/ty/print/mod.rs @@ -123,7 +123,7 @@ pub trait Printer<'tcx>: Sized { impl_trait_ref.map(|i| i.subst(self.tcx(), substs)), ) } else { - (self_ty.0, impl_trait_ref.map(|i| i.0)) + (self_ty.subst_identity(), impl_trait_ref.map(|i| i.subst_identity())) }; self.print_impl_path(def_id, substs, self_ty, impl_trait_ref) } diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index a064174e261..6156fdf7eac 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -184,7 +184,7 @@ impl<'tcx> RegionHighlightMode<'tcx> { /// Convenience wrapper for `highlighting_region`. pub fn highlighting_region_vid(&mut self, vid: ty::RegionVid, number: usize) { - self.highlighting_region(self.tcx.mk_re_var(vid), number) + self.highlighting_region(ty::Region::new_var(self.tcx, vid), number) } /// Returns `Some(n)` with the number to use for the given region, if any. @@ -685,29 +685,30 @@ pub trait PrettyPrinter<'tcx>: } ty::FnPtr(ref bare_fn) => p!(print(bare_fn)), ty::Infer(infer_ty) => { - let verbose = self.should_print_verbose(); + if self.should_print_verbose() { + p!(write("{:?}", ty.kind())); + return Ok(self); + } + if let ty::TyVar(ty_vid) = infer_ty { if let Some(name) = self.ty_infer_name(ty_vid) { p!(write("{}", name)) } else { - if verbose { - p!(write("{:?}", infer_ty)) - } else { - p!(write("{}", infer_ty)) - } + p!(write("{}", infer_ty)) } } else { - if verbose { p!(write("{:?}", infer_ty)) } else { p!(write("{}", infer_ty)) } + p!(write("{}", infer_ty)) } } - ty::Error(_) => p!("[type error]"), + ty::Error(_) => p!("{{type error}}"), ty::Param(ref param_ty) => p!(print(param_ty)), ty::Bound(debruijn, bound_ty) => match bound_ty.kind { - ty::BoundTyKind::Anon => debug_bound_var(&mut self, debruijn, bound_ty.var)?, + ty::BoundTyKind::Anon => { + rustc_type_ir::debug_bound_var(&mut self, debruijn, bound_ty.var)? + } ty::BoundTyKind::Param(_, s) => match self.should_print_verbose() { - true if debruijn == ty::INNERMOST => p!(write("^{}", s)), - true => p!(write("^{}_{}", debruijn.index(), s)), - false => p!(write("{}", s)), + true => p!(write("{:?}", ty.kind())), + false => p!(write("{s}")), }, }, ty::Adt(def, substs) => { @@ -740,10 +741,11 @@ pub trait PrettyPrinter<'tcx>: } } ty::Placeholder(placeholder) => match placeholder.bound.kind { - ty::BoundTyKind::Anon => { - debug_placeholder_var(&mut self, placeholder.universe, placeholder.bound.var)?; - } - ty::BoundTyKind::Param(_, name) => p!(write("{}", name)), + ty::BoundTyKind::Anon => p!(write("{placeholder:?}")), + ty::BoundTyKind::Param(_, name) => match self.should_print_verbose() { + true => p!(write("{:?}", ty.kind())), + false => p!(write("{name}")), + }, }, ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => { // We use verbose printing in 'NO_QUERIES' mode, to @@ -1372,15 +1374,13 @@ pub trait PrettyPrinter<'tcx>: } ty::ConstKind::Bound(debruijn, bound_var) => { - debug_bound_var(&mut self, debruijn, bound_var)? + rustc_type_ir::debug_bound_var(&mut self, debruijn, bound_var)? } - ty::ConstKind::Placeholder(placeholder) => { - debug_placeholder_var(&mut self, placeholder.universe, placeholder.bound)?; - }, + ty::ConstKind::Placeholder(placeholder) => p!(write("{placeholder:?}")), // FIXME(generic_const_exprs): // write out some legible representation of an abstract const? - ty::ConstKind::Expr(_) => p!("[const expr]"), - ty::ConstKind::Error(_) => p!("[const error]"), + ty::ConstKind::Expr(_) => p!("{{const expr}}"), + ty::ConstKind::Error(_) => p!("{{const error}}"), }; Ok(self) } @@ -2303,7 +2303,7 @@ impl<'a, 'tcx> ty::TypeFolder<TyCtxt<'tcx>> for RegionFolder<'a, 'tcx> { }; if let ty::ReLateBound(debruijn1, br) = *region { assert_eq!(debruijn1, ty::INNERMOST); - self.tcx.mk_re_late_bound(self.current_index, br) + ty::Region::new_late_bound(self.tcx, self.current_index, br) } else { region } @@ -2415,7 +2415,8 @@ impl<'tcx> FmtPrinter<'_, 'tcx> { if let Some(lt_idx) = lifetime_idx { if lt_idx > binder_level_idx { let kind = ty::BrNamed(CRATE_DEF_ID.to_def_id(), name); - return tcx.mk_re_late_bound( + return ty::Region::new_late_bound( + tcx, ty::INNERMOST, ty::BoundRegion { var: br.var, kind }, ); @@ -2430,7 +2431,8 @@ impl<'tcx> FmtPrinter<'_, 'tcx> { if let Some(lt_idx) = lifetime_idx { if lt_idx > binder_level_idx { let kind = ty::BrNamed(def_id, name); - return tcx.mk_re_late_bound( + return ty::Region::new_late_bound( + tcx, ty::INNERMOST, ty::BoundRegion { var: br.var, kind }, ); @@ -2443,7 +2445,8 @@ impl<'tcx> FmtPrinter<'_, 'tcx> { if let Some(lt_idx) = lifetime_idx { if lt_idx > binder_level_idx { let kind = br.kind; - return tcx.mk_re_late_bound( + return ty::Region::new_late_bound( + tcx, ty::INNERMOST, ty::BoundRegion { var: br.var, kind }, ); @@ -2458,7 +2461,11 @@ impl<'tcx> FmtPrinter<'_, 'tcx> { start_or_continue(&mut self, "for<", ", "); do_continue(&mut self, name); } - tcx.mk_re_late_bound(ty::INNERMOST, ty::BoundRegion { var: br.var, kind }) + ty::Region::new_late_bound( + tcx, + ty::INNERMOST, + ty::BoundRegion { var: br.var, kind }, + ) }; let mut folder = RegionFolder { tcx, @@ -3065,27 +3072,3 @@ pub struct OpaqueFnEntry<'tcx> { fn_trait_ref: Option<ty::PolyTraitRef<'tcx>>, return_ty: Option<ty::Binder<'tcx, Term<'tcx>>>, } - -pub fn debug_bound_var<T: std::fmt::Write>( - fmt: &mut T, - debruijn: ty::DebruijnIndex, - var: ty::BoundVar, -) -> Result<(), std::fmt::Error> { - if debruijn == ty::INNERMOST { - write!(fmt, "^{}", var.index()) - } else { - write!(fmt, "^{}_{}", debruijn.index(), var.index()) - } -} - -pub fn debug_placeholder_var<T: std::fmt::Write>( - fmt: &mut T, - universe: ty::UniverseIndex, - bound: ty::BoundVar, -) -> Result<(), std::fmt::Error> { - if universe == ty::UniverseIndex::ROOT { - write!(fmt, "!{}", bound.index()) - } else { - write!(fmt, "!{}_{}", universe.index(), bound.index()) - } -} diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 16cb6c91046..a965450d27d 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -88,7 +88,35 @@ impl fmt::Debug for ty::FreeRegion { impl<'tcx> fmt::Debug for ty::FnSig<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "({:?}; c_variadic: {})->{:?}", self.inputs(), self.c_variadic, self.output()) + let ty::FnSig { inputs_and_output: _, c_variadic, unsafety, abi } = self; + + write!(f, "{}", unsafety.prefix_str())?; + match abi { + rustc_target::spec::abi::Abi::Rust => (), + abi => write!(f, "extern \"{abi:?}\" ")?, + }; + + write!(f, "fn(")?; + let inputs = self.inputs(); + match inputs.len() { + 0 if *c_variadic => write!(f, "...)")?, + 0 => write!(f, ")")?, + _ => { + for ty in &self.inputs()[0..(self.inputs().len() - 1)] { + write!(f, "{ty:?}, ")?; + } + write!(f, "{:?}", self.inputs().last().unwrap())?; + if *c_variadic { + write!(f, "...")?; + } + write!(f, ")")?; + } + } + + match self.output().kind() { + ty::Tuple(list) if list.is_empty() => Ok(()), + _ => write!(f, " -> {:?}", self.output()), + } } } @@ -216,20 +244,37 @@ impl<'tcx> fmt::Debug for ty::ConstKind<'tcx> { match self { Param(param) => write!(f, "{param:?}"), Infer(var) => write!(f, "{var:?}"), - Bound(debruijn, var) => ty::print::debug_bound_var(f, *debruijn, *var), - Placeholder(placeholder) => { - ty::print::debug_placeholder_var(f, placeholder.universe, placeholder.bound) - } + Bound(debruijn, var) => rustc_type_ir::debug_bound_var(f, *debruijn, *var), + Placeholder(placeholder) => write!(f, "{placeholder:?}"), Unevaluated(uv) => { f.debug_tuple("Unevaluated").field(&uv.substs).field(&uv.def).finish() } Value(valtree) => write!(f, "{valtree:?}"), - Error(_) => write!(f, "[const error]"), + Error(_) => write!(f, "{{const error}}"), Expr(expr) => write!(f, "{expr:?}"), } } } +impl fmt::Debug for ty::BoundTy { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self.kind { + ty::BoundTyKind::Anon => write!(f, "{:?}", self.var), + ty::BoundTyKind::Param(_, sym) => write!(f, "{sym:?}"), + } + } +} + +impl<T: fmt::Debug> fmt::Debug for ty::Placeholder<T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if self.universe == ty::UniverseIndex::ROOT { + write!(f, "!{:?}", self.bound) + } else { + write!(f, "!{}_{:?}", self.universe.index(), self.bound) + } + } +} + /////////////////////////////////////////////////////////////////////////// // Atomic structs // @@ -294,6 +339,7 @@ TrivialTypeTraversalAndLiftImpls! { crate::ty::AliasRelationDirection, crate::ty::Placeholder<crate::ty::BoundRegion>, crate::ty::Placeholder<crate::ty::BoundTy>, + crate::ty::Placeholder<ty::BoundVar>, crate::ty::ClosureKind, crate::ty::FreeRegion, crate::ty::InferTy, @@ -310,7 +356,6 @@ TrivialTypeTraversalAndLiftImpls! { interpret::Scalar, rustc_target::abi::Size, ty::BoundVar, - ty::Placeholder<ty::BoundVar>, } TrivialTypeTraversalAndLiftImpls! { diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index e6d51c4ec97..d19a7bcde79 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -15,14 +15,14 @@ use hir::def::DefKind; use polonius_engine::Atom; use rustc_data_structures::captures::Captures; use rustc_data_structures::intern::Interned; -use rustc_errors::{DiagnosticArgValue, IntoDiagnosticArg}; +use rustc_errors::{DiagnosticArgValue, ErrorGuaranteed, IntoDiagnosticArg, MultiSpan}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::LangItem; use rustc_index::Idx; use rustc_macros::HashStable; use rustc_span::symbol::{kw, sym, Symbol}; -use rustc_span::Span; +use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::{FieldIdx, VariantIdx, FIRST_VARIANT}; use rustc_target::spec::abi::{self, Abi}; use std::borrow::Cow; @@ -568,7 +568,7 @@ impl<'tcx> GeneratorSubsts<'tcx> { let layout = tcx.generator_layout(def_id).unwrap(); layout.variant_fields.iter().map(move |variant| { variant.iter().map(move |field| { - ty::EarlyBinder(layout.field_tys[*field].ty).subst(tcx, self.substs) + ty::EarlyBinder::bind(layout.field_tys[*field].ty).subst(tcx, self.substs) }) }) } @@ -1459,6 +1459,103 @@ impl ParamConst { #[rustc_pass_by_value] pub struct Region<'tcx>(pub Interned<'tcx, RegionKind<'tcx>>); +impl<'tcx> Region<'tcx> { + #[inline] + pub fn new_early_bound( + tcx: TyCtxt<'tcx>, + early_bound_region: ty::EarlyBoundRegion, + ) -> Region<'tcx> { + tcx.intern_region(ty::ReEarlyBound(early_bound_region)) + } + + #[inline] + pub fn new_late_bound( + tcx: TyCtxt<'tcx>, + debruijn: ty::DebruijnIndex, + bound_region: ty::BoundRegion, + ) -> Region<'tcx> { + // Use a pre-interned one when possible. + if let ty::BoundRegion { var, kind: ty::BrAnon(None) } = bound_region + && let Some(inner) = tcx.lifetimes.re_late_bounds.get(debruijn.as_usize()) + && let Some(re) = inner.get(var.as_usize()).copied() + { + re + } else { + tcx.intern_region(ty::ReLateBound(debruijn, bound_region)) + } + } + + #[inline] + pub fn new_free( + tcx: TyCtxt<'tcx>, + scope: DefId, + bound_region: ty::BoundRegionKind, + ) -> Region<'tcx> { + tcx.intern_region(ty::ReFree(ty::FreeRegion { scope, bound_region })) + } + + #[inline] + pub fn new_var(tcx: TyCtxt<'tcx>, v: ty::RegionVid) -> Region<'tcx> { + // Use a pre-interned one when possible. + tcx.lifetimes + .re_vars + .get(v.as_usize()) + .copied() + .unwrap_or_else(|| tcx.intern_region(ty::ReVar(v))) + } + + #[inline] + pub fn new_placeholder(tcx: TyCtxt<'tcx>, placeholder: ty::PlaceholderRegion) -> Region<'tcx> { + tcx.intern_region(ty::RePlaceholder(placeholder)) + } + + /// Constructs a `RegionKind::ReError` region. + #[track_caller] + pub fn new_error(tcx: TyCtxt<'tcx>, reported: ErrorGuaranteed) -> Region<'tcx> { + tcx.intern_region(ty::ReError(reported)) + } + + /// Constructs a `RegionKind::ReError` region and registers a `delay_span_bug` to ensure it + /// gets used. + #[track_caller] + pub fn new_error_misc(tcx: TyCtxt<'tcx>) -> Region<'tcx> { + Region::new_error_with_message( + tcx, + DUMMY_SP, + "RegionKind::ReError constructed but no error reported", + ) + } + + /// Constructs a `RegionKind::ReError` region and registers a `delay_span_bug` with the given + /// `msg` to ensure it gets used. + #[track_caller] + pub fn new_error_with_message<S: Into<MultiSpan>>( + tcx: TyCtxt<'tcx>, + span: S, + msg: &'static str, + ) -> Region<'tcx> { + let reported = tcx.sess.delay_span_bug(span, msg); + Region::new_error(tcx, reported) + } + + /// Avoid this in favour of more specific `new_*` methods, where possible, + /// to avoid the cost of the `match`. + pub fn new_from_kind(tcx: TyCtxt<'tcx>, kind: RegionKind<'tcx>) -> Region<'tcx> { + match kind { + ty::ReEarlyBound(region) => Region::new_early_bound(tcx, region), + ty::ReLateBound(debruijn, region) => Region::new_late_bound(tcx, debruijn, region), + ty::ReFree(ty::FreeRegion { scope, bound_region }) => { + Region::new_free(tcx, scope, bound_region) + } + ty::ReStatic => tcx.lifetimes.re_static, + ty::ReVar(vid) => Region::new_var(tcx, vid), + ty::RePlaceholder(region) => Region::new_placeholder(tcx, region), + ty::ReErased => tcx.lifetimes.re_erased, + ty::ReError(reported) => Region::new_error(tcx, reported), + } + } +} + impl<'tcx> Deref for Region<'tcx> { type Target = RegionKind<'tcx>; @@ -1511,10 +1608,11 @@ impl Atom for RegionVid { rustc_index::newtype_index! { #[derive(HashStable)] + #[debug_format = "{}"] pub struct BoundVar {} } -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)] +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)] #[derive(HashStable)] pub struct BoundTy { pub var: BoundVar, @@ -2366,7 +2464,7 @@ impl<'tcx> Ty<'tcx> { ty::Tuple(tys) => tys.iter().all(|ty| ty.is_trivially_sized(tcx)), - ty::Adt(def, _substs) => def.sized_constraint(tcx).0.is_empty(), + ty::Adt(def, _substs) => def.sized_constraint(tcx).skip_binder().is_empty(), ty::Alias(..) | ty::Param(_) | ty::Placeholder(..) => false, diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs index 43f95635ab0..8685a22d9ca 100644 --- a/compiler/rustc_middle/src/ty/subst.rs +++ b/compiler/rustc_middle/src/ty/subst.rs @@ -538,13 +538,17 @@ impl<'tcx, T: TypeVisitable<TyCtxt<'tcx>>> TypeVisitable<TyCtxt<'tcx>> for &'tcx /// [`subst_identity`](EarlyBinder::subst_identity) or [`skip_binder`](EarlyBinder::skip_binder). #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] #[derive(Encodable, Decodable, HashStable)] -pub struct EarlyBinder<T>(pub T); +pub struct EarlyBinder<T>(T); /// For early binders, you should first call `subst` before using any visitors. impl<'tcx, T> !TypeFoldable<TyCtxt<'tcx>> for ty::EarlyBinder<T> {} impl<'tcx, T> !TypeVisitable<TyCtxt<'tcx>> for ty::EarlyBinder<T> {} impl<T> EarlyBinder<T> { + pub fn bind(inner: T) -> EarlyBinder<T> { + EarlyBinder(inner) + } + pub fn as_ref(&self) -> EarlyBinder<&T> { EarlyBinder(&self.0) } @@ -582,6 +586,9 @@ impl<T> EarlyBinder<T> { /// arguments of an `FnSig`). Otherwise, consider using /// [`subst_identity`](EarlyBinder::subst_identity). /// + /// To skip the binder on `x: &EarlyBinder<T>` to obtain `&T`, leverage + /// [`EarlyBinder::as_ref`](EarlyBinder::as_ref): `x.as_ref().skip_binder()`. + /// /// See also [`Binder::skip_binder`](super::Binder::skip_binder), which is /// the analogous operation on [`super::Binder`]. pub fn skip_binder(self) -> T { diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index ba05135638e..311f63adc7f 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -709,7 +709,7 @@ impl<'tcx> TyCtxt<'tcx> { .as_ref() .map_or_else(|| [].iter(), |l| l.field_tys.iter()) .filter(|decl| !decl.ignore_for_traits) - .map(|decl| ty::EarlyBinder(decl.ty)) + .map(|decl| ty::EarlyBinder::bind(decl.ty)) } /// Normalizes all opaque types in the given value, replacing them diff --git a/compiler/rustc_middle/src/values.rs b/compiler/rustc_middle/src/values.rs index c62c33d4dfc..a00c77ccbcd 100644 --- a/compiler/rustc_middle/src/values.rs +++ b/compiler/rustc_middle/src/values.rs @@ -96,13 +96,13 @@ impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for Representability { impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::EarlyBinder<Ty<'_>> { fn from_cycle_error(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo<DepKind>]) -> Self { - ty::EarlyBinder(Ty::from_cycle_error(tcx, cycle)) + ty::EarlyBinder::bind(Ty::from_cycle_error(tcx, cycle)) } } impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::EarlyBinder<ty::Binder<'_, ty::FnSig<'_>>> { fn from_cycle_error(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo<DepKind>]) -> Self { - ty::EarlyBinder(ty::Binder::from_cycle_error(tcx, cycle)) + ty::EarlyBinder::bind(ty::Binder::from_cycle_error(tcx, cycle)) } } diff --git a/compiler/rustc_mir_build/messages.ftl b/compiler/rustc_mir_build/messages.ftl index 0282492a261..cb265cf2c6a 100644 --- a/compiler/rustc_mir_build/messages.ftl +++ b/compiler/rustc_mir_build/messages.ftl @@ -1,62 +1,40 @@ -mir_build_unconditional_recursion = function cannot return without recursing - .label = cannot return without recursing - .help = a `loop` may express intention better if this is on purpose - -mir_build_unconditional_recursion_call_site_label = recursive call site - -mir_build_unsafe_op_in_unsafe_fn_call_to_unsafe_fn_requires_unsafe = - call to unsafe function `{$function}` is unsafe and requires unsafe block (error E0133) - .note = consult the function's documentation for information on how to avoid undefined behavior - .label = call to unsafe function - -mir_build_unsafe_op_in_unsafe_fn_call_to_unsafe_fn_requires_unsafe_nameless = - call to unsafe function is unsafe and requires unsafe block (error E0133) - .note = consult the function's documentation for information on how to avoid undefined behavior - .label = call to unsafe function - -mir_build_unsafe_op_in_unsafe_fn_inline_assembly_requires_unsafe = - use of inline assembly is unsafe and requires unsafe block (error E0133) - .note = inline assembly is entirely unchecked and can cause undefined behavior - .label = use of inline assembly +mir_build_adt_defined_here = `{$ty}` defined here -mir_build_unsafe_op_in_unsafe_fn_initializing_type_with_requires_unsafe = - initializing type with `rustc_layout_scalar_valid_range` attr is unsafe and requires unsafe - block (error E0133) - .note = initializing a layout restricted type's field with a value outside the valid range is undefined behavior - .label = initializing type with `rustc_layout_scalar_valid_range` attr +mir_build_already_borrowed = cannot borrow value as mutable because it is also borrowed as immutable -mir_build_unsafe_op_in_unsafe_fn_mutable_static_requires_unsafe = - use of mutable static is unsafe and requires unsafe block (error E0133) - .note = mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior - .label = use of mutable static +mir_build_already_mut_borrowed = cannot borrow value as immutable because it is also borrowed as mutable -mir_build_unsafe_op_in_unsafe_fn_extern_static_requires_unsafe = - use of extern static is unsafe and requires unsafe block (error E0133) - .note = extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior - .label = use of extern static +mir_build_assoc_const_in_pattern = associated consts cannot be referenced in patterns -mir_build_unsafe_op_in_unsafe_fn_deref_raw_pointer_requires_unsafe = - dereference of raw pointer is unsafe and requires unsafe block (error E0133) - .note = raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior - .label = dereference of raw pointer +mir_build_bindings_with_variant_name = + pattern binding `{$name}` is named the same as one of the variants of the type `{$ty_path}` + .suggestion = to match on the variant, qualify the path -mir_build_unsafe_op_in_unsafe_fn_union_field_requires_unsafe = - access to union field is unsafe and requires unsafe block (error E0133) - .note = the field may not be properly initialized: using uninitialized data will cause undefined behavior - .label = access to union field +mir_build_borrow = value is borrowed by `{$name}` here -mir_build_unsafe_op_in_unsafe_fn_mutation_of_layout_constrained_field_requires_unsafe = - mutation of layout constrained field is unsafe and requires unsafe block (error E0133) - .note = mutating layout constrained fields cannot statically be checked for valid values - .label = mutation of layout constrained field +mir_build_borrow_of_layout_constrained_field_requires_unsafe = + borrow of layout constrained field with interior mutability is unsafe and requires unsafe block + .note = references to fields of layout constrained fields lose the constraints. Coupled with interior mutability, the field can be changed to invalid values + .label = borrow of layout constrained field with interior mutability -mir_build_unsafe_op_in_unsafe_fn_borrow_of_layout_constrained_field_requires_unsafe = - borrow of layout constrained field with interior mutability is unsafe and requires unsafe block (error E0133) +mir_build_borrow_of_layout_constrained_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed = + borrow of layout constrained field with interior mutability is unsafe and requires unsafe function or block .note = references to fields of layout constrained fields lose the constraints. Coupled with interior mutability, the field can be changed to invalid values .label = borrow of layout constrained field with interior mutability -mir_build_unsafe_op_in_unsafe_fn_call_to_fn_with_requires_unsafe = - call to function `{$function}` with `#[target_feature]` is unsafe and requires unsafe block (error E0133) +mir_build_borrow_of_moved_value = borrow of moved value + .label = value moved into `{$name}` here + .occurs_because_label = move occurs because `{$name}` has type `{$ty}` which does not implement the `Copy` trait + .value_borrowed_label = value borrowed here after move + .suggestion = borrow this binding in the pattern to avoid moving the value + +mir_build_call_to_fn_with_requires_unsafe = + call to function `{$function}` with `#[target_feature]` is unsafe and requires unsafe block + .note = can only be called if the required target features are available + .label = call to function with `#[target_feature]` + +mir_build_call_to_fn_with_requires_unsafe_unsafe_op_in_unsafe_fn_allowed = + call to function `{$function}` with `#[target_feature]` is unsafe and requires unsafe function or block .note = can only be called if the required target features are available .label = call to function with `#[target_feature]` @@ -70,55 +48,24 @@ mir_build_call_to_unsafe_fn_requires_unsafe_nameless = .note = consult the function's documentation for information on how to avoid undefined behavior .label = call to unsafe function -mir_build_call_to_unsafe_fn_requires_unsafe_unsafe_op_in_unsafe_fn_allowed = - call to unsafe function `{$function}` is unsafe and requires unsafe function or block - .note = consult the function's documentation for information on how to avoid undefined behavior - .label = call to unsafe function - mir_build_call_to_unsafe_fn_requires_unsafe_nameless_unsafe_op_in_unsafe_fn_allowed = call to unsafe function is unsafe and requires unsafe function or block .note = consult the function's documentation for information on how to avoid undefined behavior .label = call to unsafe function -mir_build_inline_assembly_requires_unsafe = - use of inline assembly is unsafe and requires unsafe block - .note = inline assembly is entirely unchecked and can cause undefined behavior - .label = use of inline assembly - -mir_build_inline_assembly_requires_unsafe_unsafe_op_in_unsafe_fn_allowed = - use of inline assembly is unsafe and requires unsafe function or block - .note = inline assembly is entirely unchecked and can cause undefined behavior - .label = use of inline assembly - -mir_build_initializing_type_with_requires_unsafe = - initializing type with `rustc_layout_scalar_valid_range` attr is unsafe and requires unsafe block - .note = initializing a layout restricted type's field with a value outside the valid range is undefined behavior - .label = initializing type with `rustc_layout_scalar_valid_range` attr - -mir_build_initializing_type_with_requires_unsafe_unsafe_op_in_unsafe_fn_allowed = - initializing type with `rustc_layout_scalar_valid_range` attr is unsafe and requires unsafe function or block - .note = initializing a layout restricted type's field with a value outside the valid range is undefined behavior - .label = initializing type with `rustc_layout_scalar_valid_range` attr +mir_build_call_to_unsafe_fn_requires_unsafe_unsafe_op_in_unsafe_fn_allowed = + call to unsafe function `{$function}` is unsafe and requires unsafe function or block + .note = consult the function's documentation for information on how to avoid undefined behavior + .label = call to unsafe function -mir_build_mutable_static_requires_unsafe = - use of mutable static is unsafe and requires unsafe block - .note = mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior - .label = use of mutable static +mir_build_confused = missing patterns are not covered because `{$variable}` is interpreted as a constant pattern, not a new variable -mir_build_mutable_static_requires_unsafe_unsafe_op_in_unsafe_fn_allowed = - use of mutable static is unsafe and requires unsafe function or block - .note = mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior - .label = use of mutable static +mir_build_const_param_in_pattern = const parameters cannot be referenced in patterns -mir_build_extern_static_requires_unsafe = - use of extern static is unsafe and requires unsafe block - .note = extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior - .label = use of extern static +mir_build_const_pattern_depends_on_generic_parameter = + constant pattern depends on a generic parameter -mir_build_extern_static_requires_unsafe_unsafe_op_in_unsafe_fn_allowed = - use of extern static is unsafe and requires unsafe function or block - .note = extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior - .label = use of extern static +mir_build_could_not_eval_const_pattern = could not evaluate constant pattern mir_build_deref_raw_pointer_requires_unsafe = dereference of raw pointer is unsafe and requires unsafe block @@ -130,117 +77,46 @@ mir_build_deref_raw_pointer_requires_unsafe_unsafe_op_in_unsafe_fn_allowed = .note = raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior .label = dereference of raw pointer -mir_build_union_field_requires_unsafe = - access to union field is unsafe and requires unsafe block - .note = the field may not be properly initialized: using uninitialized data will cause undefined behavior - .label = access to union field - -mir_build_union_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed = - access to union field is unsafe and requires unsafe function or block - .note = the field may not be properly initialized: using uninitialized data will cause undefined behavior - .label = access to union field - -mir_build_mutation_of_layout_constrained_field_requires_unsafe = - mutation of layout constrained field is unsafe and requires unsafe block - .note = mutating layout constrained fields cannot statically be checked for valid values - .label = mutation of layout constrained field - -mir_build_mutation_of_layout_constrained_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed = - mutation of layout constrained field is unsafe and requires unsafe function or block - .note = mutating layout constrained fields cannot statically be checked for valid values - .label = mutation of layout constrained field - -mir_build_borrow_of_layout_constrained_field_requires_unsafe = - borrow of layout constrained field with interior mutability is unsafe and requires unsafe block - .note = references to fields of layout constrained fields lose the constraints. Coupled with interior mutability, the field can be changed to invalid values - .label = borrow of layout constrained field with interior mutability - -mir_build_borrow_of_layout_constrained_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed = - borrow of layout constrained field with interior mutability is unsafe and requires unsafe function or block - .note = references to fields of layout constrained fields lose the constraints. Coupled with interior mutability, the field can be changed to invalid values - .label = borrow of layout constrained field with interior mutability - -mir_build_call_to_fn_with_requires_unsafe = - call to function `{$function}` with `#[target_feature]` is unsafe and requires unsafe block - .note = can only be called if the required target features are available - .label = call to function with `#[target_feature]` - -mir_build_call_to_fn_with_requires_unsafe_unsafe_op_in_unsafe_fn_allowed = - call to function `{$function}` with `#[target_feature]` is unsafe and requires unsafe function or block - .note = can only be called if the required target features are available - .label = call to function with `#[target_feature]` - -mir_build_unused_unsafe = unnecessary `unsafe` block - .label = unnecessary `unsafe` block - -mir_build_unused_unsafe_enclosing_block_label = because it's nested under this `unsafe` block -mir_build_unused_unsafe_enclosing_fn_label = because it's nested under this `unsafe` fn - -mir_build_non_exhaustive_patterns_type_not_empty = non-exhaustive patterns: type `{$ty}` is non-empty - .def_note = `{$peeled_ty}` defined here - .type_note = the matched value is of type `{$ty}` - .non_exhaustive_type_note = the matched value is of type `{$ty}`, which is marked as non-exhaustive - .reference_note = references are always considered inhabited - .suggestion = ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown - .help = ensure that all possible cases are being handled by adding a match arm with a wildcard pattern - -mir_build_static_in_pattern = statics cannot be referenced in patterns - -mir_build_assoc_const_in_pattern = associated consts cannot be referenced in patterns - -mir_build_const_param_in_pattern = const parameters cannot be referenced in patterns +mir_build_extern_static_requires_unsafe = + use of extern static is unsafe and requires unsafe block + .note = extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior + .label = use of extern static -mir_build_non_const_path = runtime values cannot be referenced in patterns +mir_build_extern_static_requires_unsafe_unsafe_op_in_unsafe_fn_allowed = + use of extern static is unsafe and requires unsafe function or block + .note = extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior + .label = use of extern static -mir_build_unreachable_pattern = unreachable pattern - .label = unreachable pattern - .catchall_label = matches any value +mir_build_float_pattern = floating-point types cannot be used in patterns -mir_build_const_pattern_depends_on_generic_parameter = - constant pattern depends on a generic parameter +mir_build_indirect_structural_match = + to use a constant of type `{$non_sm_ty}` in a pattern, `{$non_sm_ty}` must be annotated with `#[derive(PartialEq, Eq)]` -mir_build_could_not_eval_const_pattern = could not evaluate constant pattern +mir_build_inform_irrefutable = `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant -mir_build_lower_range_bound_must_be_less_than_or_equal_to_upper = - lower range bound must be less than or equal to upper - .label = lower bound larger than upper bound - .teach_note = When matching against a range, the compiler verifies that the range is non-empty. Range patterns include both end-points, so this is equivalent to requiring the start of the range to be less than or equal to the end of the range. +mir_build_initializing_type_with_requires_unsafe = + initializing type with `rustc_layout_scalar_valid_range` attr is unsafe and requires unsafe block + .note = initializing a layout restricted type's field with a value outside the valid range is undefined behavior + .label = initializing type with `rustc_layout_scalar_valid_range` attr -mir_build_literal_in_range_out_of_bounds = - literal out of range for `{$ty}` - .label = this value doesn't fit in `{$ty}` whose maximum value is `{$max}` +mir_build_initializing_type_with_requires_unsafe_unsafe_op_in_unsafe_fn_allowed = + initializing type with `rustc_layout_scalar_valid_range` attr is unsafe and requires unsafe function or block + .note = initializing a layout restricted type's field with a value outside the valid range is undefined behavior + .label = initializing type with `rustc_layout_scalar_valid_range` attr -mir_build_lower_range_bound_must_be_less_than_upper = lower range bound must be less than upper +mir_build_inline_assembly_requires_unsafe = + use of inline assembly is unsafe and requires unsafe block + .note = inline assembly is entirely unchecked and can cause undefined behavior + .label = use of inline assembly -mir_build_leading_irrefutable_let_patterns = leading irrefutable {$count -> - [one] pattern - *[other] patterns - } in let chain - .note = {$count -> - [one] this pattern - *[other] these patterns - } will always match - .help = consider moving {$count -> - [one] it - *[other] them - } outside of the construct +mir_build_inline_assembly_requires_unsafe_unsafe_op_in_unsafe_fn_allowed = + use of inline assembly is unsafe and requires unsafe function or block + .note = inline assembly is entirely unchecked and can cause undefined behavior + .label = use of inline assembly -mir_build_trailing_irrefutable_let_patterns = trailing irrefutable {$count -> - [one] pattern - *[other] patterns - } in let chain - .note = {$count -> - [one] this pattern - *[other] these patterns - } will always match - .help = consider moving {$count -> - [one] it - *[other] them - } into the body +mir_build_interpreted_as_const = introduce a variable instead -mir_build_bindings_with_variant_name = - pattern binding `{$name}` is named the same as one of the variants of the type `{$ty_path}` - .suggestion = to match on the variant, qualify the path +mir_build_invalid_pattern = `{$non_sm_ty}` cannot be used in patterns mir_build_irrefutable_let_patterns_if_let = irrefutable `if let` {$count -> [one] pattern @@ -282,80 +158,97 @@ mir_build_irrefutable_let_patterns_while_let = irrefutable `while let` {$count - } will always match, so the loop will never exit .help = consider instead using a `loop {"{"} ... {"}"}` with a `let` inside it -mir_build_borrow_of_moved_value = borrow of moved value - .label = value moved into `{$name}` here - .occurs_because_label = move occurs because `{$name}` has type `{$ty}` which does not implement the `Copy` trait - .value_borrowed_label = value borrowed here after move - .suggestion = borrow this binding in the pattern to avoid moving the value +mir_build_leading_irrefutable_let_patterns = leading irrefutable {$count -> + [one] pattern + *[other] patterns + } in let chain + .note = {$count -> + [one] this pattern + *[other] these patterns + } will always match + .help = consider moving {$count -> + [one] it + *[other] them + } outside of the construct -mir_build_multiple_mut_borrows = cannot borrow value as mutable more than once at a time +mir_build_literal_in_range_out_of_bounds = + literal out of range for `{$ty}` + .label = this value doesn't fit in `{$ty}` whose maximum value is `{$max}` -mir_build_already_borrowed = cannot borrow value as mutable because it is also borrowed as immutable +mir_build_lower_range_bound_must_be_less_than_or_equal_to_upper = + lower range bound must be less than or equal to upper + .label = lower bound larger than upper bound + .teach_note = When matching against a range, the compiler verifies that the range is non-empty. Range patterns include both end-points, so this is equivalent to requiring the start of the range to be less than or equal to the end of the range. -mir_build_already_mut_borrowed = cannot borrow value as immutable because it is also borrowed as mutable +mir_build_lower_range_bound_must_be_less_than_upper = lower range bound must be less than upper -mir_build_moved_while_borrowed = cannot move out of value because it is borrowed +mir_build_more_information = for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html -mir_build_mutable_borrow = value is mutably borrowed by `{$name}` here +mir_build_moved = value is moved into `{$name}` here -mir_build_borrow = value is borrowed by `{$name}` here +mir_build_moved_while_borrowed = cannot move out of value because it is borrowed -mir_build_moved = value is moved into `{$name}` here +mir_build_multiple_mut_borrows = cannot borrow value as mutable more than once at a time -mir_build_union_pattern = cannot use unions in constant patterns +mir_build_mutable_borrow = value is mutably borrowed by `{$name}` here -mir_build_type_not_structural = - to use a constant of type `{$non_sm_ty}` in a pattern, `{$non_sm_ty}` must be annotated with `#[derive(PartialEq, Eq)]` +mir_build_mutable_static_requires_unsafe = + use of mutable static is unsafe and requires unsafe block + .note = mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior + .label = use of mutable static -mir_build_unsized_pattern = cannot use unsized non-slice type `{$non_sm_ty}` in constant patterns +mir_build_mutable_static_requires_unsafe_unsafe_op_in_unsafe_fn_allowed = + use of mutable static is unsafe and requires unsafe function or block + .note = mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior + .label = use of mutable static -mir_build_invalid_pattern = `{$non_sm_ty}` cannot be used in patterns +mir_build_mutation_of_layout_constrained_field_requires_unsafe = + mutation of layout constrained field is unsafe and requires unsafe block + .note = mutating layout constrained fields cannot statically be checked for valid values + .label = mutation of layout constrained field -mir_build_float_pattern = floating-point types cannot be used in patterns +mir_build_mutation_of_layout_constrained_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed = + mutation of layout constrained field is unsafe and requires unsafe function or block + .note = mutating layout constrained fields cannot statically be checked for valid values + .label = mutation of layout constrained field -mir_build_pointer_pattern = function pointers and unsized pointers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. +mir_build_non_const_path = runtime values cannot be referenced in patterns -mir_build_indirect_structural_match = - to use a constant of type `{$non_sm_ty}` in a pattern, `{$non_sm_ty}` must be annotated with `#[derive(PartialEq, Eq)]` +mir_build_non_exhaustive_omitted_pattern = some variants are not matched explicitly + .help = ensure that all variants are matched explicitly by adding the suggested match arms + .note = the matched value is of type `{$scrut_ty}` and the `non_exhaustive_omitted_patterns` attribute was found + +mir_build_non_exhaustive_patterns_type_not_empty = non-exhaustive patterns: type `{$ty}` is non-empty + .def_note = `{$peeled_ty}` defined here + .type_note = the matched value is of type `{$ty}` + .non_exhaustive_type_note = the matched value is of type `{$ty}`, which is marked as non-exhaustive + .reference_note = references are always considered inhabited + .suggestion = ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown + .help = ensure that all possible cases are being handled by adding a match arm with a wildcard pattern mir_build_nontrivial_structural_match = to use a constant of type `{$non_sm_ty}` in a pattern, the constant's initializer must be trivial or `{$non_sm_ty}` must be annotated with `#[derive(PartialEq, Eq)]` -mir_build_type_not_structural_tip = the traits must be derived, manual `impl`s are not sufficient - -mir_build_type_not_structural_more_info = see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details - mir_build_overlapping_range_endpoints = multiple patterns overlap on their endpoints .range = ... with this range .note = you likely meant to write mutually exclusive ranges -mir_build_non_exhaustive_omitted_pattern = some variants are not matched explicitly - .help = ensure that all variants are matched explicitly by adding the suggested match arms - .note = the matched value is of type `{$scrut_ty}` and the `non_exhaustive_omitted_patterns` attribute was found - -mir_build_uncovered = {$count -> - [1] pattern `{$witness_1}` - [2] patterns `{$witness_1}` and `{$witness_2}` - [3] patterns `{$witness_1}`, `{$witness_2}` and `{$witness_3}` - *[other] patterns `{$witness_1}`, `{$witness_2}`, `{$witness_3}` and {$remainder} more - } not covered - -mir_build_privately_uninhabited = pattern `{$witness_1}` is currently uninhabited, but this variant contains private fields which may become inhabited in the future - mir_build_pattern_not_covered = refutable pattern in {$origin} .pattern_ty = the matched value is of type `{$pattern_ty}` -mir_build_inform_irrefutable = `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant +mir_build_pointer_pattern = function pointers and unsized pointers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. -mir_build_more_information = for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html +mir_build_privately_uninhabited = pattern `{$witness_1}` is currently uninhabited, but this variant contains private fields which may become inhabited in the future -mir_build_adt_defined_here = `{$ty}` defined here +mir_build_rustc_box_attribute_error = `#[rustc_box]` attribute used incorrectly + .attributes = no other attributes may be applied + .not_box = `#[rustc_box]` may only be applied to a `Box::new()` call + .missing_box = `#[rustc_box]` requires the `owned_box` lang item -mir_build_variant_defined_here = not covered +mir_build_static_in_pattern = statics cannot be referenced in patterns -mir_build_interpreted_as_const = introduce a variable instead +mir_build_suggest_attempted_int_lit = alternatively, you could prepend the pattern with an underscore to define a new named variable; identifiers cannot begin with digits -mir_build_confused = missing patterns are not covered because `{$variable}` is interpreted as a constant pattern, not a new variable mir_build_suggest_if_let = you might want to use `if let` to ignore the {$count -> [one] variant that isn't @@ -367,10 +260,117 @@ mir_build_suggest_let_else = you might want to use `let else` to handle the {$co *[other] variants that aren't } matched -mir_build_suggest_attempted_int_lit = alternatively, you could prepend the pattern with an underscore to define a new named variable; identifiers cannot begin with digits +mir_build_trailing_irrefutable_let_patterns = trailing irrefutable {$count -> + [one] pattern + *[other] patterns + } in let chain + .note = {$count -> + [one] this pattern + *[other] these patterns + } will always match + .help = consider moving {$count -> + [one] it + *[other] them + } into the body +mir_build_type_not_structural = + to use a constant of type `{$non_sm_ty}` in a pattern, `{$non_sm_ty}` must be annotated with `#[derive(PartialEq, Eq)]` -mir_build_rustc_box_attribute_error = `#[rustc_box]` attribute used incorrectly - .attributes = no other attributes may be applied - .not_box = `#[rustc_box]` may only be applied to a `Box::new()` call - .missing_box = `#[rustc_box]` requires the `owned_box` lang item +mir_build_type_not_structural_more_info = see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details + +mir_build_type_not_structural_tip = the traits must be derived, manual `impl`s are not sufficient + +mir_build_unconditional_recursion = function cannot return without recursing + .label = cannot return without recursing + .help = a `loop` may express intention better if this is on purpose + +mir_build_unconditional_recursion_call_site_label = recursive call site + +mir_build_uncovered = {$count -> + [1] pattern `{$witness_1}` + [2] patterns `{$witness_1}` and `{$witness_2}` + [3] patterns `{$witness_1}`, `{$witness_2}` and `{$witness_3}` + *[other] patterns `{$witness_1}`, `{$witness_2}`, `{$witness_3}` and {$remainder} more + } not covered + +mir_build_union_field_requires_unsafe = + access to union field is unsafe and requires unsafe block + .note = the field may not be properly initialized: using uninitialized data will cause undefined behavior + .label = access to union field + +mir_build_union_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed = + access to union field is unsafe and requires unsafe function or block + .note = the field may not be properly initialized: using uninitialized data will cause undefined behavior + .label = access to union field + +mir_build_union_pattern = cannot use unions in constant patterns + +mir_build_unreachable_pattern = unreachable pattern + .label = unreachable pattern + .catchall_label = matches any value + +mir_build_unsafe_op_in_unsafe_fn_borrow_of_layout_constrained_field_requires_unsafe = + borrow of layout constrained field with interior mutability is unsafe and requires unsafe block (error E0133) + .note = references to fields of layout constrained fields lose the constraints. Coupled with interior mutability, the field can be changed to invalid values + .label = borrow of layout constrained field with interior mutability + +mir_build_unsafe_op_in_unsafe_fn_call_to_fn_with_requires_unsafe = + call to function `{$function}` with `#[target_feature]` is unsafe and requires unsafe block (error E0133) + .note = can only be called if the required target features are available + .label = call to function with `#[target_feature]` + +mir_build_unsafe_op_in_unsafe_fn_call_to_unsafe_fn_requires_unsafe = + call to unsafe function `{$function}` is unsafe and requires unsafe block (error E0133) + .note = consult the function's documentation for information on how to avoid undefined behavior + .label = call to unsafe function + +mir_build_unsafe_op_in_unsafe_fn_call_to_unsafe_fn_requires_unsafe_nameless = + call to unsafe function is unsafe and requires unsafe block (error E0133) + .note = consult the function's documentation for information on how to avoid undefined behavior + .label = call to unsafe function + +mir_build_unsafe_op_in_unsafe_fn_deref_raw_pointer_requires_unsafe = + dereference of raw pointer is unsafe and requires unsafe block (error E0133) + .note = raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior + .label = dereference of raw pointer + +mir_build_unsafe_op_in_unsafe_fn_extern_static_requires_unsafe = + use of extern static is unsafe and requires unsafe block (error E0133) + .note = extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior + .label = use of extern static + +mir_build_unsafe_op_in_unsafe_fn_initializing_type_with_requires_unsafe = + initializing type with `rustc_layout_scalar_valid_range` attr is unsafe and requires unsafe + block (error E0133) + .note = initializing a layout restricted type's field with a value outside the valid range is undefined behavior + .label = initializing type with `rustc_layout_scalar_valid_range` attr + +mir_build_unsafe_op_in_unsafe_fn_inline_assembly_requires_unsafe = + use of inline assembly is unsafe and requires unsafe block (error E0133) + .note = inline assembly is entirely unchecked and can cause undefined behavior + .label = use of inline assembly + +mir_build_unsafe_op_in_unsafe_fn_mutable_static_requires_unsafe = + use of mutable static is unsafe and requires unsafe block (error E0133) + .note = mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior + .label = use of mutable static + +mir_build_unsafe_op_in_unsafe_fn_mutation_of_layout_constrained_field_requires_unsafe = + mutation of layout constrained field is unsafe and requires unsafe block (error E0133) + .note = mutating layout constrained fields cannot statically be checked for valid values + .label = mutation of layout constrained field + +mir_build_unsafe_op_in_unsafe_fn_union_field_requires_unsafe = + access to union field is unsafe and requires unsafe block (error E0133) + .note = the field may not be properly initialized: using uninitialized data will cause undefined behavior + .label = access to union field + +mir_build_unsized_pattern = cannot use unsized non-slice type `{$non_sm_ty}` in constant patterns + +mir_build_unused_unsafe = unnecessary `unsafe` block + .label = unnecessary `unsafe` block + +mir_build_unused_unsafe_enclosing_block_label = because it's nested under this `unsafe` block +mir_build_unused_unsafe_enclosing_fn_label = because it's nested under this `unsafe` fn + +mir_build_variant_defined_here = not covered diff --git a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs index b74422708ce..ebf830cb9c1 100644 --- a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs +++ b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs @@ -57,6 +57,7 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> { place: self.parse_place(args[0])?, target: self.parse_block(args[1])?, unwind: UnwindAction::Continue, + replace: false, }) }, @call("mir_call", args) => { diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs index bcab4c0d24b..3742d640e3b 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs @@ -725,6 +725,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { place: to_drop, target: success, unwind: UnwindAction::Continue, + replace: false, }, ); this.diverge_from(block); diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs index 7331f8ecaa9..7c0fbc6f81c 100644 --- a/compiler/rustc_mir_build/src/build/scope.rs +++ b/compiler/rustc_mir_build/src/build/scope.rs @@ -91,7 +91,7 @@ use rustc_middle::middle::region; use rustc_middle::mir::*; use rustc_middle::thir::{Expr, LintLevel}; -use rustc_span::{DesugaringKind, Span, DUMMY_SP}; +use rustc_span::{Span, DUMMY_SP}; #[derive(Debug)] pub struct Scopes<'tcx> { @@ -371,6 +371,7 @@ impl DropTree { // The caller will handle this if needed. unwind: UnwindAction::Terminate, place: drop_data.0.local.into(), + replace: false, }; cfg.terminate(block, drop_data.0.source_info, terminator); } @@ -1128,9 +1129,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { place: Place<'tcx>, value: Rvalue<'tcx>, ) -> BlockAnd<()> { - let span = self.tcx.with_stable_hashing_context(|hcx| { - span.mark_with_reason(None, DesugaringKind::Replace, self.tcx.sess.edition(), hcx) - }); let source_info = self.source_info(span); // create the new block for the assignment @@ -1148,6 +1146,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { place, target: assign, unwind: UnwindAction::Cleanup(assign_unwind), + replace: true, }, ); self.diverge_from(block); @@ -1261,6 +1260,7 @@ fn build_scope_drops<'tcx>( place: local.into(), target: next, unwind: UnwindAction::Continue, + replace: false, }, ); block = next; diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs index 463f639defe..d00fb754c64 100644 --- a/compiler/rustc_mir_build/src/thir/cx/mod.rs +++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs @@ -142,7 +142,7 @@ impl<'tcx> Cx<'tcx> { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind: ty::BrEnv, }; - let env_region = self.tcx.mk_re_late_bound(ty::INNERMOST, br); + let env_region = ty::Region::new_late_bound(self.tcx, ty::INNERMOST, br); let closure_env_ty = self.tcx.closure_env_ty(closure_def_id, closure_substs, env_region).unwrap(); let liberated_closure_env_ty = self.tcx.erase_late_bound_regions( 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 c11a4f7229d..1e51cb9aa96 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -491,8 +491,8 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { AdtDefinedHere { adt_def_span, ty, variants } }; - // Emit an extra note if the first uncovered witness is - // visibly uninhabited anywhere in the current crate. + // Emit an extra note if the first uncovered witness would be uninhabited + // if we disregard visibility. let witness_1_is_privately_uninhabited = if cx.tcx.features().exhaustive_patterns && let Some(witness_1) = witnesses.get(0) diff --git a/compiler/rustc_mir_dataflow/messages.ftl b/compiler/rustc_mir_dataflow/messages.ftl index 98854152508..5698367e42b 100644 --- a/compiler/rustc_mir_dataflow/messages.ftl +++ b/compiler/rustc_mir_dataflow/messages.ftl @@ -1,29 +1,29 @@ +mir_dataflow_duplicate_values_for = + duplicate values for `{$name}` + mir_dataflow_path_must_end_in_filename = path must end in a filename -mir_dataflow_unknown_formatter = - unknown formatter +mir_dataflow_peek_argument_not_a_local = + rustc_peek: argument was not a local -mir_dataflow_duplicate_values_for = - duplicate values for `{$name}` +mir_dataflow_peek_argument_untracked = + rustc_peek: argument untracked -mir_dataflow_requires_an_argument = - `{$name}` requires an argument +mir_dataflow_peek_bit_not_set = + rustc_peek: bit not set -mir_dataflow_stop_after_dataflow_ended_compilation = - stop_after_dataflow ended compilation +mir_dataflow_peek_must_be_not_temporary = + dataflow::sanity_check cannot feed a non-temp to rustc_peek mir_dataflow_peek_must_be_place_or_ref_place = rustc_peek: argument expression must be either `place` or `&place` -mir_dataflow_peek_must_be_not_temporary = - dataflow::sanity_check cannot feed a non-temp to rustc_peek - -mir_dataflow_peek_bit_not_set = - rustc_peek: bit not set +mir_dataflow_requires_an_argument = + `{$name}` requires an argument -mir_dataflow_peek_argument_not_a_local = - rustc_peek: argument was not a local +mir_dataflow_stop_after_dataflow_ended_compilation = + stop_after_dataflow ended compilation -mir_dataflow_peek_argument_untracked = - rustc_peek: argument untracked +mir_dataflow_unknown_formatter = + unknown formatter diff --git a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs index 18895072c3b..d615c83d621 100644 --- a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs +++ b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs @@ -237,6 +237,7 @@ where place: self.place, target: self.succ, unwind: self.unwind.into_action(), + replace: false, }, ); } @@ -719,6 +720,7 @@ where place: tcx.mk_place_deref(ptr), target: loop_block, unwind: unwind.into_action(), + replace: false, }, ); @@ -963,8 +965,12 @@ where } fn drop_block(&mut self, target: BasicBlock, unwind: Unwind) -> BasicBlock { - let block = - TerminatorKind::Drop { place: self.place, target, unwind: unwind.into_action() }; + let block = TerminatorKind::Drop { + place: self.place, + target, + unwind: unwind.into_action(), + replace: false, + }; self.new_block(unwind, block) } diff --git a/compiler/rustc_mir_dataflow/src/framework/direction.rs b/compiler/rustc_mir_dataflow/src/framework/direction.rs index c8fe1af6674..ba328e78040 100644 --- a/compiler/rustc_mir_dataflow/src/framework/direction.rs +++ b/compiler/rustc_mir_dataflow/src/framework/direction.rs @@ -479,7 +479,7 @@ impl Direction for Forward { Goto { target } => propagate(target, exit_state), Assert { target, unwind, expected: _, msg: _, cond: _ } - | Drop { target, unwind, place: _ } + | Drop { target, unwind, place: _, replace: _ } | FalseUnwind { real_target: target, unwind } => { if let UnwindAction::Cleanup(unwind) = unwind { propagate(unwind, exit_state); diff --git a/compiler/rustc_mir_dataflow/src/impls/liveness.rs b/compiler/rustc_mir_dataflow/src/impls/liveness.rs index aeca0073304..6ae6bdc17d5 100644 --- a/compiler/rustc_mir_dataflow/src/impls/liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/liveness.rs @@ -199,8 +199,7 @@ impl DefUse { | NonMutatingUseContext::Move | NonMutatingUseContext::PlaceMention | NonMutatingUseContext::ShallowBorrow - | NonMutatingUseContext::SharedBorrow - | NonMutatingUseContext::UniqueBorrow, + | NonMutatingUseContext::SharedBorrow, ) => Some(DefUse::Use), PlaceContext::MutatingUse(MutatingUseContext::Projection) diff --git a/compiler/rustc_mir_transform/messages.ftl b/compiler/rustc_mir_transform/messages.ftl index 8c85cb5f76d..b13429d121d 100644 --- a/compiler/rustc_mir_transform/messages.ftl +++ b/compiler/rustc_mir_transform/messages.ftl @@ -1,3 +1,8 @@ +mir_transform_arithmetic_overflow = this arithmetic operation will overflow +mir_transform_call_to_unsafe_label = call to unsafe function +mir_transform_call_to_unsafe_note = consult the function's documentation for information on how to avoid undefined behavior +mir_transform_const_defined_here = `const` item defined here + mir_transform_const_modify = attempting to modify a `const` item .note = each usage of a `const` item creates a new temporary; the original `const` item will not be modified @@ -6,50 +11,10 @@ mir_transform_const_mut_borrow = taking a mutable reference to a `const` item .note2 = the mutable reference will refer to this temporary, not the original `const` item .note3 = mutable reference created due to call to this method -mir_transform_const_defined_here = `const` item defined here - -mir_transform_unaligned_packed_ref = reference to packed field is unaligned - .note = packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses - .note_ub = creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) - .help = copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) - -mir_transform_unused_unsafe = unnecessary `unsafe` block - .label = because it's nested under this `unsafe` block - -mir_transform_requires_unsafe = {$details} is unsafe and requires unsafe {$op_in_unsafe_fn_allowed -> - [true] function or block - *[false] block - } - .not_inherited = items do not inherit unsafety from separate enclosing items - -mir_transform_call_to_unsafe_label = call to unsafe function -mir_transform_call_to_unsafe_note = consult the function's documentation for information on how to avoid undefined behavior -mir_transform_use_of_asm_label = use of inline assembly -mir_transform_use_of_asm_note = inline assembly is entirely unchecked and can cause undefined behavior -mir_transform_initializing_valid_range_label = initializing type with `rustc_layout_scalar_valid_range` attr -mir_transform_initializing_valid_range_note = initializing a layout restricted type's field with a value outside the valid range is undefined behavior mir_transform_const_ptr2int_label = cast of pointer to int mir_transform_const_ptr2int_note = casting pointers to integers in constants -mir_transform_use_of_static_mut_label = use of mutable static -mir_transform_use_of_static_mut_note = mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior -mir_transform_use_of_extern_static_label = use of extern static -mir_transform_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 mir_transform_deref_ptr_label = dereference of raw pointer mir_transform_deref_ptr_note = raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior -mir_transform_union_access_label = access to union field -mir_transform_union_access_note = the field may not be properly initialized: using uninitialized data will cause undefined behavior -mir_transform_mutation_layout_constrained_label = mutation of layout constrained field -mir_transform_mutation_layout_constrained_note = mutating layout constrained fields cannot statically be checked for valid values -mir_transform_mutation_layout_constrained_borrow_label = borrow of layout constrained field with interior mutability -mir_transform_mutation_layout_constrained_borrow_note = references to fields of layout constrained fields lose the constraints. Coupled with interior mutability, the field can be changed to invalid values -mir_transform_target_feature_call_label = call to function with `#[target_feature]` -mir_transform_target_feature_call_note = can only be called if the required target features are available - -mir_transform_unsafe_op_in_unsafe_fn = {$details} is unsafe and requires unsafe block (error E0133) - -mir_transform_arithmetic_overflow = this arithmetic operation will overflow -mir_transform_operation_will_panic = this operation will panic at runtime - mir_transform_ffi_unwind_call = call to {$foreign -> [true] foreign function *[false] function pointer @@ -58,9 +23,45 @@ mir_transform_ffi_unwind_call = call to {$foreign -> mir_transform_fn_item_ref = taking a reference to a function item does not give a function pointer .suggestion = cast `{$ident}` to obtain a function pointer +mir_transform_initializing_valid_range_label = initializing type with `rustc_layout_scalar_valid_range` attr +mir_transform_initializing_valid_range_note = initializing a layout restricted type's field with a value outside the valid range is undefined behavior mir_transform_must_not_suspend = {$pre}`{$def_path}`{$post} held across a suspend point, but should not be .label = the value is held across this suspend point .note = {$reason} .help = consider using a block (`{"{ ... }"}`) to shrink the value's scope, ending before the suspend point +mir_transform_mutation_layout_constrained_borrow_label = borrow of layout constrained field with interior mutability +mir_transform_mutation_layout_constrained_borrow_note = references to fields of layout constrained fields lose the constraints. Coupled with interior mutability, the field can be changed to invalid values +mir_transform_mutation_layout_constrained_label = mutation of layout constrained field +mir_transform_mutation_layout_constrained_note = mutating layout constrained fields cannot statically be checked for valid values +mir_transform_operation_will_panic = this operation will panic at runtime + +mir_transform_requires_unsafe = {$details} is unsafe and requires unsafe {$op_in_unsafe_fn_allowed -> + [true] function or block + *[false] block + } + .not_inherited = items do not inherit unsafety from separate enclosing items + mir_transform_simd_shuffle_last_const = last argument of `simd_shuffle` is required to be a `const` item + +mir_transform_target_feature_call_label = call to function with `#[target_feature]` +mir_transform_target_feature_call_note = can only be called if the required target features are available + +mir_transform_unaligned_packed_ref = reference to packed field is unaligned + .note = packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + .note_ub = creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) + .help = copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) + +mir_transform_union_access_label = access to union field +mir_transform_union_access_note = the field may not be properly initialized: using uninitialized data will cause undefined behavior +mir_transform_unsafe_op_in_unsafe_fn = {$details} is unsafe and requires unsafe block (error E0133) + +mir_transform_unused_unsafe = unnecessary `unsafe` block + .label = because it's nested under this `unsafe` block + +mir_transform_use_of_asm_label = use of inline assembly +mir_transform_use_of_asm_note = inline assembly is entirely unchecked and can cause undefined behavior +mir_transform_use_of_extern_static_label = use of extern static +mir_transform_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 +mir_transform_use_of_static_mut_label = use of mutable static +mir_transform_use_of_static_mut_note = mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior diff --git a/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs b/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs index b29ffcc70f9..ef2a0c790e9 100644 --- a/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs +++ b/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs @@ -80,7 +80,7 @@ fn add_move_for_packed_drop<'tcx>( is_cleanup: bool, ) { debug!("add_move_for_packed_drop({:?} @ {:?})", terminator, loc); - let TerminatorKind::Drop { ref place, target, unwind } = terminator.kind else { + let TerminatorKind::Drop { ref place, target, unwind, replace } = terminator.kind else { unreachable!(); }; @@ -98,6 +98,11 @@ fn add_move_for_packed_drop<'tcx>( patch.add_assign(loc, Place::from(temp), Rvalue::Use(Operand::Move(*place))); patch.patch_terminator( loc.block, - TerminatorKind::Drop { place: Place::from(temp), target: storage_dead_block, unwind }, + TerminatorKind::Drop { + place: Place::from(temp), + target: storage_dead_block, + unwind, + replace, + }, ); } diff --git a/compiler/rustc_mir_transform/src/check_alignment.rs b/compiler/rustc_mir_transform/src/check_alignment.rs index d60184e0ebe..1fe8ea07892 100644 --- a/compiler/rustc_mir_transform/src/check_alignment.rs +++ b/compiler/rustc_mir_transform/src/check_alignment.rs @@ -75,6 +75,14 @@ struct PointerFinder<'tcx, 'a> { } impl<'tcx, 'a> Visitor<'tcx> for PointerFinder<'tcx, 'a> { + fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { + if let Rvalue::AddressOf(..) = rvalue { + // Ignore dereferences inside of an AddressOf + return; + } + self.super_rvalue(rvalue, location); + } + fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, _location: Location) { if let PlaceContext::NonUse(_) = context { return; diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs index a5d18fff89b..1ba1951afde 100644 --- a/compiler/rustc_mir_transform/src/const_prop.rs +++ b/compiler/rustc_mir_transform/src/const_prop.rs @@ -772,7 +772,6 @@ impl<'tcx> Visitor<'tcx> for CanConstProp { // mutation. | NonMutatingUse(NonMutatingUseContext::SharedBorrow) | NonMutatingUse(NonMutatingUseContext::ShallowBorrow) - | NonMutatingUse(NonMutatingUseContext::UniqueBorrow) | NonMutatingUse(NonMutatingUseContext::AddressOf) | MutatingUse(MutatingUseContext::Borrow) | MutatingUse(MutatingUseContext::AddressOf) => { diff --git a/compiler/rustc_mir_transform/src/copy_prop.rs b/compiler/rustc_mir_transform/src/copy_prop.rs index 319f3a79705..3df459dfa79 100644 --- a/compiler/rustc_mir_transform/src/copy_prop.rs +++ b/compiler/rustc_mir_transform/src/copy_prop.rs @@ -130,7 +130,6 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> { PlaceContext::NonMutatingUse( NonMutatingUseContext::SharedBorrow | NonMutatingUseContext::ShallowBorrow - | NonMutatingUseContext::UniqueBorrow | NonMutatingUseContext::AddressOf, ) => true, // For debuginfo, merging locals is ok. diff --git a/compiler/rustc_mir_transform/src/elaborate_drops.rs b/compiler/rustc_mir_transform/src/elaborate_drops.rs index 98e7a519c20..fda0e1023f7 100644 --- a/compiler/rustc_mir_transform/src/elaborate_drops.rs +++ b/compiler/rustc_mir_transform/src/elaborate_drops.rs @@ -14,7 +14,7 @@ use rustc_mir_dataflow::un_derefer::UnDerefer; use rustc_mir_dataflow::MoveDataParamEnv; use rustc_mir_dataflow::{on_all_children_bits, on_all_drop_children_bits}; use rustc_mir_dataflow::{Analysis, ResultsCursor}; -use rustc_span::{DesugaringKind, Span}; +use rustc_span::Span; use rustc_target::abi::{FieldIdx, VariantIdx}; use std::fmt; @@ -401,7 +401,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { let terminator = data.terminator(); match terminator.kind { - TerminatorKind::Drop { mut place, target, unwind } => { + TerminatorKind::Drop { mut place, target, unwind, replace } => { if let Some(new_place) = self.un_derefer.derefer(place.as_ref(), self.body) { place = new_place; } @@ -434,10 +434,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { ) } LookupResult::Parent(..) => { - if !matches!( - terminator.source_info.span.desugaring_kind(), - Some(DesugaringKind::Replace), - ) { + if !replace { self.tcx.sess.delay_span_bug( terminator.source_info.span, format!("drop of untracked value {:?}", bb), diff --git a/compiler/rustc_mir_transform/src/function_item_references.rs b/compiler/rustc_mir_transform/src/function_item_references.rs index 5989dbebf2d..b1c9c4acc40 100644 --- a/compiler/rustc_mir_transform/src/function_item_references.rs +++ b/compiler/rustc_mir_transform/src/function_item_references.rs @@ -83,7 +83,7 @@ impl<'tcx> FunctionItemRefChecker<'_, 'tcx> { // If the inner type matches the type bound by `Pointer` if inner_ty == bound_ty { // Do a substitution using the parameters from the callsite - let subst_ty = EarlyBinder(inner_ty).subst(self.tcx, substs_ref); + let subst_ty = EarlyBinder::bind(inner_ty).subst(self.tcx, substs_ref); if let Some((fn_id, fn_substs)) = FunctionItemRefChecker::is_fn_ref(subst_ty) { diff --git a/compiler/rustc_mir_transform/src/generator.rs b/compiler/rustc_mir_transform/src/generator.rs index 891e446942e..89567ed0ab8 100644 --- a/compiler/rustc_mir_transform/src/generator.rs +++ b/compiler/rustc_mir_transform/src/generator.rs @@ -1045,7 +1045,10 @@ fn elaborate_generator_drops<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { for (block, block_data) in body.basic_blocks.iter_enumerated() { let (target, unwind, source_info) = match block_data.terminator() { - Terminator { source_info, kind: TerminatorKind::Drop { place, target, unwind } } => { + Terminator { + source_info, + kind: TerminatorKind::Drop { place, target, unwind, replace: _ }, + } => { if let Some(local) = place.as_local() { if local == SELF_ARG { (target, unwind, source_info) @@ -1304,6 +1307,7 @@ fn insert_clean_drop(body: &mut Body<'_>) -> BasicBlock { place: Place::from(SELF_ARG), target: return_block, unwind: UnwindAction::Continue, + replace: false, }; let source_info = SourceInfo::outermost(body.span); diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index 1748b1bf4a0..55b9f084c39 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -192,7 +192,7 @@ impl<'tcx> Inliner<'tcx> { let Ok(callee_body) = callsite.callee.try_subst_mir_and_normalize_erasing_regions( self.tcx, self.param_env, - ty::EarlyBinder(callee_body.clone()), + ty::EarlyBinder::bind(callee_body.clone()), ) else { return Err("failed to normalize callee body"); }; @@ -449,16 +449,16 @@ impl<'tcx> Inliner<'tcx> { checker.visit_basic_block_data(bb, blk); let term = blk.terminator(); - if let TerminatorKind::Drop { ref place, target, unwind } = term.kind { + if let TerminatorKind::Drop { ref place, target, unwind, replace: _ } = term.kind { work_list.push(target); // If the place doesn't actually need dropping, treat it like a regular goto. let ty = callsite .callee - .subst_mir(self.tcx, ty::EarlyBinder(&place.ty(callee_body, tcx).ty)); + .subst_mir(self.tcx, ty::EarlyBinder::bind(&place.ty(callee_body, tcx).ty)); if ty.needs_drop(tcx, self.param_env) && let UnwindAction::Cleanup(unwind) = unwind { - work_list.push(unwind); - } + work_list.push(unwind); + } } else if callee_attrs.instruction_set != self.codegen_fn_attrs.instruction_set && matches!(term.kind, TerminatorKind::InlineAsm { .. }) { @@ -790,7 +790,7 @@ impl<'tcx> Visitor<'tcx> for CostChecker<'_, 'tcx> { // If the place doesn't actually need dropping, treat it like a regular goto. let ty = self .instance - .subst_mir(tcx, ty::EarlyBinder(&place.ty(self.callee_body, tcx).ty)); + .subst_mir(tcx, ty::EarlyBinder::bind(&place.ty(self.callee_body, tcx).ty)); if ty.needs_drop(tcx, self.param_env) { self.cost += CALL_PENALTY; if let UnwindAction::Cleanup(_) = unwind { @@ -801,7 +801,7 @@ impl<'tcx> Visitor<'tcx> for CostChecker<'_, 'tcx> { } } TerminatorKind::Call { func: Operand::Constant(ref f), unwind, .. } => { - let fn_ty = self.instance.subst_mir(tcx, ty::EarlyBinder(&f.literal.ty())); + let fn_ty = self.instance.subst_mir(tcx, ty::EarlyBinder::bind(&f.literal.ty())); self.cost += if let ty::FnDef(def_id, _) = *fn_ty.kind() && tcx.is_intrinsic(def_id) { // Don't give intrinsics the extra penalty for calls INSTR_COST diff --git a/compiler/rustc_mir_transform/src/inline/cycle.rs b/compiler/rustc_mir_transform/src/inline/cycle.rs index 1ccf06f6153..8a10445f837 100644 --- a/compiler/rustc_mir_transform/src/inline/cycle.rs +++ b/compiler/rustc_mir_transform/src/inline/cycle.rs @@ -47,7 +47,7 @@ pub(crate) fn mir_callgraph_reachable<'tcx>( let Ok(substs) = caller.try_subst_mir_and_normalize_erasing_regions( tcx, param_env, - ty::EarlyBinder(substs), + ty::EarlyBinder::bind(substs), ) else { trace!(?caller, ?param_env, ?substs, "cannot normalize, skipping"); continue; diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 65864dc016f..54c138b6fbd 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -3,6 +3,7 @@ #![deny(rustc::diagnostic_outside_of_impl)] #![feature(box_patterns)] #![feature(drain_filter)] +#![feature(is_sorted)] #![feature(let_chains)] #![feature(map_try_insert)] #![feature(min_specialization)] @@ -84,6 +85,7 @@ mod match_branches; mod multiple_return_terminators; mod normalize_array_len; mod nrvo; +mod prettify; mod ref_prop; mod remove_noop_landing_pads; mod remove_storage_markers; @@ -581,6 +583,9 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { &large_enums::EnumSizeOpt { discrepancy: 128 }, // Some cleanup necessary at least for LLVM and potentially other codegen backends. &add_call_guards::CriticalCallEdges, + // Cleanup for human readability, off by default. + &prettify::ReorderBasicBlocks, + &prettify::ReorderLocals, // Dump the end result for testing and debugging purposes. &dump_mir::Marker("PreCodegen"), ], diff --git a/compiler/rustc_mir_transform/src/match_branches.rs b/compiler/rustc_mir_transform/src/match_branches.rs index 59942dc76f9..6eb48498274 100644 --- a/compiler/rustc_mir_transform/src/match_branches.rs +++ b/compiler/rustc_mir_transform/src/match_branches.rs @@ -41,7 +41,7 @@ pub struct MatchBranchSimplification; impl<'tcx> MirPass<'tcx> for MatchBranchSimplification { fn is_enabled(&self, sess: &rustc_session::Session) -> bool { - sess.mir_opt_level() >= 3 + sess.mir_opt_level() >= 1 } fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { @@ -62,7 +62,12 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification { .. } if targets.iter().len() == 1 => { let (value, target) = targets.iter().next().unwrap(); - if target == targets.otherwise() { + // We require that this block and the two possible target blocks all be + // distinct. + if target == targets.otherwise() + || bb_idx == target + || bb_idx == targets.otherwise() + { continue; } (discr, value, target, targets.otherwise()) diff --git a/compiler/rustc_mir_transform/src/prettify.rs b/compiler/rustc_mir_transform/src/prettify.rs new file mode 100644 index 00000000000..6f46974ea00 --- /dev/null +++ b/compiler/rustc_mir_transform/src/prettify.rs @@ -0,0 +1,150 @@ +//! These two passes provide no value to the compiler, so are off at every level. +//! +//! However, they can be enabled on the command line +//! (`-Zmir-enable-passes=+ReorderBasicBlocks,+ReorderLocals`) +//! to make the MIR easier to read for humans. + +use crate::MirPass; +use rustc_index::{bit_set::BitSet, IndexSlice, IndexVec}; +use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor}; +use rustc_middle::mir::*; +use rustc_middle::ty::TyCtxt; +use rustc_session::Session; + +/// Rearranges the basic blocks into a *reverse post-order*. +/// +/// Thus after this pass, all the successors of a block are later than it in the +/// `IndexVec`, unless that successor is a back-edge (such as from a loop). +pub struct ReorderBasicBlocks; + +impl<'tcx> MirPass<'tcx> for ReorderBasicBlocks { + fn is_enabled(&self, _session: &Session) -> bool { + false + } + + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + let rpo: IndexVec<BasicBlock, BasicBlock> = + body.basic_blocks.postorder().iter().copied().rev().collect(); + if rpo.iter().is_sorted() { + return; + } + + let mut updater = BasicBlockUpdater { map: rpo.invert_bijective_mapping(), tcx }; + debug_assert_eq!(updater.map[START_BLOCK], START_BLOCK); + updater.visit_body(body); + + permute(body.basic_blocks.as_mut(), &updater.map); + } +} + +/// Rearranges the locals into *use* order. +/// +/// Thus after this pass, a local with a smaller [`Location`] where it was first +/// assigned or referenced will have a smaller number. +/// +/// (Does not reorder arguments nor the [`RETURN_PLACE`].) +pub struct ReorderLocals; + +impl<'tcx> MirPass<'tcx> for ReorderLocals { + fn is_enabled(&self, _session: &Session) -> bool { + false + } + + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + let mut finder = + LocalFinder { map: IndexVec::new(), seen: BitSet::new_empty(body.local_decls.len()) }; + + // We can't reorder the return place or the arguments + for local in (0..=body.arg_count).map(Local::from_usize) { + finder.track(local); + } + + for (bb, bbd) in body.basic_blocks.iter_enumerated() { + finder.visit_basic_block_data(bb, bbd); + } + + // track everything in case there are some locals that we never saw, + // such as in non-block things like debug info or in non-uses. + for local in body.local_decls.indices() { + finder.track(local); + } + + if finder.map.iter().is_sorted() { + return; + } + + let mut updater = LocalUpdater { map: finder.map.invert_bijective_mapping(), tcx }; + + for local in (0..=body.arg_count).map(Local::from_usize) { + debug_assert_eq!(updater.map[local], local); + } + + updater.visit_body_preserves_cfg(body); + + permute(&mut body.local_decls, &updater.map); + } +} + +fn permute<I: rustc_index::Idx + Ord, T>(data: &mut IndexVec<I, T>, map: &IndexSlice<I, I>) { + // FIXME: It would be nice to have a less-awkward way to apply permutations, + // but I don't know one that exists. `sort_by_cached_key` has logic for it + // internally, but not in a way that we're allowed to use here. + let mut enumerated: Vec<_> = std::mem::take(data).into_iter_enumerated().collect(); + enumerated.sort_by_key(|p| map[p.0]); + *data = enumerated.into_iter().map(|p| p.1).collect(); +} + +struct BasicBlockUpdater<'tcx> { + map: IndexVec<BasicBlock, BasicBlock>, + tcx: TyCtxt<'tcx>, +} + +impl<'tcx> MutVisitor<'tcx> for BasicBlockUpdater<'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } + + fn visit_terminator(&mut self, terminator: &mut Terminator<'tcx>, _location: Location) { + for succ in terminator.successors_mut() { + *succ = self.map[*succ]; + } + } +} + +struct LocalFinder { + map: IndexVec<Local, Local>, + seen: BitSet<Local>, +} + +impl LocalFinder { + fn track(&mut self, l: Local) { + if self.seen.insert(l) { + self.map.push(l); + } + } +} + +impl<'tcx> Visitor<'tcx> for LocalFinder { + fn visit_local(&mut self, l: Local, context: PlaceContext, _location: Location) { + // Exclude non-uses to keep `StorageLive` from controlling where we put + // a `Local`, since it might not actually be assigned until much later. + if context.is_use() { + self.track(l); + } + } +} + +struct LocalUpdater<'tcx> { + pub map: IndexVec<Local, Local>, + pub tcx: TyCtxt<'tcx>, +} + +impl<'tcx> MutVisitor<'tcx> for LocalUpdater<'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } + + fn visit_local(&mut self, l: &mut Local, _: PlaceContext, _: Location) { + *l = self.map[*l]; + } +} diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index 7c47d8814db..ae726dea944 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -69,7 +69,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<' // of this function. Is this intentional? if let Some(ty::Generator(gen_def_id, substs, _)) = ty.map(Ty::kind) { let body = tcx.optimized_mir(*gen_def_id).generator_drop().unwrap(); - let body = EarlyBinder(body.clone()).subst(tcx, substs); + let body = EarlyBinder::bind(body.clone()).subst(tcx, substs); debug!("make_shim({:?}) = {:?}", instance, body); return body; } @@ -544,6 +544,7 @@ impl<'tcx> CloneShimBuilder<'tcx> { place: dest_field, target: unwind, unwind: UnwindAction::Terminate, + replace: false, }, true, ); @@ -643,8 +644,11 @@ fn build_call_shim<'tcx>( let sig = sig.map_bound(|sig| tcx.erase_late_bound_regions(sig)); assert_eq!(sig_substs.is_some(), !instance.has_polymorphic_mir_body()); - let mut sig = - if let Some(sig_substs) = sig_substs { sig.subst(tcx, &sig_substs) } else { sig.0 }; + let mut sig = if let Some(sig_substs) = sig_substs { + sig.subst(tcx, &sig_substs) + } else { + sig.skip_binder() + }; if let CallKind::Indirect(fnty) = call_kind { // `sig` determines our local decls, and thus the callee type in the `Call` terminator. This @@ -800,6 +804,7 @@ fn build_call_shim<'tcx>( place: rcvr_place(), target: BasicBlock::new(2), unwind: UnwindAction::Continue, + replace: false, }, false, ); @@ -815,6 +820,7 @@ fn build_call_shim<'tcx>( place: rcvr_place(), target: BasicBlock::new(4), unwind: UnwindAction::Terminate, + replace: false, }, true, ); diff --git a/compiler/rustc_mir_transform/src/ssa.rs b/compiler/rustc_mir_transform/src/ssa.rs index e8e4246b797..7a0d3a025f3 100644 --- a/compiler/rustc_mir_transform/src/ssa.rs +++ b/compiler/rustc_mir_transform/src/ssa.rs @@ -216,7 +216,6 @@ impl<'tcx> Visitor<'tcx> for SsaVisitor<'_> { PlaceContext::NonMutatingUse( NonMutatingUseContext::SharedBorrow | NonMutatingUseContext::ShallowBorrow - | NonMutatingUseContext::UniqueBorrow | NonMutatingUseContext::AddressOf, ) | PlaceContext::MutatingUse(_) => { diff --git a/compiler/rustc_monomorphize/messages.ftl b/compiler/rustc_monomorphize/messages.ftl index 6cea6a603f3..fdd47e6f79b 100644 --- a/compiler/rustc_monomorphize/messages.ftl +++ b/compiler/rustc_monomorphize/messages.ftl @@ -1,32 +1,32 @@ -monomorphize_recursion_limit = - reached the recursion limit while instantiating `{$shrunk}` - .note = `{$def_path_str}` defined here - -monomorphize_written_to_path = the full type name has been written to '{$path}' - -monomorphize_type_length_limit = reached the type-length limit while instantiating `{$shrunk}` - monomorphize_consider_type_length_limit = consider adding a `#![type_length_limit="{$type_length}"]` attribute to your crate -monomorphize_fatal_error = {$error_message} - -monomorphize_unknown_partition_strategy = unknown partitioning strategy +monomorphize_couldnt_dump_mono_stats = + unexpected error occurred while dumping monomorphization stats: {$error} -monomorphize_symbol_already_defined = symbol `{$symbol}` is already defined +monomorphize_encountered_error_while_instantiating = + the above error was encountered while instantiating `{$formatted_item}` -monomorphize_unused_generic_params = item has unused generic parameters +monomorphize_fatal_error = {$error_message} monomorphize_large_assignments = moving {$size} bytes .label = value moved from here .note = The current maximum size is {$limit}, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]` -monomorphize_couldnt_dump_mono_stats = - unexpected error occurred while dumping monomorphization stats: {$error} +monomorphize_recursion_limit = + reached the recursion limit while instantiating `{$shrunk}` + .note = `{$def_path_str}` defined here -monomorphize_encountered_error_while_instantiating = - the above error was encountered while instantiating `{$formatted_item}` +monomorphize_symbol_already_defined = symbol `{$symbol}` is already defined + +monomorphize_type_length_limit = reached the type-length limit while instantiating `{$shrunk}` monomorphize_unknown_cgu_collection_mode = unknown codegen-item collection mode '{$mode}', falling back to 'lazy' mode + +monomorphize_unknown_partition_strategy = unknown partitioning strategy + +monomorphize_unused_generic_params = item has unused generic parameters + +monomorphize_written_to_path = the full type name has been written to '{$path}' diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 35b154b7b34..cefa64d27ac 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -677,7 +677,7 @@ impl<'a, 'tcx> MirNeighborCollector<'a, 'tcx> { self.instance.subst_mir_and_normalize_erasing_regions( self.tcx, ty::ParamEnv::reveal_all(), - ty::EarlyBinder(value), + ty::EarlyBinder::bind(value), ) } } diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs new file mode 100644 index 00000000000..be9c349c384 --- /dev/null +++ b/compiler/rustc_monomorphize/src/partitioning.rs @@ -0,0 +1,1182 @@ +//! Partitioning Codegen Units for Incremental Compilation +//! ====================================================== +//! +//! The task of this module is to take the complete set of monomorphizations of +//! a crate and produce a set of codegen units from it, where a codegen unit +//! is a named set of (mono-item, linkage) pairs. That is, this module +//! decides which monomorphization appears in which codegen units with which +//! linkage. The following paragraphs describe some of the background on the +//! partitioning scheme. +//! +//! The most important opportunity for saving on compilation time with +//! incremental compilation is to avoid re-codegenning and re-optimizing code. +//! Since the unit of codegen and optimization for LLVM is "modules" or, how +//! we call them "codegen units", the particulars of how much time can be saved +//! by incremental compilation are tightly linked to how the output program is +//! partitioned into these codegen units prior to passing it to LLVM -- +//! especially because we have to treat codegen units as opaque entities once +//! they are created: There is no way for us to incrementally update an existing +//! LLVM module and so we have to build any such module from scratch if it was +//! affected by some change in the source code. +//! +//! From that point of view it would make sense to maximize the number of +//! codegen units by, for example, putting each function into its own module. +//! That way only those modules would have to be re-compiled that were actually +//! affected by some change, minimizing the number of functions that could have +//! been re-used but just happened to be located in a module that is +//! re-compiled. +//! +//! However, since LLVM optimization does not work across module boundaries, +//! using such a highly granular partitioning would lead to very slow runtime +//! code since it would effectively prohibit inlining and other inter-procedure +//! optimizations. We want to avoid that as much as possible. +//! +//! Thus we end up with a trade-off: The bigger the codegen units, the better +//! LLVM's optimizer can do its work, but also the smaller the compilation time +//! reduction we get from incremental compilation. +//! +//! Ideally, we would create a partitioning such that there are few big codegen +//! units with few interdependencies between them. For now though, we use the +//! following heuristic to determine the partitioning: +//! +//! - There are two codegen units for every source-level module: +//! - One for "stable", that is non-generic, code +//! - One for more "volatile" code, i.e., monomorphized instances of functions +//! defined in that module +//! +//! In order to see why this heuristic makes sense, let's take a look at when a +//! codegen unit can get invalidated: +//! +//! 1. The most straightforward case is when the BODY of a function or global +//! changes. Then any codegen unit containing the code for that item has to be +//! re-compiled. Note that this includes all codegen units where the function +//! has been inlined. +//! +//! 2. The next case is when the SIGNATURE of a function or global changes. In +//! this case, all codegen units containing a REFERENCE to that item have to be +//! re-compiled. This is a superset of case 1. +//! +//! 3. The final and most subtle case is when a REFERENCE to a generic function +//! is added or removed somewhere. Even though the definition of the function +//! might be unchanged, a new REFERENCE might introduce a new monomorphized +//! instance of this function which has to be placed and compiled somewhere. +//! Conversely, when removing a REFERENCE, it might have been the last one with +//! that particular set of generic arguments and thus we have to remove it. +//! +//! From the above we see that just using one codegen unit per source-level +//! module is not such a good idea, since just adding a REFERENCE to some +//! generic item somewhere else would invalidate everything within the module +//! containing the generic item. The heuristic above reduces this detrimental +//! side-effect of references a little by at least not touching the non-generic +//! code of the module. +//! +//! A Note on Inlining +//! ------------------ +//! As briefly mentioned above, in order for LLVM to be able to inline a +//! function call, the body of the function has to be available in the LLVM +//! module where the call is made. This has a few consequences for partitioning: +//! +//! - The partitioning algorithm has to take care of placing functions into all +//! codegen units where they should be available for inlining. It also has to +//! decide on the correct linkage for these functions. +//! +//! - The partitioning algorithm has to know which functions are likely to get +//! inlined, so it can distribute function instantiations accordingly. Since +//! there is no way of knowing for sure which functions LLVM will decide to +//! inline in the end, we apply a heuristic here: Only functions marked with +//! `#[inline]` are considered for inlining by the partitioner. The current +//! implementation will not try to determine if a function is likely to be +//! inlined by looking at the functions definition. +//! +//! Note though that as a side-effect of creating a codegen units per +//! source-level module, functions from the same module will be available for +//! inlining, even when they are not marked `#[inline]`. + +use std::cmp; +use std::collections::hash_map::Entry; +use std::fs::{self, File}; +use std::io::{BufWriter, Write}; +use std::path::{Path, PathBuf}; + +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::sync; +use rustc_hir::def::DefKind; +use rustc_hir::def_id::{DefId, DefIdSet, LOCAL_CRATE}; +use rustc_hir::definitions::DefPathDataName; +use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; +use rustc_middle::middle::exported_symbols::{SymbolExportInfo, SymbolExportLevel}; +use rustc_middle::mir; +use rustc_middle::mir::mono::{ + CodegenUnit, CodegenUnitNameBuilder, InstantiationMode, Linkage, MonoItem, Visibility, +}; +use rustc_middle::query::Providers; +use rustc_middle::ty::print::{characteristic_def_id_of_type, with_no_trimmed_paths}; +use rustc_middle::ty::{self, visit::TypeVisitableExt, InstanceDef, TyCtxt}; +use rustc_session::config::{DumpMonoStatsFormat, SwitchWithOptPath}; +use rustc_span::symbol::Symbol; + +use crate::collector::InliningMap; +use crate::collector::{self, MonoItemCollectionMode}; +use crate::errors::{CouldntDumpMonoStats, SymbolAlreadyDefined, UnknownCguCollectionMode}; + +struct PartitioningCx<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + target_cgu_count: usize, + inlining_map: &'a InliningMap<'tcx>, +} + +struct PlacedRootMonoItems<'tcx> { + codegen_units: Vec<CodegenUnit<'tcx>>, + roots: FxHashSet<MonoItem<'tcx>>, + internalization_candidates: FxHashSet<MonoItem<'tcx>>, +} + +fn partition<'tcx, I>( + tcx: TyCtxt<'tcx>, + mono_items: &mut I, + max_cgu_count: usize, + inlining_map: &InliningMap<'tcx>, +) -> Vec<CodegenUnit<'tcx>> +where + I: Iterator<Item = MonoItem<'tcx>>, +{ + let _prof_timer = tcx.prof.generic_activity("cgu_partitioning"); + + let cx = &PartitioningCx { tcx, target_cgu_count: max_cgu_count, inlining_map }; + // In the first step, we place all regular monomorphizations into their + // respective 'home' codegen unit. Regular monomorphizations are all + // functions and statics defined in the local crate. + let PlacedRootMonoItems { mut codegen_units, roots, internalization_candidates } = { + let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_place_roots"); + place_root_mono_items(cx, mono_items) + }; + + for cgu in &mut codegen_units { + cgu.create_size_estimate(tcx); + } + + debug_dump(tcx, "INITIAL PARTITIONING", &codegen_units); + + // Merge until we have at most `max_cgu_count` codegen units. + // `merge_codegen_units` is responsible for updating the CGU size + // estimates. + { + let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_merge_cgus"); + merge_codegen_units(cx, &mut codegen_units); + debug_dump(tcx, "POST MERGING", &codegen_units); + } + + // In the next step, we use the inlining map to determine which additional + // monomorphizations have to go into each codegen unit. These additional + // monomorphizations can be drop-glue, functions from external crates, and + // local functions the definition of which is marked with `#[inline]`. + let mono_item_placements = { + let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_place_inline_items"); + place_inlined_mono_items(cx, &mut codegen_units, roots) + }; + + for cgu in &mut codegen_units { + cgu.create_size_estimate(tcx); + } + + debug_dump(tcx, "POST INLINING", &codegen_units); + + // Next we try to make as many symbols "internal" as possible, so LLVM has + // more freedom to optimize. + if !tcx.sess.link_dead_code() { + let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_internalize_symbols"); + internalize_symbols( + cx, + &mut codegen_units, + mono_item_placements, + internalization_candidates, + ); + } + + let instrument_dead_code = + tcx.sess.instrument_coverage() && !tcx.sess.instrument_coverage_except_unused_functions(); + + if instrument_dead_code { + assert!( + codegen_units.len() > 0, + "There must be at least one CGU that code coverage data can be generated in." + ); + + // Find the smallest CGU that has exported symbols and put the dead + // function stubs in that CGU. We look for exported symbols to increase + // the likelihood the linker won't throw away the dead functions. + // FIXME(#92165): In order to truly resolve this, we need to make sure + // the object file (CGU) containing the dead function stubs is included + // in the final binary. This will probably require forcing these + // function symbols to be included via `-u` or `/include` linker args. + let mut cgus: Vec<_> = codegen_units.iter_mut().collect(); + cgus.sort_by_key(|cgu| cgu.size_estimate()); + + let dead_code_cgu = + if let Some(cgu) = cgus.into_iter().rev().find(|cgu| { + cgu.items().iter().any(|(_, (linkage, _))| *linkage == Linkage::External) + }) { + cgu + } else { + // If there are no CGUs that have externally linked items, + // then we just pick the first CGU as a fallback. + &mut codegen_units[0] + }; + dead_code_cgu.make_code_coverage_dead_code_cgu(); + } + + // Finally, sort by codegen unit name, so that we get deterministic results. + codegen_units.sort_by(|a, b| a.name().as_str().cmp(b.name().as_str())); + + debug_dump(tcx, "FINAL", &codegen_units); + + codegen_units +} + +fn place_root_mono_items<'tcx, I>( + cx: &PartitioningCx<'_, 'tcx>, + mono_items: &mut I, +) -> PlacedRootMonoItems<'tcx> +where + I: Iterator<Item = MonoItem<'tcx>>, +{ + let mut roots = FxHashSet::default(); + let mut codegen_units = FxHashMap::default(); + let is_incremental_build = cx.tcx.sess.opts.incremental.is_some(); + let mut internalization_candidates = FxHashSet::default(); + + // Determine if monomorphizations instantiated in this crate will be made + // available to downstream crates. This depends on whether we are in + // share-generics mode and whether the current crate can even have + // downstream crates. + let export_generics = + cx.tcx.sess.opts.share_generics() && cx.tcx.local_crate_exports_generics(); + + let cgu_name_builder = &mut CodegenUnitNameBuilder::new(cx.tcx); + let cgu_name_cache = &mut FxHashMap::default(); + + for mono_item in mono_items { + match mono_item.instantiation_mode(cx.tcx) { + InstantiationMode::GloballyShared { .. } => {} + InstantiationMode::LocalCopy => continue, + } + + let characteristic_def_id = characteristic_def_id_of_mono_item(cx.tcx, mono_item); + let is_volatile = is_incremental_build && mono_item.is_generic_fn(); + + let codegen_unit_name = match characteristic_def_id { + Some(def_id) => compute_codegen_unit_name( + cx.tcx, + cgu_name_builder, + def_id, + is_volatile, + cgu_name_cache, + ), + None => fallback_cgu_name(cgu_name_builder), + }; + + let codegen_unit = codegen_units + .entry(codegen_unit_name) + .or_insert_with(|| CodegenUnit::new(codegen_unit_name)); + + let mut can_be_internalized = true; + let (linkage, visibility) = mono_item_linkage_and_visibility( + cx.tcx, + &mono_item, + &mut can_be_internalized, + export_generics, + ); + if visibility == Visibility::Hidden && can_be_internalized { + internalization_candidates.insert(mono_item); + } + + codegen_unit.items_mut().insert(mono_item, (linkage, visibility)); + roots.insert(mono_item); + } + + // Always ensure we have at least one CGU; otherwise, if we have a + // crate with just types (for example), we could wind up with no CGU. + if codegen_units.is_empty() { + let codegen_unit_name = fallback_cgu_name(cgu_name_builder); + codegen_units.insert(codegen_unit_name, CodegenUnit::new(codegen_unit_name)); + } + + let codegen_units = codegen_units.into_values().collect(); + PlacedRootMonoItems { codegen_units, roots, internalization_candidates } +} + +fn merge_codegen_units<'tcx>( + cx: &PartitioningCx<'_, 'tcx>, + codegen_units: &mut Vec<CodegenUnit<'tcx>>, +) { + assert!(cx.target_cgu_count >= 1); + + // Note that at this point in time the `codegen_units` here may not be + // in a deterministic order (but we know they're deterministically the + // same set). We want this merging to produce a deterministic ordering + // of codegen units from the input. + // + // Due to basically how we've implemented the merging below (merge the + // two smallest into each other) we're sure to start off with a + // deterministic order (sorted by name). This'll mean that if two cgus + // have the same size the stable sort below will keep everything nice + // and deterministic. + codegen_units.sort_by(|a, b| a.name().as_str().cmp(b.name().as_str())); + + // This map keeps track of what got merged into what. + let mut cgu_contents: FxHashMap<Symbol, Vec<Symbol>> = + codegen_units.iter().map(|cgu| (cgu.name(), vec![cgu.name()])).collect(); + + // Merge the two smallest codegen units until the target size is + // reached. + while codegen_units.len() > cx.target_cgu_count { + // Sort small cgus to the back + codegen_units.sort_by_cached_key(|cgu| cmp::Reverse(cgu.size_estimate())); + let mut smallest = codegen_units.pop().unwrap(); + let second_smallest = codegen_units.last_mut().unwrap(); + + // Move the mono-items from `smallest` to `second_smallest` + second_smallest.modify_size_estimate(smallest.size_estimate()); + for (k, v) in smallest.items_mut().drain() { + second_smallest.items_mut().insert(k, v); + } + + // Record that `second_smallest` now contains all the stuff that was + // in `smallest` before. + let mut consumed_cgu_names = cgu_contents.remove(&smallest.name()).unwrap(); + cgu_contents.get_mut(&second_smallest.name()).unwrap().append(&mut consumed_cgu_names); + + debug!( + "CodegenUnit {} merged into CodegenUnit {}", + smallest.name(), + second_smallest.name() + ); + } + + let cgu_name_builder = &mut CodegenUnitNameBuilder::new(cx.tcx); + + if cx.tcx.sess.opts.incremental.is_some() { + // If we are doing incremental compilation, we want CGU names to + // reflect the path of the source level module they correspond to. + // For CGUs that contain the code of multiple modules because of the + // merging done above, we use a concatenation of the names of all + // contained CGUs. + let new_cgu_names: FxHashMap<Symbol, String> = cgu_contents + .into_iter() + // This `filter` makes sure we only update the name of CGUs that + // were actually modified by merging. + .filter(|(_, cgu_contents)| cgu_contents.len() > 1) + .map(|(current_cgu_name, cgu_contents)| { + let mut cgu_contents: Vec<&str> = cgu_contents.iter().map(|s| s.as_str()).collect(); + + // Sort the names, so things are deterministic and easy to + // predict. We are sorting primitive `&str`s here so we can + // use unstable sort. + cgu_contents.sort_unstable(); + + (current_cgu_name, cgu_contents.join("--")) + }) + .collect(); + + for cgu in codegen_units.iter_mut() { + if let Some(new_cgu_name) = new_cgu_names.get(&cgu.name()) { + if cx.tcx.sess.opts.unstable_opts.human_readable_cgu_names { + cgu.set_name(Symbol::intern(&new_cgu_name)); + } else { + // If we don't require CGU names to be human-readable, + // we use a fixed length hash of the composite CGU name + // instead. + let new_cgu_name = CodegenUnit::mangle_name(&new_cgu_name); + cgu.set_name(Symbol::intern(&new_cgu_name)); + } + } + } + } else { + // If we are compiling non-incrementally we just generate simple CGU + // names containing an index. + for (index, cgu) in codegen_units.iter_mut().enumerate() { + let numbered_codegen_unit_name = + cgu_name_builder.build_cgu_name_no_mangle(LOCAL_CRATE, &["cgu"], Some(index)); + cgu.set_name(numbered_codegen_unit_name); + } + } +} + +/// For symbol internalization, we need to know whether a symbol/mono-item is +/// accessed from outside the codegen unit it is defined in. This type is used +/// to keep track of that. +#[derive(Clone, PartialEq, Eq, Debug)] +enum MonoItemPlacement { + SingleCgu { cgu_name: Symbol }, + MultipleCgus, +} + +fn place_inlined_mono_items<'tcx>( + cx: &PartitioningCx<'_, 'tcx>, + codegen_units: &mut [CodegenUnit<'tcx>], + roots: FxHashSet<MonoItem<'tcx>>, +) -> FxHashMap<MonoItem<'tcx>, MonoItemPlacement> { + let mut mono_item_placements = FxHashMap::default(); + + let single_codegen_unit = codegen_units.len() == 1; + + for old_codegen_unit in codegen_units.iter_mut() { + // Collect all items that need to be available in this codegen unit. + let mut reachable = FxHashSet::default(); + for root in old_codegen_unit.items().keys() { + follow_inlining(*root, cx.inlining_map, &mut reachable); + } + + let mut new_codegen_unit = CodegenUnit::new(old_codegen_unit.name()); + + // Add all monomorphizations that are not already there. + for mono_item in reachable { + if let Some(linkage) = old_codegen_unit.items().get(&mono_item) { + // This is a root, just copy it over. + new_codegen_unit.items_mut().insert(mono_item, *linkage); + } else { + if roots.contains(&mono_item) { + bug!( + "GloballyShared mono-item inlined into other CGU: \ + {:?}", + mono_item + ); + } + + // This is a CGU-private copy. + new_codegen_unit + .items_mut() + .insert(mono_item, (Linkage::Internal, Visibility::Default)); + } + + if !single_codegen_unit { + // If there is more than one codegen unit, we need to keep track + // in which codegen units each monomorphization is placed. + match mono_item_placements.entry(mono_item) { + Entry::Occupied(e) => { + let placement = e.into_mut(); + debug_assert!(match *placement { + MonoItemPlacement::SingleCgu { cgu_name } => { + cgu_name != new_codegen_unit.name() + } + MonoItemPlacement::MultipleCgus => true, + }); + *placement = MonoItemPlacement::MultipleCgus; + } + Entry::Vacant(e) => { + e.insert(MonoItemPlacement::SingleCgu { + cgu_name: new_codegen_unit.name(), + }); + } + } + } + } + + *old_codegen_unit = new_codegen_unit; + } + + return mono_item_placements; + + fn follow_inlining<'tcx>( + mono_item: MonoItem<'tcx>, + inlining_map: &InliningMap<'tcx>, + visited: &mut FxHashSet<MonoItem<'tcx>>, + ) { + if !visited.insert(mono_item) { + return; + } + + inlining_map.with_inlining_candidates(mono_item, |target| { + follow_inlining(target, inlining_map, visited); + }); + } +} + +fn internalize_symbols<'tcx>( + cx: &PartitioningCx<'_, 'tcx>, + codegen_units: &mut [CodegenUnit<'tcx>], + mono_item_placements: FxHashMap<MonoItem<'tcx>, MonoItemPlacement>, + internalization_candidates: FxHashSet<MonoItem<'tcx>>, +) { + if codegen_units.len() == 1 { + // Fast path for when there is only one codegen unit. In this case we + // can internalize all candidates, since there is nowhere else they + // could be accessed from. + for cgu in codegen_units { + for candidate in &internalization_candidates { + cgu.items_mut().insert(*candidate, (Linkage::Internal, Visibility::Default)); + } + } + + return; + } + + // Build a map from every monomorphization to all the monomorphizations that + // reference it. + let mut accessor_map: FxHashMap<MonoItem<'tcx>, Vec<MonoItem<'tcx>>> = Default::default(); + cx.inlining_map.iter_accesses(|accessor, accessees| { + for accessee in accessees { + accessor_map.entry(*accessee).or_default().push(accessor); + } + }); + + // For each internalization candidates in each codegen unit, check if it is + // accessed from outside its defining codegen unit. + for cgu in codegen_units { + let home_cgu = MonoItemPlacement::SingleCgu { cgu_name: cgu.name() }; + + for (accessee, linkage_and_visibility) in cgu.items_mut() { + if !internalization_candidates.contains(accessee) { + // This item is no candidate for internalizing, so skip it. + continue; + } + debug_assert_eq!(mono_item_placements[accessee], home_cgu); + + if let Some(accessors) = accessor_map.get(accessee) { + if accessors + .iter() + .filter_map(|accessor| { + // Some accessors might not have been + // instantiated. We can safely ignore those. + mono_item_placements.get(accessor) + }) + .any(|placement| *placement != home_cgu) + { + // Found an accessor from another CGU, so skip to the next + // item without marking this one as internal. + continue; + } + } + + // If we got here, we did not find any accesses from other CGUs, + // so it's fine to make this monomorphization internal. + *linkage_and_visibility = (Linkage::Internal, Visibility::Default); + } + } +} + +fn characteristic_def_id_of_mono_item<'tcx>( + tcx: TyCtxt<'tcx>, + mono_item: MonoItem<'tcx>, +) -> Option<DefId> { + match mono_item { + MonoItem::Fn(instance) => { + let def_id = match instance.def { + ty::InstanceDef::Item(def) => def, + ty::InstanceDef::VTableShim(..) + | ty::InstanceDef::ReifyShim(..) + | ty::InstanceDef::FnPtrShim(..) + | ty::InstanceDef::ClosureOnceShim { .. } + | ty::InstanceDef::Intrinsic(..) + | ty::InstanceDef::DropGlue(..) + | ty::InstanceDef::Virtual(..) + | ty::InstanceDef::CloneShim(..) + | ty::InstanceDef::ThreadLocalShim(..) + | ty::InstanceDef::FnPtrAddrShim(..) => return None, + }; + + // If this is a method, we want to put it into the same module as + // its self-type. If the self-type does not provide a characteristic + // DefId, we use the location of the impl after all. + + if tcx.trait_of_item(def_id).is_some() { + let self_ty = instance.substs.type_at(0); + // This is a default implementation of a trait method. + return characteristic_def_id_of_type(self_ty).or(Some(def_id)); + } + + if let Some(impl_def_id) = tcx.impl_of_method(def_id) { + if tcx.sess.opts.incremental.is_some() + && tcx.trait_id_of_impl(impl_def_id) == tcx.lang_items().drop_trait() + { + // Put `Drop::drop` into the same cgu as `drop_in_place` + // since `drop_in_place` is the only thing that can + // call it. + return None; + } + + // When polymorphization is enabled, methods which do not depend on their generic + // parameters, but the self-type of their impl block do will fail to normalize. + if !tcx.sess.opts.unstable_opts.polymorphize || !instance.has_param() { + // This is a method within an impl, find out what the self-type is: + let impl_self_ty = tcx.subst_and_normalize_erasing_regions( + instance.substs, + ty::ParamEnv::reveal_all(), + tcx.type_of(impl_def_id), + ); + if let Some(def_id) = characteristic_def_id_of_type(impl_self_ty) { + return Some(def_id); + } + } + } + + Some(def_id) + } + MonoItem::Static(def_id) => Some(def_id), + MonoItem::GlobalAsm(item_id) => Some(item_id.owner_id.to_def_id()), + } +} + +fn compute_codegen_unit_name( + tcx: TyCtxt<'_>, + name_builder: &mut CodegenUnitNameBuilder<'_>, + def_id: DefId, + volatile: bool, + cache: &mut CguNameCache, +) -> Symbol { + // Find the innermost module that is not nested within a function. + let mut current_def_id = def_id; + let mut cgu_def_id = None; + // Walk backwards from the item we want to find the module for. + loop { + if current_def_id.is_crate_root() { + if cgu_def_id.is_none() { + // If we have not found a module yet, take the crate root. + cgu_def_id = Some(def_id.krate.as_def_id()); + } + break; + } else if tcx.def_kind(current_def_id) == DefKind::Mod { + if cgu_def_id.is_none() { + cgu_def_id = Some(current_def_id); + } + } else { + // If we encounter something that is not a module, throw away + // any module that we've found so far because we now know that + // it is nested within something else. + cgu_def_id = None; + } + + current_def_id = tcx.parent(current_def_id); + } + + let cgu_def_id = cgu_def_id.unwrap(); + + *cache.entry((cgu_def_id, volatile)).or_insert_with(|| { + let def_path = tcx.def_path(cgu_def_id); + + let components = def_path.data.iter().map(|part| match part.data.name() { + DefPathDataName::Named(name) => name, + DefPathDataName::Anon { .. } => unreachable!(), + }); + + let volatile_suffix = volatile.then_some("volatile"); + + name_builder.build_cgu_name(def_path.krate, components, volatile_suffix) + }) +} + +// Anything we can't find a proper codegen unit for goes into this. +fn fallback_cgu_name(name_builder: &mut CodegenUnitNameBuilder<'_>) -> Symbol { + name_builder.build_cgu_name(LOCAL_CRATE, &["fallback"], Some("cgu")) +} + +fn mono_item_linkage_and_visibility<'tcx>( + tcx: TyCtxt<'tcx>, + mono_item: &MonoItem<'tcx>, + can_be_internalized: &mut bool, + export_generics: bool, +) -> (Linkage, Visibility) { + if let Some(explicit_linkage) = mono_item.explicit_linkage(tcx) { + return (explicit_linkage, Visibility::Default); + } + let vis = mono_item_visibility(tcx, mono_item, can_be_internalized, export_generics); + (Linkage::External, vis) +} + +type CguNameCache = FxHashMap<(DefId, bool), Symbol>; + +fn static_visibility<'tcx>( + tcx: TyCtxt<'tcx>, + can_be_internalized: &mut bool, + def_id: DefId, +) -> Visibility { + if tcx.is_reachable_non_generic(def_id) { + *can_be_internalized = false; + default_visibility(tcx, def_id, false) + } else { + Visibility::Hidden + } +} + +fn mono_item_visibility<'tcx>( + tcx: TyCtxt<'tcx>, + mono_item: &MonoItem<'tcx>, + can_be_internalized: &mut bool, + export_generics: bool, +) -> Visibility { + let instance = match mono_item { + // This is pretty complicated; see below. + MonoItem::Fn(instance) => instance, + + // Misc handling for generics and such, but otherwise: + MonoItem::Static(def_id) => return static_visibility(tcx, can_be_internalized, *def_id), + MonoItem::GlobalAsm(item_id) => { + return static_visibility(tcx, can_be_internalized, item_id.owner_id.to_def_id()); + } + }; + + let def_id = match instance.def { + InstanceDef::Item(def_id) | InstanceDef::DropGlue(def_id, Some(_)) => def_id, + + // We match the visibility of statics here + InstanceDef::ThreadLocalShim(def_id) => { + return static_visibility(tcx, can_be_internalized, def_id); + } + + // These are all compiler glue and such, never exported, always hidden. + InstanceDef::VTableShim(..) + | InstanceDef::ReifyShim(..) + | InstanceDef::FnPtrShim(..) + | InstanceDef::Virtual(..) + | InstanceDef::Intrinsic(..) + | InstanceDef::ClosureOnceShim { .. } + | InstanceDef::DropGlue(..) + | InstanceDef::CloneShim(..) + | InstanceDef::FnPtrAddrShim(..) => return Visibility::Hidden, + }; + + // The `start_fn` lang item is actually a monomorphized instance of a + // function in the standard library, used for the `main` function. We don't + // want to export it so we tag it with `Hidden` visibility but this symbol + // is only referenced from the actual `main` symbol which we unfortunately + // don't know anything about during partitioning/collection. As a result we + // forcibly keep this symbol out of the `internalization_candidates` set. + // + // FIXME: eventually we don't want to always force this symbol to have + // hidden visibility, it should indeed be a candidate for + // internalization, but we have to understand that it's referenced + // from the `main` symbol we'll generate later. + // + // This may be fixable with a new `InstanceDef` perhaps? Unsure! + if tcx.lang_items().start_fn() == Some(def_id) { + *can_be_internalized = false; + return Visibility::Hidden; + } + + let is_generic = instance.substs.non_erasable_generics().next().is_some(); + + // Upstream `DefId` instances get different handling than local ones. + let Some(def_id) = def_id.as_local() else { + return if export_generics && is_generic { + // If it is an upstream monomorphization and we export generics, we must make + // it available to downstream crates. + *can_be_internalized = false; + default_visibility(tcx, def_id, true) + } else { + Visibility::Hidden + }; + }; + + if is_generic { + if export_generics { + if tcx.is_unreachable_local_definition(def_id) { + // This instance cannot be used from another crate. + Visibility::Hidden + } else { + // This instance might be useful in a downstream crate. + *can_be_internalized = false; + default_visibility(tcx, def_id.to_def_id(), true) + } + } else { + // We are not exporting generics or the definition is not reachable + // for downstream crates, we can internalize its instantiations. + Visibility::Hidden + } + } else { + // If this isn't a generic function then we mark this a `Default` if + // this is a reachable item, meaning that it's a symbol other crates may + // access when they link to us. + if tcx.is_reachable_non_generic(def_id.to_def_id()) { + *can_be_internalized = false; + debug_assert!(!is_generic); + return default_visibility(tcx, def_id.to_def_id(), false); + } + + // If this isn't reachable then we're gonna tag this with `Hidden` + // visibility. In some situations though we'll want to prevent this + // symbol from being internalized. + // + // There's two categories of items here: + // + // * First is weak lang items. These are basically mechanisms for + // libcore to forward-reference symbols defined later in crates like + // the standard library or `#[panic_handler]` definitions. The + // definition of these weak lang items needs to be referencable by + // libcore, so we're no longer a candidate for internalization. + // Removal of these functions can't be done by LLVM but rather must be + // done by the linker as it's a non-local decision. + // + // * Second is "std internal symbols". Currently this is primarily used + // for allocator symbols. Allocators are a little weird in their + // implementation, but the idea is that the compiler, at the last + // minute, defines an allocator with an injected object file. The + // `alloc` crate references these symbols (`__rust_alloc`) and the + // definition doesn't get hooked up until a linked crate artifact is + // generated. + // + // The symbols synthesized by the compiler (`__rust_alloc`) are thin + // veneers around the actual implementation, some other symbol which + // implements the same ABI. These symbols (things like `__rg_alloc`, + // `__rdl_alloc`, `__rde_alloc`, etc), are all tagged with "std + // internal symbols". + // + // The std-internal symbols here **should not show up in a dll as an + // exported interface**, so they return `false` from + // `is_reachable_non_generic` above and we'll give them `Hidden` + // visibility below. Like the weak lang items, though, we can't let + // LLVM internalize them as this decision is left up to the linker to + // omit them, so prevent them from being internalized. + let attrs = tcx.codegen_fn_attrs(def_id); + if attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL) { + *can_be_internalized = false; + } + + Visibility::Hidden + } +} + +fn default_visibility(tcx: TyCtxt<'_>, id: DefId, is_generic: bool) -> Visibility { + if !tcx.sess.target.default_hidden_visibility { + return Visibility::Default; + } + + // Generic functions never have export-level C. + if is_generic { + return Visibility::Hidden; + } + + // Things with export level C don't get instantiated in + // downstream crates. + if !id.is_local() { + return Visibility::Hidden; + } + + // C-export level items remain at `Default`, all other internal + // items become `Hidden`. + match tcx.reachable_non_generics(id.krate).get(&id) { + Some(SymbolExportInfo { level: SymbolExportLevel::C, .. }) => Visibility::Default, + _ => Visibility::Hidden, + } +} +fn debug_dump<'a, 'tcx: 'a>(tcx: TyCtxt<'tcx>, label: &str, cgus: &[CodegenUnit<'tcx>]) { + let dump = move || { + use std::fmt::Write; + + let num_cgus = cgus.len(); + let max = cgus.iter().map(|cgu| cgu.size_estimate()).max().unwrap(); + let min = cgus.iter().map(|cgu| cgu.size_estimate()).min().unwrap(); + let ratio = max as f64 / min as f64; + + let s = &mut String::new(); + let _ = writeln!( + s, + "{label} ({num_cgus} CodegenUnits, max={max}, min={min}, max/min={ratio:.1}):" + ); + for cgu in cgus { + let _ = + writeln!(s, "CodegenUnit {} estimated size {}:", cgu.name(), cgu.size_estimate()); + + for (mono_item, linkage) in cgu.items() { + let symbol_name = mono_item.symbol_name(tcx).name; + let symbol_hash_start = symbol_name.rfind('h'); + let symbol_hash = symbol_hash_start.map_or("<no hash>", |i| &symbol_name[i..]); + + let _ = with_no_trimmed_paths!(writeln!( + s, + " - {} [{:?}] [{}] estimated size {}", + mono_item, + linkage, + symbol_hash, + mono_item.size_estimate(tcx) + )); + } + + let _ = writeln!(s); + } + + std::mem::take(s) + }; + + debug!("{}", dump()); +} + +#[inline(never)] // give this a place in the profiler +fn assert_symbols_are_distinct<'a, 'tcx, I>(tcx: TyCtxt<'tcx>, mono_items: I) +where + I: Iterator<Item = &'a MonoItem<'tcx>>, + 'tcx: 'a, +{ + let _prof_timer = tcx.prof.generic_activity("assert_symbols_are_distinct"); + + let mut symbols: Vec<_> = + mono_items.map(|mono_item| (mono_item, mono_item.symbol_name(tcx))).collect(); + + symbols.sort_by_key(|sym| sym.1); + + for &[(mono_item1, ref sym1), (mono_item2, ref sym2)] in symbols.array_windows() { + if sym1 == sym2 { + let span1 = mono_item1.local_span(tcx); + let span2 = mono_item2.local_span(tcx); + + // Deterministically select one of the spans for error reporting + let span = match (span1, span2) { + (Some(span1), Some(span2)) => { + Some(if span1.lo().0 > span2.lo().0 { span1 } else { span2 }) + } + (span1, span2) => span1.or(span2), + }; + + tcx.sess.emit_fatal(SymbolAlreadyDefined { span, symbol: sym1.to_string() }); + } + } +} + +fn collect_and_partition_mono_items(tcx: TyCtxt<'_>, (): ()) -> (&DefIdSet, &[CodegenUnit<'_>]) { + let collection_mode = match tcx.sess.opts.unstable_opts.print_mono_items { + Some(ref s) => { + let mode = s.to_lowercase(); + let mode = mode.trim(); + if mode == "eager" { + MonoItemCollectionMode::Eager + } else { + if mode != "lazy" { + tcx.sess.emit_warning(UnknownCguCollectionMode { mode }); + } + + MonoItemCollectionMode::Lazy + } + } + None => { + if tcx.sess.link_dead_code() { + MonoItemCollectionMode::Eager + } else { + MonoItemCollectionMode::Lazy + } + } + }; + + let (items, inlining_map) = collector::collect_crate_mono_items(tcx, collection_mode); + + tcx.sess.abort_if_errors(); + + let (codegen_units, _) = tcx.sess.time("partition_and_assert_distinct_symbols", || { + sync::join( + || { + let mut codegen_units = partition( + tcx, + &mut items.iter().copied(), + tcx.sess.codegen_units(), + &inlining_map, + ); + codegen_units[0].make_primary(); + &*tcx.arena.alloc_from_iter(codegen_units) + }, + || assert_symbols_are_distinct(tcx, items.iter()), + ) + }); + + if tcx.prof.enabled() { + // Record CGU size estimates for self-profiling. + for cgu in codegen_units { + tcx.prof.artifact_size( + "codegen_unit_size_estimate", + cgu.name().as_str(), + cgu.size_estimate() as u64, + ); + } + } + + let mono_items: DefIdSet = items + .iter() + .filter_map(|mono_item| match *mono_item { + MonoItem::Fn(ref instance) => Some(instance.def_id()), + MonoItem::Static(def_id) => Some(def_id), + _ => None, + }) + .collect(); + + // Output monomorphization stats per def_id + if let SwitchWithOptPath::Enabled(ref path) = tcx.sess.opts.unstable_opts.dump_mono_stats { + if let Err(err) = + dump_mono_items_stats(tcx, &codegen_units, path, tcx.crate_name(LOCAL_CRATE)) + { + tcx.sess.emit_fatal(CouldntDumpMonoStats { error: err.to_string() }); + } + } + + if tcx.sess.opts.unstable_opts.print_mono_items.is_some() { + let mut item_to_cgus: FxHashMap<_, Vec<_>> = Default::default(); + + for cgu in codegen_units { + for (&mono_item, &linkage) in cgu.items() { + item_to_cgus.entry(mono_item).or_default().push((cgu.name(), linkage)); + } + } + + let mut item_keys: Vec<_> = items + .iter() + .map(|i| { + let mut output = with_no_trimmed_paths!(i.to_string()); + output.push_str(" @@"); + let mut empty = Vec::new(); + let cgus = item_to_cgus.get_mut(i).unwrap_or(&mut empty); + cgus.sort_by_key(|(name, _)| *name); + cgus.dedup(); + for &(ref cgu_name, (linkage, _)) in cgus.iter() { + output.push(' '); + output.push_str(cgu_name.as_str()); + + let linkage_abbrev = match linkage { + Linkage::External => "External", + Linkage::AvailableExternally => "Available", + Linkage::LinkOnceAny => "OnceAny", + Linkage::LinkOnceODR => "OnceODR", + Linkage::WeakAny => "WeakAny", + Linkage::WeakODR => "WeakODR", + Linkage::Appending => "Appending", + Linkage::Internal => "Internal", + Linkage::Private => "Private", + Linkage::ExternalWeak => "ExternalWeak", + Linkage::Common => "Common", + }; + + output.push('['); + output.push_str(linkage_abbrev); + output.push(']'); + } + output + }) + .collect(); + + item_keys.sort(); + + for item in item_keys { + println!("MONO_ITEM {item}"); + } + } + + (tcx.arena.alloc(mono_items), codegen_units) +} + +/// Outputs stats about instantiation counts and estimated size, per `MonoItem`'s +/// def, to a file in the given output directory. +fn dump_mono_items_stats<'tcx>( + tcx: TyCtxt<'tcx>, + codegen_units: &[CodegenUnit<'tcx>], + output_directory: &Option<PathBuf>, + crate_name: Symbol, +) -> Result<(), Box<dyn std::error::Error>> { + let output_directory = if let Some(ref directory) = output_directory { + fs::create_dir_all(directory)?; + directory + } else { + Path::new(".") + }; + + let format = tcx.sess.opts.unstable_opts.dump_mono_stats_format; + let ext = format.extension(); + let filename = format!("{crate_name}.mono_items.{ext}"); + let output_path = output_directory.join(&filename); + let file = File::create(&output_path)?; + let mut file = BufWriter::new(file); + + // Gather instantiated mono items grouped by def_id + let mut items_per_def_id: FxHashMap<_, Vec<_>> = Default::default(); + for cgu in codegen_units { + for (&mono_item, _) in cgu.items() { + // Avoid variable-sized compiler-generated shims + if mono_item.is_user_defined() { + items_per_def_id.entry(mono_item.def_id()).or_default().push(mono_item); + } + } + } + + #[derive(serde::Serialize)] + struct MonoItem { + name: String, + instantiation_count: usize, + size_estimate: usize, + total_estimate: usize, + } + + // Output stats sorted by total instantiated size, from heaviest to lightest + let mut stats: Vec<_> = items_per_def_id + .into_iter() + .map(|(def_id, items)| { + let name = with_no_trimmed_paths!(tcx.def_path_str(def_id)); + let instantiation_count = items.len(); + let size_estimate = items[0].size_estimate(tcx); + let total_estimate = instantiation_count * size_estimate; + MonoItem { name, instantiation_count, size_estimate, total_estimate } + }) + .collect(); + stats.sort_unstable_by_key(|item| cmp::Reverse(item.total_estimate)); + + if !stats.is_empty() { + match format { + DumpMonoStatsFormat::Json => serde_json::to_writer(file, &stats)?, + DumpMonoStatsFormat::Markdown => { + writeln!( + file, + "| Item | Instantiation count | Estimated Cost Per Instantiation | Total Estimated Cost |" + )?; + writeln!(file, "| --- | ---: | ---: | ---: |")?; + + for MonoItem { name, instantiation_count, size_estimate, total_estimate } in stats { + writeln!( + file, + "| `{name}` | {instantiation_count} | {size_estimate} | {total_estimate} |" + )?; + } + } + } + } + + Ok(()) +} + +fn codegened_and_inlined_items(tcx: TyCtxt<'_>, (): ()) -> &DefIdSet { + let (items, cgus) = tcx.collect_and_partition_mono_items(()); + let mut visited = DefIdSet::default(); + let mut result = items.clone(); + + for cgu in cgus { + for (item, _) in cgu.items() { + if let MonoItem::Fn(ref instance) = item { + let did = instance.def_id(); + if !visited.insert(did) { + continue; + } + let body = tcx.instance_mir(instance.def); + for block in body.basic_blocks.iter() { + for statement in &block.statements { + let mir::StatementKind::Coverage(_) = statement.kind else { continue }; + let scope = statement.source_info.scope; + if let Some(inlined) = scope.inlined_instance(&body.source_scopes) { + result.insert(inlined.def_id()); + } + } + } + } + } + } + + tcx.arena.alloc(result) +} + +pub fn provide(providers: &mut Providers) { + providers.collect_and_partition_mono_items = collect_and_partition_mono_items; + providers.codegened_and_inlined_items = codegened_and_inlined_items; + + providers.is_codegened_item = |tcx, def_id| { + let (all_mono_items, _) = tcx.collect_and_partition_mono_items(()); + all_mono_items.contains(&def_id) + }; + + providers.codegen_unit = |tcx, name| { + let (_, all) = tcx.collect_and_partition_mono_items(()); + all.iter() + .find(|cgu| cgu.name() == name) + .unwrap_or_else(|| panic!("failed to find cgu with name {name:?}")) + }; +} diff --git a/compiler/rustc_monomorphize/src/partitioning/default.rs b/compiler/rustc_monomorphize/src/partitioning/default.rs deleted file mode 100644 index 37b7f6bf8a8..00000000000 --- a/compiler/rustc_monomorphize/src/partitioning/default.rs +++ /dev/null @@ -1,568 +0,0 @@ -use std::collections::hash_map::Entry; - -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_hir::def::DefKind; -use rustc_hir::def_id::{DefId, LOCAL_CRATE}; -use rustc_hir::definitions::DefPathDataName; -use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; -use rustc_middle::middle::exported_symbols::{SymbolExportInfo, SymbolExportLevel}; -use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder, Linkage, Visibility}; -use rustc_middle::mir::mono::{InstantiationMode, MonoItem}; -use rustc_middle::ty::print::characteristic_def_id_of_type; -use rustc_middle::ty::{self, visit::TypeVisitableExt, InstanceDef, TyCtxt}; -use rustc_span::symbol::Symbol; - -use super::PartitioningCx; -use crate::collector::InliningMap; -use crate::partitioning::merging; -use crate::partitioning::{ - MonoItemPlacement, Partition, PostInliningPartitioning, PreInliningPartitioning, -}; - -pub struct DefaultPartitioning; - -impl<'tcx> Partition<'tcx> for DefaultPartitioning { - fn place_root_mono_items<I>( - &mut self, - cx: &PartitioningCx<'_, 'tcx>, - mono_items: &mut I, - ) -> PreInliningPartitioning<'tcx> - where - I: Iterator<Item = MonoItem<'tcx>>, - { - let mut roots = FxHashSet::default(); - let mut codegen_units = FxHashMap::default(); - let is_incremental_build = cx.tcx.sess.opts.incremental.is_some(); - let mut internalization_candidates = FxHashSet::default(); - - // Determine if monomorphizations instantiated in this crate will be made - // available to downstream crates. This depends on whether we are in - // share-generics mode and whether the current crate can even have - // downstream crates. - let export_generics = - cx.tcx.sess.opts.share_generics() && cx.tcx.local_crate_exports_generics(); - - let cgu_name_builder = &mut CodegenUnitNameBuilder::new(cx.tcx); - let cgu_name_cache = &mut FxHashMap::default(); - - for mono_item in mono_items { - match mono_item.instantiation_mode(cx.tcx) { - InstantiationMode::GloballyShared { .. } => {} - InstantiationMode::LocalCopy => continue, - } - - let characteristic_def_id = characteristic_def_id_of_mono_item(cx.tcx, mono_item); - let is_volatile = is_incremental_build && mono_item.is_generic_fn(); - - let codegen_unit_name = match characteristic_def_id { - Some(def_id) => compute_codegen_unit_name( - cx.tcx, - cgu_name_builder, - def_id, - is_volatile, - cgu_name_cache, - ), - None => fallback_cgu_name(cgu_name_builder), - }; - - let codegen_unit = codegen_units - .entry(codegen_unit_name) - .or_insert_with(|| CodegenUnit::new(codegen_unit_name)); - - let mut can_be_internalized = true; - let (linkage, visibility) = mono_item_linkage_and_visibility( - cx.tcx, - &mono_item, - &mut can_be_internalized, - export_generics, - ); - if visibility == Visibility::Hidden && can_be_internalized { - internalization_candidates.insert(mono_item); - } - - codegen_unit.items_mut().insert(mono_item, (linkage, visibility)); - roots.insert(mono_item); - } - - // Always ensure we have at least one CGU; otherwise, if we have a - // crate with just types (for example), we could wind up with no CGU. - if codegen_units.is_empty() { - let codegen_unit_name = fallback_cgu_name(cgu_name_builder); - codegen_units.insert(codegen_unit_name, CodegenUnit::new(codegen_unit_name)); - } - - PreInliningPartitioning { - codegen_units: codegen_units.into_values().collect(), - roots, - internalization_candidates, - } - } - - fn merge_codegen_units( - &mut self, - cx: &PartitioningCx<'_, 'tcx>, - initial_partitioning: &mut PreInliningPartitioning<'tcx>, - ) { - merging::merge_codegen_units(cx, initial_partitioning); - } - - fn place_inlined_mono_items( - &mut self, - cx: &PartitioningCx<'_, 'tcx>, - initial_partitioning: PreInliningPartitioning<'tcx>, - ) -> PostInliningPartitioning<'tcx> { - let mut new_partitioning = Vec::new(); - let mut mono_item_placements = FxHashMap::default(); - - let PreInliningPartitioning { - codegen_units: initial_cgus, - roots, - internalization_candidates, - } = initial_partitioning; - - let single_codegen_unit = initial_cgus.len() == 1; - - for old_codegen_unit in initial_cgus { - // Collect all items that need to be available in this codegen unit. - let mut reachable = FxHashSet::default(); - for root in old_codegen_unit.items().keys() { - follow_inlining(*root, cx.inlining_map, &mut reachable); - } - - let mut new_codegen_unit = CodegenUnit::new(old_codegen_unit.name()); - - // Add all monomorphizations that are not already there. - for mono_item in reachable { - if let Some(linkage) = old_codegen_unit.items().get(&mono_item) { - // This is a root, just copy it over. - new_codegen_unit.items_mut().insert(mono_item, *linkage); - } else { - if roots.contains(&mono_item) { - bug!( - "GloballyShared mono-item inlined into other CGU: \ - {:?}", - mono_item - ); - } - - // This is a CGU-private copy. - new_codegen_unit - .items_mut() - .insert(mono_item, (Linkage::Internal, Visibility::Default)); - } - - if !single_codegen_unit { - // If there is more than one codegen unit, we need to keep track - // in which codegen units each monomorphization is placed. - match mono_item_placements.entry(mono_item) { - Entry::Occupied(e) => { - let placement = e.into_mut(); - debug_assert!(match *placement { - MonoItemPlacement::SingleCgu { cgu_name } => { - cgu_name != new_codegen_unit.name() - } - MonoItemPlacement::MultipleCgus => true, - }); - *placement = MonoItemPlacement::MultipleCgus; - } - Entry::Vacant(e) => { - e.insert(MonoItemPlacement::SingleCgu { - cgu_name: new_codegen_unit.name(), - }); - } - } - } - } - - new_partitioning.push(new_codegen_unit); - } - - return PostInliningPartitioning { - codegen_units: new_partitioning, - mono_item_placements, - internalization_candidates, - }; - - fn follow_inlining<'tcx>( - mono_item: MonoItem<'tcx>, - inlining_map: &InliningMap<'tcx>, - visited: &mut FxHashSet<MonoItem<'tcx>>, - ) { - if !visited.insert(mono_item) { - return; - } - - inlining_map.with_inlining_candidates(mono_item, |target| { - follow_inlining(target, inlining_map, visited); - }); - } - } - - fn internalize_symbols( - &mut self, - cx: &PartitioningCx<'_, 'tcx>, - partitioning: &mut PostInliningPartitioning<'tcx>, - ) { - if partitioning.codegen_units.len() == 1 { - // Fast path for when there is only one codegen unit. In this case we - // can internalize all candidates, since there is nowhere else they - // could be accessed from. - for cgu in &mut partitioning.codegen_units { - for candidate in &partitioning.internalization_candidates { - cgu.items_mut().insert(*candidate, (Linkage::Internal, Visibility::Default)); - } - } - - return; - } - - // Build a map from every monomorphization to all the monomorphizations that - // reference it. - let mut accessor_map: FxHashMap<MonoItem<'tcx>, Vec<MonoItem<'tcx>>> = Default::default(); - cx.inlining_map.iter_accesses(|accessor, accessees| { - for accessee in accessees { - accessor_map.entry(*accessee).or_default().push(accessor); - } - }); - - let mono_item_placements = &partitioning.mono_item_placements; - - // For each internalization candidates in each codegen unit, check if it is - // accessed from outside its defining codegen unit. - for cgu in &mut partitioning.codegen_units { - let home_cgu = MonoItemPlacement::SingleCgu { cgu_name: cgu.name() }; - - for (accessee, linkage_and_visibility) in cgu.items_mut() { - if !partitioning.internalization_candidates.contains(accessee) { - // This item is no candidate for internalizing, so skip it. - continue; - } - debug_assert_eq!(mono_item_placements[accessee], home_cgu); - - if let Some(accessors) = accessor_map.get(accessee) { - if accessors - .iter() - .filter_map(|accessor| { - // Some accessors might not have been - // instantiated. We can safely ignore those. - mono_item_placements.get(accessor) - }) - .any(|placement| *placement != home_cgu) - { - // Found an accessor from another CGU, so skip to the next - // item without marking this one as internal. - continue; - } - } - - // If we got here, we did not find any accesses from other CGUs, - // so it's fine to make this monomorphization internal. - *linkage_and_visibility = (Linkage::Internal, Visibility::Default); - } - } - } -} - -fn characteristic_def_id_of_mono_item<'tcx>( - tcx: TyCtxt<'tcx>, - mono_item: MonoItem<'tcx>, -) -> Option<DefId> { - match mono_item { - MonoItem::Fn(instance) => { - let def_id = match instance.def { - ty::InstanceDef::Item(def) => def, - ty::InstanceDef::VTableShim(..) - | ty::InstanceDef::ReifyShim(..) - | ty::InstanceDef::FnPtrShim(..) - | ty::InstanceDef::ClosureOnceShim { .. } - | ty::InstanceDef::Intrinsic(..) - | ty::InstanceDef::DropGlue(..) - | ty::InstanceDef::Virtual(..) - | ty::InstanceDef::CloneShim(..) - | ty::InstanceDef::ThreadLocalShim(..) - | ty::InstanceDef::FnPtrAddrShim(..) => return None, - }; - - // If this is a method, we want to put it into the same module as - // its self-type. If the self-type does not provide a characteristic - // DefId, we use the location of the impl after all. - - if tcx.trait_of_item(def_id).is_some() { - let self_ty = instance.substs.type_at(0); - // This is a default implementation of a trait method. - return characteristic_def_id_of_type(self_ty).or(Some(def_id)); - } - - if let Some(impl_def_id) = tcx.impl_of_method(def_id) { - if tcx.sess.opts.incremental.is_some() - && tcx.trait_id_of_impl(impl_def_id) == tcx.lang_items().drop_trait() - { - // Put `Drop::drop` into the same cgu as `drop_in_place` - // since `drop_in_place` is the only thing that can - // call it. - return None; - } - - // When polymorphization is enabled, methods which do not depend on their generic - // parameters, but the self-type of their impl block do will fail to normalize. - if !tcx.sess.opts.unstable_opts.polymorphize || !instance.has_param() { - // This is a method within an impl, find out what the self-type is: - let impl_self_ty = tcx.subst_and_normalize_erasing_regions( - instance.substs, - ty::ParamEnv::reveal_all(), - tcx.type_of(impl_def_id), - ); - if let Some(def_id) = characteristic_def_id_of_type(impl_self_ty) { - return Some(def_id); - } - } - } - - Some(def_id) - } - MonoItem::Static(def_id) => Some(def_id), - MonoItem::GlobalAsm(item_id) => Some(item_id.owner_id.to_def_id()), - } -} - -fn compute_codegen_unit_name( - tcx: TyCtxt<'_>, - name_builder: &mut CodegenUnitNameBuilder<'_>, - def_id: DefId, - volatile: bool, - cache: &mut CguNameCache, -) -> Symbol { - // Find the innermost module that is not nested within a function. - let mut current_def_id = def_id; - let mut cgu_def_id = None; - // Walk backwards from the item we want to find the module for. - loop { - if current_def_id.is_crate_root() { - if cgu_def_id.is_none() { - // If we have not found a module yet, take the crate root. - cgu_def_id = Some(def_id.krate.as_def_id()); - } - break; - } else if tcx.def_kind(current_def_id) == DefKind::Mod { - if cgu_def_id.is_none() { - cgu_def_id = Some(current_def_id); - } - } else { - // If we encounter something that is not a module, throw away - // any module that we've found so far because we now know that - // it is nested within something else. - cgu_def_id = None; - } - - current_def_id = tcx.parent(current_def_id); - } - - let cgu_def_id = cgu_def_id.unwrap(); - - *cache.entry((cgu_def_id, volatile)).or_insert_with(|| { - let def_path = tcx.def_path(cgu_def_id); - - let components = def_path.data.iter().map(|part| match part.data.name() { - DefPathDataName::Named(name) => name, - DefPathDataName::Anon { .. } => unreachable!(), - }); - - let volatile_suffix = volatile.then_some("volatile"); - - name_builder.build_cgu_name(def_path.krate, components, volatile_suffix) - }) -} - -// Anything we can't find a proper codegen unit for goes into this. -fn fallback_cgu_name(name_builder: &mut CodegenUnitNameBuilder<'_>) -> Symbol { - name_builder.build_cgu_name(LOCAL_CRATE, &["fallback"], Some("cgu")) -} - -fn mono_item_linkage_and_visibility<'tcx>( - tcx: TyCtxt<'tcx>, - mono_item: &MonoItem<'tcx>, - can_be_internalized: &mut bool, - export_generics: bool, -) -> (Linkage, Visibility) { - if let Some(explicit_linkage) = mono_item.explicit_linkage(tcx) { - return (explicit_linkage, Visibility::Default); - } - let vis = mono_item_visibility(tcx, mono_item, can_be_internalized, export_generics); - (Linkage::External, vis) -} - -type CguNameCache = FxHashMap<(DefId, bool), Symbol>; - -fn static_visibility<'tcx>( - tcx: TyCtxt<'tcx>, - can_be_internalized: &mut bool, - def_id: DefId, -) -> Visibility { - if tcx.is_reachable_non_generic(def_id) { - *can_be_internalized = false; - default_visibility(tcx, def_id, false) - } else { - Visibility::Hidden - } -} - -fn mono_item_visibility<'tcx>( - tcx: TyCtxt<'tcx>, - mono_item: &MonoItem<'tcx>, - can_be_internalized: &mut bool, - export_generics: bool, -) -> Visibility { - let instance = match mono_item { - // This is pretty complicated; see below. - MonoItem::Fn(instance) => instance, - - // Misc handling for generics and such, but otherwise: - MonoItem::Static(def_id) => return static_visibility(tcx, can_be_internalized, *def_id), - MonoItem::GlobalAsm(item_id) => { - return static_visibility(tcx, can_be_internalized, item_id.owner_id.to_def_id()); - } - }; - - let def_id = match instance.def { - InstanceDef::Item(def_id) | InstanceDef::DropGlue(def_id, Some(_)) => def_id, - - // We match the visibility of statics here - InstanceDef::ThreadLocalShim(def_id) => { - return static_visibility(tcx, can_be_internalized, def_id); - } - - // These are all compiler glue and such, never exported, always hidden. - InstanceDef::VTableShim(..) - | InstanceDef::ReifyShim(..) - | InstanceDef::FnPtrShim(..) - | InstanceDef::Virtual(..) - | InstanceDef::Intrinsic(..) - | InstanceDef::ClosureOnceShim { .. } - | InstanceDef::DropGlue(..) - | InstanceDef::CloneShim(..) - | InstanceDef::FnPtrAddrShim(..) => return Visibility::Hidden, - }; - - // The `start_fn` lang item is actually a monomorphized instance of a - // function in the standard library, used for the `main` function. We don't - // want to export it so we tag it with `Hidden` visibility but this symbol - // is only referenced from the actual `main` symbol which we unfortunately - // don't know anything about during partitioning/collection. As a result we - // forcibly keep this symbol out of the `internalization_candidates` set. - // - // FIXME: eventually we don't want to always force this symbol to have - // hidden visibility, it should indeed be a candidate for - // internalization, but we have to understand that it's referenced - // from the `main` symbol we'll generate later. - // - // This may be fixable with a new `InstanceDef` perhaps? Unsure! - if tcx.lang_items().start_fn() == Some(def_id) { - *can_be_internalized = false; - return Visibility::Hidden; - } - - let is_generic = instance.substs.non_erasable_generics().next().is_some(); - - // Upstream `DefId` instances get different handling than local ones. - let Some(def_id) = def_id.as_local() else { - return if export_generics && is_generic { - // If it is an upstream monomorphization and we export generics, we must make - // it available to downstream crates. - *can_be_internalized = false; - default_visibility(tcx, def_id, true) - } else { - Visibility::Hidden - }; - }; - - if is_generic { - if export_generics { - if tcx.is_unreachable_local_definition(def_id) { - // This instance cannot be used from another crate. - Visibility::Hidden - } else { - // This instance might be useful in a downstream crate. - *can_be_internalized = false; - default_visibility(tcx, def_id.to_def_id(), true) - } - } else { - // We are not exporting generics or the definition is not reachable - // for downstream crates, we can internalize its instantiations. - Visibility::Hidden - } - } else { - // If this isn't a generic function then we mark this a `Default` if - // this is a reachable item, meaning that it's a symbol other crates may - // access when they link to us. - if tcx.is_reachable_non_generic(def_id.to_def_id()) { - *can_be_internalized = false; - debug_assert!(!is_generic); - return default_visibility(tcx, def_id.to_def_id(), false); - } - - // If this isn't reachable then we're gonna tag this with `Hidden` - // visibility. In some situations though we'll want to prevent this - // symbol from being internalized. - // - // There's two categories of items here: - // - // * First is weak lang items. These are basically mechanisms for - // libcore to forward-reference symbols defined later in crates like - // the standard library or `#[panic_handler]` definitions. The - // definition of these weak lang items needs to be referencable by - // libcore, so we're no longer a candidate for internalization. - // Removal of these functions can't be done by LLVM but rather must be - // done by the linker as it's a non-local decision. - // - // * Second is "std internal symbols". Currently this is primarily used - // for allocator symbols. Allocators are a little weird in their - // implementation, but the idea is that the compiler, at the last - // minute, defines an allocator with an injected object file. The - // `alloc` crate references these symbols (`__rust_alloc`) and the - // definition doesn't get hooked up until a linked crate artifact is - // generated. - // - // The symbols synthesized by the compiler (`__rust_alloc`) are thin - // veneers around the actual implementation, some other symbol which - // implements the same ABI. These symbols (things like `__rg_alloc`, - // `__rdl_alloc`, `__rde_alloc`, etc), are all tagged with "std - // internal symbols". - // - // The std-internal symbols here **should not show up in a dll as an - // exported interface**, so they return `false` from - // `is_reachable_non_generic` above and we'll give them `Hidden` - // visibility below. Like the weak lang items, though, we can't let - // LLVM internalize them as this decision is left up to the linker to - // omit them, so prevent them from being internalized. - let attrs = tcx.codegen_fn_attrs(def_id); - if attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL) { - *can_be_internalized = false; - } - - Visibility::Hidden - } -} - -fn default_visibility(tcx: TyCtxt<'_>, id: DefId, is_generic: bool) -> Visibility { - if !tcx.sess.target.default_hidden_visibility { - return Visibility::Default; - } - - // Generic functions never have export-level C. - if is_generic { - return Visibility::Hidden; - } - - // Things with export level C don't get instantiated in - // downstream crates. - if !id.is_local() { - return Visibility::Hidden; - } - - // C-export level items remain at `Default`, all other internal - // items become `Hidden`. - match tcx.reachable_non_generics(id.krate).get(&id) { - Some(SymbolExportInfo { level: SymbolExportLevel::C, .. }) => Visibility::Default, - _ => Visibility::Hidden, - } -} diff --git a/compiler/rustc_monomorphize/src/partitioning/merging.rs b/compiler/rustc_monomorphize/src/partitioning/merging.rs deleted file mode 100644 index 5c524a18454..00000000000 --- a/compiler/rustc_monomorphize/src/partitioning/merging.rs +++ /dev/null @@ -1,111 +0,0 @@ -use std::cmp; - -use rustc_data_structures::fx::FxHashMap; -use rustc_hir::def_id::LOCAL_CRATE; -use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder}; -use rustc_span::symbol::Symbol; - -use super::PartitioningCx; -use crate::partitioning::PreInliningPartitioning; - -pub fn merge_codegen_units<'tcx>( - cx: &PartitioningCx<'_, 'tcx>, - initial_partitioning: &mut PreInliningPartitioning<'tcx>, -) { - assert!(cx.target_cgu_count >= 1); - let codegen_units = &mut initial_partitioning.codegen_units; - - // Note that at this point in time the `codegen_units` here may not be in a - // deterministic order (but we know they're deterministically the same set). - // We want this merging to produce a deterministic ordering of codegen units - // from the input. - // - // Due to basically how we've implemented the merging below (merge the two - // smallest into each other) we're sure to start off with a deterministic - // order (sorted by name). This'll mean that if two cgus have the same size - // the stable sort below will keep everything nice and deterministic. - codegen_units.sort_by(|a, b| a.name().as_str().cmp(b.name().as_str())); - - // This map keeps track of what got merged into what. - let mut cgu_contents: FxHashMap<Symbol, Vec<Symbol>> = - codegen_units.iter().map(|cgu| (cgu.name(), vec![cgu.name()])).collect(); - - // Merge the two smallest codegen units until the target size is reached. - while codegen_units.len() > cx.target_cgu_count { - // Sort small cgus to the back - codegen_units.sort_by_cached_key(|cgu| cmp::Reverse(cgu.size_estimate())); - let mut smallest = codegen_units.pop().unwrap(); - let second_smallest = codegen_units.last_mut().unwrap(); - - // Move the mono-items from `smallest` to `second_smallest` - second_smallest.modify_size_estimate(smallest.size_estimate()); - for (k, v) in smallest.items_mut().drain() { - second_smallest.items_mut().insert(k, v); - } - - // Record that `second_smallest` now contains all the stuff that was in - // `smallest` before. - let mut consumed_cgu_names = cgu_contents.remove(&smallest.name()).unwrap(); - cgu_contents.get_mut(&second_smallest.name()).unwrap().append(&mut consumed_cgu_names); - - debug!( - "CodegenUnit {} merged into CodegenUnit {}", - smallest.name(), - second_smallest.name() - ); - } - - let cgu_name_builder = &mut CodegenUnitNameBuilder::new(cx.tcx); - - if cx.tcx.sess.opts.incremental.is_some() { - // If we are doing incremental compilation, we want CGU names to - // reflect the path of the source level module they correspond to. - // For CGUs that contain the code of multiple modules because of the - // merging done above, we use a concatenation of the names of - // all contained CGUs. - let new_cgu_names: FxHashMap<Symbol, String> = cgu_contents - .into_iter() - // This `filter` makes sure we only update the name of CGUs that - // were actually modified by merging. - .filter(|(_, cgu_contents)| cgu_contents.len() > 1) - .map(|(current_cgu_name, cgu_contents)| { - let mut cgu_contents: Vec<&str> = cgu_contents.iter().map(|s| s.as_str()).collect(); - - // Sort the names, so things are deterministic and easy to - // predict. - - // We are sorting primitive &strs here so we can use unstable sort - cgu_contents.sort_unstable(); - - (current_cgu_name, cgu_contents.join("--")) - }) - .collect(); - - for cgu in codegen_units.iter_mut() { - if let Some(new_cgu_name) = new_cgu_names.get(&cgu.name()) { - if cx.tcx.sess.opts.unstable_opts.human_readable_cgu_names { - cgu.set_name(Symbol::intern(&new_cgu_name)); - } else { - // If we don't require CGU names to be human-readable, we - // use a fixed length hash of the composite CGU name - // instead. - let new_cgu_name = CodegenUnit::mangle_name(&new_cgu_name); - cgu.set_name(Symbol::intern(&new_cgu_name)); - } - } - } - } else { - // If we are compiling non-incrementally we just generate simple CGU - // names containing an index. - for (index, cgu) in codegen_units.iter_mut().enumerate() { - cgu.set_name(numbered_codegen_unit_name(cgu_name_builder, index)); - } - } -} - -fn numbered_codegen_unit_name( - name_builder: &mut CodegenUnitNameBuilder<'_>, - index: usize, -) -> Symbol { - name_builder.build_cgu_name_no_mangle(LOCAL_CRATE, &["cgu"], Some(index)) -} diff --git a/compiler/rustc_monomorphize/src/partitioning/mod.rs b/compiler/rustc_monomorphize/src/partitioning/mod.rs deleted file mode 100644 index eafe57a0c02..00000000000 --- a/compiler/rustc_monomorphize/src/partitioning/mod.rs +++ /dev/null @@ -1,672 +0,0 @@ -//! Partitioning Codegen Units for Incremental Compilation -//! ====================================================== -//! -//! The task of this module is to take the complete set of monomorphizations of -//! a crate and produce a set of codegen units from it, where a codegen unit -//! is a named set of (mono-item, linkage) pairs. That is, this module -//! decides which monomorphization appears in which codegen units with which -//! linkage. The following paragraphs describe some of the background on the -//! partitioning scheme. -//! -//! The most important opportunity for saving on compilation time with -//! incremental compilation is to avoid re-codegenning and re-optimizing code. -//! Since the unit of codegen and optimization for LLVM is "modules" or, how -//! we call them "codegen units", the particulars of how much time can be saved -//! by incremental compilation are tightly linked to how the output program is -//! partitioned into these codegen units prior to passing it to LLVM -- -//! especially because we have to treat codegen units as opaque entities once -//! they are created: There is no way for us to incrementally update an existing -//! LLVM module and so we have to build any such module from scratch if it was -//! affected by some change in the source code. -//! -//! From that point of view it would make sense to maximize the number of -//! codegen units by, for example, putting each function into its own module. -//! That way only those modules would have to be re-compiled that were actually -//! affected by some change, minimizing the number of functions that could have -//! been re-used but just happened to be located in a module that is -//! re-compiled. -//! -//! However, since LLVM optimization does not work across module boundaries, -//! using such a highly granular partitioning would lead to very slow runtime -//! code since it would effectively prohibit inlining and other inter-procedure -//! optimizations. We want to avoid that as much as possible. -//! -//! Thus we end up with a trade-off: The bigger the codegen units, the better -//! LLVM's optimizer can do its work, but also the smaller the compilation time -//! reduction we get from incremental compilation. -//! -//! Ideally, we would create a partitioning such that there are few big codegen -//! units with few interdependencies between them. For now though, we use the -//! following heuristic to determine the partitioning: -//! -//! - There are two codegen units for every source-level module: -//! - One for "stable", that is non-generic, code -//! - One for more "volatile" code, i.e., monomorphized instances of functions -//! defined in that module -//! -//! In order to see why this heuristic makes sense, let's take a look at when a -//! codegen unit can get invalidated: -//! -//! 1. The most straightforward case is when the BODY of a function or global -//! changes. Then any codegen unit containing the code for that item has to be -//! re-compiled. Note that this includes all codegen units where the function -//! has been inlined. -//! -//! 2. The next case is when the SIGNATURE of a function or global changes. In -//! this case, all codegen units containing a REFERENCE to that item have to be -//! re-compiled. This is a superset of case 1. -//! -//! 3. The final and most subtle case is when a REFERENCE to a generic function -//! is added or removed somewhere. Even though the definition of the function -//! might be unchanged, a new REFERENCE might introduce a new monomorphized -//! instance of this function which has to be placed and compiled somewhere. -//! Conversely, when removing a REFERENCE, it might have been the last one with -//! that particular set of generic arguments and thus we have to remove it. -//! -//! From the above we see that just using one codegen unit per source-level -//! module is not such a good idea, since just adding a REFERENCE to some -//! generic item somewhere else would invalidate everything within the module -//! containing the generic item. The heuristic above reduces this detrimental -//! side-effect of references a little by at least not touching the non-generic -//! code of the module. -//! -//! A Note on Inlining -//! ------------------ -//! As briefly mentioned above, in order for LLVM to be able to inline a -//! function call, the body of the function has to be available in the LLVM -//! module where the call is made. This has a few consequences for partitioning: -//! -//! - The partitioning algorithm has to take care of placing functions into all -//! codegen units where they should be available for inlining. It also has to -//! decide on the correct linkage for these functions. -//! -//! - The partitioning algorithm has to know which functions are likely to get -//! inlined, so it can distribute function instantiations accordingly. Since -//! there is no way of knowing for sure which functions LLVM will decide to -//! inline in the end, we apply a heuristic here: Only functions marked with -//! `#[inline]` are considered for inlining by the partitioner. The current -//! implementation will not try to determine if a function is likely to be -//! inlined by looking at the functions definition. -//! -//! Note though that as a side-effect of creating a codegen units per -//! source-level module, functions from the same module will be available for -//! inlining, even when they are not marked `#[inline]`. - -mod default; -mod merging; - -use std::cmp; -use std::fs::{self, File}; -use std::io::{BufWriter, Write}; -use std::path::{Path, PathBuf}; - -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_data_structures::sync; -use rustc_hir::def_id::{DefIdSet, LOCAL_CRATE}; -use rustc_middle::mir; -use rustc_middle::mir::mono::MonoItem; -use rustc_middle::mir::mono::{CodegenUnit, Linkage}; -use rustc_middle::query::Providers; -use rustc_middle::ty::print::with_no_trimmed_paths; -use rustc_middle::ty::TyCtxt; -use rustc_session::config::{DumpMonoStatsFormat, SwitchWithOptPath}; -use rustc_span::symbol::Symbol; - -use crate::collector::InliningMap; -use crate::collector::{self, MonoItemCollectionMode}; -use crate::errors::{ - CouldntDumpMonoStats, SymbolAlreadyDefined, UnknownCguCollectionMode, UnknownPartitionStrategy, -}; - -enum Partitioner { - Default(default::DefaultPartitioning), - // Other partitioning strategies can go here. - Unknown, -} - -impl<'tcx> Partition<'tcx> for Partitioner { - fn place_root_mono_items<I>( - &mut self, - cx: &PartitioningCx<'_, 'tcx>, - mono_items: &mut I, - ) -> PreInliningPartitioning<'tcx> - where - I: Iterator<Item = MonoItem<'tcx>>, - { - match self { - Partitioner::Default(partitioner) => partitioner.place_root_mono_items(cx, mono_items), - Partitioner::Unknown => cx.tcx.sess.emit_fatal(UnknownPartitionStrategy), - } - } - - fn merge_codegen_units( - &mut self, - cx: &PartitioningCx<'_, 'tcx>, - initial_partitioning: &mut PreInliningPartitioning<'tcx>, - ) { - match self { - Partitioner::Default(partitioner) => { - partitioner.merge_codegen_units(cx, initial_partitioning) - } - Partitioner::Unknown => cx.tcx.sess.emit_fatal(UnknownPartitionStrategy), - } - } - - fn place_inlined_mono_items( - &mut self, - cx: &PartitioningCx<'_, 'tcx>, - initial_partitioning: PreInliningPartitioning<'tcx>, - ) -> PostInliningPartitioning<'tcx> { - match self { - Partitioner::Default(partitioner) => { - partitioner.place_inlined_mono_items(cx, initial_partitioning) - } - Partitioner::Unknown => cx.tcx.sess.emit_fatal(UnknownPartitionStrategy), - } - } - - fn internalize_symbols( - &mut self, - cx: &PartitioningCx<'_, 'tcx>, - post_inlining_partitioning: &mut PostInliningPartitioning<'tcx>, - ) { - match self { - Partitioner::Default(partitioner) => { - partitioner.internalize_symbols(cx, post_inlining_partitioning) - } - Partitioner::Unknown => cx.tcx.sess.emit_fatal(UnknownPartitionStrategy), - } - } -} - -pub struct PartitioningCx<'a, 'tcx> { - tcx: TyCtxt<'tcx>, - target_cgu_count: usize, - inlining_map: &'a InliningMap<'tcx>, -} - -trait Partition<'tcx> { - fn place_root_mono_items<I>( - &mut self, - cx: &PartitioningCx<'_, 'tcx>, - mono_items: &mut I, - ) -> PreInliningPartitioning<'tcx> - where - I: Iterator<Item = MonoItem<'tcx>>; - - fn merge_codegen_units( - &mut self, - cx: &PartitioningCx<'_, 'tcx>, - initial_partitioning: &mut PreInliningPartitioning<'tcx>, - ); - - fn place_inlined_mono_items( - &mut self, - cx: &PartitioningCx<'_, 'tcx>, - initial_partitioning: PreInliningPartitioning<'tcx>, - ) -> PostInliningPartitioning<'tcx>; - - fn internalize_symbols( - &mut self, - cx: &PartitioningCx<'_, 'tcx>, - partitioning: &mut PostInliningPartitioning<'tcx>, - ); -} - -fn get_partitioner(tcx: TyCtxt<'_>) -> Partitioner { - let strategy = match &tcx.sess.opts.unstable_opts.cgu_partitioning_strategy { - None => "default", - Some(s) => &s[..], - }; - - match strategy { - "default" => Partitioner::Default(default::DefaultPartitioning), - _ => Partitioner::Unknown, - } -} - -pub fn partition<'tcx, I>( - tcx: TyCtxt<'tcx>, - mono_items: &mut I, - max_cgu_count: usize, - inlining_map: &InliningMap<'tcx>, -) -> Vec<CodegenUnit<'tcx>> -where - I: Iterator<Item = MonoItem<'tcx>>, -{ - let _prof_timer = tcx.prof.generic_activity("cgu_partitioning"); - - let mut partitioner = get_partitioner(tcx); - let cx = &PartitioningCx { tcx, target_cgu_count: max_cgu_count, inlining_map }; - // In the first step, we place all regular monomorphizations into their - // respective 'home' codegen unit. Regular monomorphizations are all - // functions and statics defined in the local crate. - let mut initial_partitioning = { - let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_place_roots"); - partitioner.place_root_mono_items(cx, mono_items) - }; - - for cgu in &mut initial_partitioning.codegen_units { - cgu.create_size_estimate(tcx); - } - - debug_dump(tcx, "INITIAL PARTITIONING", &initial_partitioning.codegen_units); - - // Merge until we have at most `max_cgu_count` codegen units. - { - let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_merge_cgus"); - partitioner.merge_codegen_units(cx, &mut initial_partitioning); - debug_dump(tcx, "POST MERGING", &initial_partitioning.codegen_units); - } - - // In the next step, we use the inlining map to determine which additional - // monomorphizations have to go into each codegen unit. These additional - // monomorphizations can be drop-glue, functions from external crates, and - // local functions the definition of which is marked with `#[inline]`. - let mut post_inlining = { - let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_place_inline_items"); - partitioner.place_inlined_mono_items(cx, initial_partitioning) - }; - - for cgu in &mut post_inlining.codegen_units { - cgu.create_size_estimate(tcx); - } - - debug_dump(tcx, "POST INLINING", &post_inlining.codegen_units); - - // Next we try to make as many symbols "internal" as possible, so LLVM has - // more freedom to optimize. - if !tcx.sess.link_dead_code() { - let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_internalize_symbols"); - partitioner.internalize_symbols(cx, &mut post_inlining); - } - - let instrument_dead_code = - tcx.sess.instrument_coverage() && !tcx.sess.instrument_coverage_except_unused_functions(); - - if instrument_dead_code { - assert!( - post_inlining.codegen_units.len() > 0, - "There must be at least one CGU that code coverage data can be generated in." - ); - - // Find the smallest CGU that has exported symbols and put the dead - // function stubs in that CGU. We look for exported symbols to increase - // the likelihood the linker won't throw away the dead functions. - // FIXME(#92165): In order to truly resolve this, we need to make sure - // the object file (CGU) containing the dead function stubs is included - // in the final binary. This will probably require forcing these - // function symbols to be included via `-u` or `/include` linker args. - let mut cgus: Vec<_> = post_inlining.codegen_units.iter_mut().collect(); - cgus.sort_by_key(|cgu| cgu.size_estimate()); - - let dead_code_cgu = - if let Some(cgu) = cgus.into_iter().rev().find(|cgu| { - cgu.items().iter().any(|(_, (linkage, _))| *linkage == Linkage::External) - }) { - cgu - } else { - // If there are no CGUs that have externally linked items, - // then we just pick the first CGU as a fallback. - &mut post_inlining.codegen_units[0] - }; - dead_code_cgu.make_code_coverage_dead_code_cgu(); - } - - // Finally, sort by codegen unit name, so that we get deterministic results. - let PostInliningPartitioning { - codegen_units: mut result, - mono_item_placements: _, - internalization_candidates: _, - } = post_inlining; - - result.sort_by(|a, b| a.name().as_str().cmp(b.name().as_str())); - - debug_dump(tcx, "FINAL", &result); - - result -} - -pub struct PreInliningPartitioning<'tcx> { - codegen_units: Vec<CodegenUnit<'tcx>>, - roots: FxHashSet<MonoItem<'tcx>>, - internalization_candidates: FxHashSet<MonoItem<'tcx>>, -} - -/// For symbol internalization, we need to know whether a symbol/mono-item is -/// accessed from outside the codegen unit it is defined in. This type is used -/// to keep track of that. -#[derive(Clone, PartialEq, Eq, Debug)] -enum MonoItemPlacement { - SingleCgu { cgu_name: Symbol }, - MultipleCgus, -} - -struct PostInliningPartitioning<'tcx> { - codegen_units: Vec<CodegenUnit<'tcx>>, - mono_item_placements: FxHashMap<MonoItem<'tcx>, MonoItemPlacement>, - internalization_candidates: FxHashSet<MonoItem<'tcx>>, -} - -fn debug_dump<'a, 'tcx: 'a>(tcx: TyCtxt<'tcx>, label: &str, cgus: &[CodegenUnit<'tcx>]) { - let dump = move || { - use std::fmt::Write; - - let num_cgus = cgus.len(); - let max = cgus.iter().map(|cgu| cgu.size_estimate()).max().unwrap(); - let min = cgus.iter().map(|cgu| cgu.size_estimate()).min().unwrap(); - let ratio = max as f64 / min as f64; - - let s = &mut String::new(); - let _ = writeln!( - s, - "{label} ({num_cgus} CodegenUnits, max={max}, min={min}, max/min={ratio:.1}):" - ); - for cgu in cgus { - let _ = - writeln!(s, "CodegenUnit {} estimated size {}:", cgu.name(), cgu.size_estimate()); - - for (mono_item, linkage) in cgu.items() { - let symbol_name = mono_item.symbol_name(tcx).name; - let symbol_hash_start = symbol_name.rfind('h'); - let symbol_hash = symbol_hash_start.map_or("<no hash>", |i| &symbol_name[i..]); - - let _ = with_no_trimmed_paths!(writeln!( - s, - " - {} [{:?}] [{}] estimated size {}", - mono_item, - linkage, - symbol_hash, - mono_item.size_estimate(tcx) - )); - } - - let _ = writeln!(s); - } - - std::mem::take(s) - }; - - debug!("{}", dump()); -} - -#[inline(never)] // give this a place in the profiler -fn assert_symbols_are_distinct<'a, 'tcx, I>(tcx: TyCtxt<'tcx>, mono_items: I) -where - I: Iterator<Item = &'a MonoItem<'tcx>>, - 'tcx: 'a, -{ - let _prof_timer = tcx.prof.generic_activity("assert_symbols_are_distinct"); - - let mut symbols: Vec<_> = - mono_items.map(|mono_item| (mono_item, mono_item.symbol_name(tcx))).collect(); - - symbols.sort_by_key(|sym| sym.1); - - for &[(mono_item1, ref sym1), (mono_item2, ref sym2)] in symbols.array_windows() { - if sym1 == sym2 { - let span1 = mono_item1.local_span(tcx); - let span2 = mono_item2.local_span(tcx); - - // Deterministically select one of the spans for error reporting - let span = match (span1, span2) { - (Some(span1), Some(span2)) => { - Some(if span1.lo().0 > span2.lo().0 { span1 } else { span2 }) - } - (span1, span2) => span1.or(span2), - }; - - tcx.sess.emit_fatal(SymbolAlreadyDefined { span, symbol: sym1.to_string() }); - } - } -} - -fn collect_and_partition_mono_items(tcx: TyCtxt<'_>, (): ()) -> (&DefIdSet, &[CodegenUnit<'_>]) { - let collection_mode = match tcx.sess.opts.unstable_opts.print_mono_items { - Some(ref s) => { - let mode = s.to_lowercase(); - let mode = mode.trim(); - if mode == "eager" { - MonoItemCollectionMode::Eager - } else { - if mode != "lazy" { - tcx.sess.emit_warning(UnknownCguCollectionMode { mode }); - } - - MonoItemCollectionMode::Lazy - } - } - None => { - if tcx.sess.link_dead_code() { - MonoItemCollectionMode::Eager - } else { - MonoItemCollectionMode::Lazy - } - } - }; - - let (items, inlining_map) = collector::collect_crate_mono_items(tcx, collection_mode); - - tcx.sess.abort_if_errors(); - - let (codegen_units, _) = tcx.sess.time("partition_and_assert_distinct_symbols", || { - sync::join( - || { - let mut codegen_units = partition( - tcx, - &mut items.iter().copied(), - tcx.sess.codegen_units(), - &inlining_map, - ); - codegen_units[0].make_primary(); - &*tcx.arena.alloc_from_iter(codegen_units) - }, - || assert_symbols_are_distinct(tcx, items.iter()), - ) - }); - - if tcx.prof.enabled() { - // Record CGU size estimates for self-profiling. - for cgu in codegen_units { - tcx.prof.artifact_size( - "codegen_unit_size_estimate", - cgu.name().as_str(), - cgu.size_estimate() as u64, - ); - } - } - - let mono_items: DefIdSet = items - .iter() - .filter_map(|mono_item| match *mono_item { - MonoItem::Fn(ref instance) => Some(instance.def_id()), - MonoItem::Static(def_id) => Some(def_id), - _ => None, - }) - .collect(); - - // Output monomorphization stats per def_id - if let SwitchWithOptPath::Enabled(ref path) = tcx.sess.opts.unstable_opts.dump_mono_stats { - if let Err(err) = - dump_mono_items_stats(tcx, &codegen_units, path, tcx.crate_name(LOCAL_CRATE)) - { - tcx.sess.emit_fatal(CouldntDumpMonoStats { error: err.to_string() }); - } - } - - if tcx.sess.opts.unstable_opts.print_mono_items.is_some() { - let mut item_to_cgus: FxHashMap<_, Vec<_>> = Default::default(); - - for cgu in codegen_units { - for (&mono_item, &linkage) in cgu.items() { - item_to_cgus.entry(mono_item).or_default().push((cgu.name(), linkage)); - } - } - - let mut item_keys: Vec<_> = items - .iter() - .map(|i| { - let mut output = with_no_trimmed_paths!(i.to_string()); - output.push_str(" @@"); - let mut empty = Vec::new(); - let cgus = item_to_cgus.get_mut(i).unwrap_or(&mut empty); - cgus.sort_by_key(|(name, _)| *name); - cgus.dedup(); - for &(ref cgu_name, (linkage, _)) in cgus.iter() { - output.push(' '); - output.push_str(cgu_name.as_str()); - - let linkage_abbrev = match linkage { - Linkage::External => "External", - Linkage::AvailableExternally => "Available", - Linkage::LinkOnceAny => "OnceAny", - Linkage::LinkOnceODR => "OnceODR", - Linkage::WeakAny => "WeakAny", - Linkage::WeakODR => "WeakODR", - Linkage::Appending => "Appending", - Linkage::Internal => "Internal", - Linkage::Private => "Private", - Linkage::ExternalWeak => "ExternalWeak", - Linkage::Common => "Common", - }; - - output.push('['); - output.push_str(linkage_abbrev); - output.push(']'); - } - output - }) - .collect(); - - item_keys.sort(); - - for item in item_keys { - println!("MONO_ITEM {item}"); - } - } - - (tcx.arena.alloc(mono_items), codegen_units) -} - -/// Outputs stats about instantiation counts and estimated size, per `MonoItem`'s -/// def, to a file in the given output directory. -fn dump_mono_items_stats<'tcx>( - tcx: TyCtxt<'tcx>, - codegen_units: &[CodegenUnit<'tcx>], - output_directory: &Option<PathBuf>, - crate_name: Symbol, -) -> Result<(), Box<dyn std::error::Error>> { - let output_directory = if let Some(ref directory) = output_directory { - fs::create_dir_all(directory)?; - directory - } else { - Path::new(".") - }; - - let format = tcx.sess.opts.unstable_opts.dump_mono_stats_format; - let ext = format.extension(); - let filename = format!("{crate_name}.mono_items.{ext}"); - let output_path = output_directory.join(&filename); - let file = File::create(&output_path)?; - let mut file = BufWriter::new(file); - - // Gather instantiated mono items grouped by def_id - let mut items_per_def_id: FxHashMap<_, Vec<_>> = Default::default(); - for cgu in codegen_units { - for (&mono_item, _) in cgu.items() { - // Avoid variable-sized compiler-generated shims - if mono_item.is_user_defined() { - items_per_def_id.entry(mono_item.def_id()).or_default().push(mono_item); - } - } - } - - #[derive(serde::Serialize)] - struct MonoItem { - name: String, - instantiation_count: usize, - size_estimate: usize, - total_estimate: usize, - } - - // Output stats sorted by total instantiated size, from heaviest to lightest - let mut stats: Vec<_> = items_per_def_id - .into_iter() - .map(|(def_id, items)| { - let name = with_no_trimmed_paths!(tcx.def_path_str(def_id)); - let instantiation_count = items.len(); - let size_estimate = items[0].size_estimate(tcx); - let total_estimate = instantiation_count * size_estimate; - MonoItem { name, instantiation_count, size_estimate, total_estimate } - }) - .collect(); - stats.sort_unstable_by_key(|item| cmp::Reverse(item.total_estimate)); - - if !stats.is_empty() { - match format { - DumpMonoStatsFormat::Json => serde_json::to_writer(file, &stats)?, - DumpMonoStatsFormat::Markdown => { - writeln!( - file, - "| Item | Instantiation count | Estimated Cost Per Instantiation | Total Estimated Cost |" - )?; - writeln!(file, "| --- | ---: | ---: | ---: |")?; - - for MonoItem { name, instantiation_count, size_estimate, total_estimate } in stats { - writeln!( - file, - "| `{name}` | {instantiation_count} | {size_estimate} | {total_estimate} |" - )?; - } - } - } - } - - Ok(()) -} - -fn codegened_and_inlined_items(tcx: TyCtxt<'_>, (): ()) -> &DefIdSet { - let (items, cgus) = tcx.collect_and_partition_mono_items(()); - let mut visited = DefIdSet::default(); - let mut result = items.clone(); - - for cgu in cgus { - for (item, _) in cgu.items() { - if let MonoItem::Fn(ref instance) = item { - let did = instance.def_id(); - if !visited.insert(did) { - continue; - } - let body = tcx.instance_mir(instance.def); - for block in body.basic_blocks.iter() { - for statement in &block.statements { - let mir::StatementKind::Coverage(_) = statement.kind else { continue }; - let scope = statement.source_info.scope; - if let Some(inlined) = scope.inlined_instance(&body.source_scopes) { - result.insert(inlined.def_id()); - } - } - } - } - } - } - - tcx.arena.alloc(result) -} - -pub fn provide(providers: &mut Providers) { - providers.collect_and_partition_mono_items = collect_and_partition_mono_items; - providers.codegened_and_inlined_items = codegened_and_inlined_items; - - providers.is_codegened_item = |tcx, def_id| { - let (all_mono_items, _) = tcx.collect_and_partition_mono_items(()); - all_mono_items.contains(&def_id) - }; - - providers.codegen_unit = |tcx, name| { - let (_, all) = tcx.collect_and_partition_mono_items(()); - all.iter() - .find(|cgu| cgu.name() == name) - .unwrap_or_else(|| panic!("failed to find cgu with name {name:?}")) - }; -} diff --git a/compiler/rustc_monomorphize/src/util.rs b/compiler/rustc_monomorphize/src/util.rs index d12bfc6f6bb..f6a80b0431f 100644 --- a/compiler/rustc_monomorphize/src/util.rs +++ b/compiler/rustc_monomorphize/src/util.rs @@ -29,12 +29,12 @@ pub(crate) fn dump_closure_profile<'tcx>(tcx: TyCtxt<'tcx>, closure_instance: In let before_feature_tys = tcx.subst_and_normalize_erasing_regions( closure_instance.substs, param_env, - ty::EarlyBinder(before_feature_tys), + ty::EarlyBinder::bind(before_feature_tys), ); let after_feature_tys = tcx.subst_and_normalize_erasing_regions( closure_instance.substs, param_env, - ty::EarlyBinder(after_feature_tys), + ty::EarlyBinder::bind(after_feature_tys), ); let new_size = tcx diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 2d0f466e236..9263394508e 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -1,230 +1,298 @@ -parse_struct_literal_body_without_path = - struct literal body without path - .suggestion = you might have forgotten to add the struct literal inside the block +parse_add_paren = try adding parentheses -parse_struct_literal_needing_parens = - invalid struct literal - .suggestion = you might need to surround the struct literal in parentheses +parse_ambiguous_missing_keyword_for_item_definition = missing `fn` or `struct` for function or struct definition + .suggestion = if you meant to call a macro, try + .help = if you meant to call a macro, remove the `pub` and add a trailing `!` after the identifier -parse_maybe_report_ambiguous_plus = - ambiguous `+` in a type - .suggestion = use parentheses to disambiguate +parse_ambiguous_range_pattern = the range pattern here has ambiguous interpretation + .suggestion = add parentheses to clarify the precedence -parse_maybe_recover_from_bad_type_plus = - expected a path on the left-hand side of `+`, not `{$ty}` +parse_array_brackets_instead_of_braces = this is a block expression, not an array + .suggestion = to make an array, use square brackets instead of curly braces -parse_add_paren = try adding parentheses +parse_assignment_else_not_allowed = <assignment> ... else {"{"} ... {"}"} is not allowed -parse_forgot_paren = perhaps you forgot parentheses? +parse_assoc_lifetime = associated lifetimes are not supported + .label = the lifetime is given here + .help = if you meant to specify a trait object, write `dyn Trait + 'lifetime` -parse_expect_path = expected a path +parse_associated_static_item_not_allowed = associated `static` items are not allowed -parse_maybe_recover_from_bad_qpath_stage_2 = - missing angle brackets in associated item path - .suggestion = try: `{$ty}` +parse_async_block_in_2015 = `async` blocks are only allowed in Rust 2018 or later -parse_incorrect_semicolon = - expected item, found `;` - .suggestion = remove this semicolon - .help = {$name} declarations are not followed by a semicolon +parse_async_fn_in_2015 = `async fn` is not permitted in Rust 2015 + .label = to use `async fn`, switch to Rust 2018 or later -parse_incorrect_use_of_await = - incorrect use of `await` - .parentheses_suggestion = `await` is not a method call, remove the parentheses - .postfix_suggestion = `await` is a postfix operation +parse_async_move_order_incorrect = the order of `move` and `async` is incorrect + .suggestion = try switching the order -parse_in_in_typo = - expected iterable, found keyword `in` - .suggestion = remove the duplicated `in` +parse_attr_after_generic = trailing attribute after generic parameter + .label = attributes must go before parameters -parse_invalid_variable_declaration = - invalid variable declaration +parse_attr_without_generics = attribute without generic parameters + .label = attributes are only permitted when preceding parameters -parse_switch_mut_let_order = - switch the order of `mut` and `let` -parse_missing_let_before_mut = missing keyword -parse_use_let_not_auto = write `let` instead of `auto` to introduce a new variable -parse_use_let_not_var = write `let` instead of `var` to introduce a new variable +parse_attribute_on_param_type = attributes cannot be applied to a function parameter's type + .label = attributes are not allowed here -parse_invalid_comparison_operator = invalid comparison operator `{$invalid}` - .use_instead = `{$invalid}` is not a valid comparison operator, use `{$correct}` - .spaceship_operator_invalid = `<=>` is not a valid comparison operator, use `std::cmp::Ordering` +parse_bad_assoc_type_bounds = bounds on associated types do not belong here + .label = belongs in `where` clause -parse_invalid_logical_operator = `{$incorrect}` is not a logical operator - .note = unlike in e.g., Python and PHP, `&&` and `||` are used for logical operators - .use_amp_amp_for_conjunction = use `&&` to perform logical conjunction - .use_pipe_pipe_for_disjunction = use `||` to perform logical disjunction +parse_bad_item_kind = {$descr} is not supported in {$ctx} + .help = consider moving the {$descr} out to a nearby module scope -parse_tilde_is_not_unary_operator = `~` cannot be used as a unary operator - .suggestion = use `!` to perform bitwise not +parse_bad_return_type_notation_dotdot = + return type notation uses `()` instead of `(..)` for elided arguments + .suggestion = remove the `..` -parse_unexpected_if_with_if = unexpected `if` in the condition expression - .suggestion = remove the `if` +parse_bad_return_type_notation_output = + return type not allowed with return type notation + .suggestion = remove the return type -parse_unexpected_token_after_not = unexpected {$negated_desc} after identifier -parse_unexpected_token_after_not_bitwise = use `!` to perform bitwise not -parse_unexpected_token_after_not_logical = use `!` to perform logical negation -parse_unexpected_token_after_not_default = use `!` to perform logical negation or bitwise not +parse_bare_cr = {$double_quotes -> + [true] bare CR not allowed in string, use `\r` instead + *[false] character constant must be escaped: `\r` + } + .escape = escape the character -parse_malformed_loop_label = malformed loop label - .suggestion = use the correct loop label format +parse_bare_cr_in_raw_string = bare CR not allowed in raw string -parse_lifetime_in_borrow_expression = borrow expressions cannot be annotated with lifetimes - .suggestion = remove the lifetime annotation - .label = annotated with lifetime here +parse_binary_float_literal_not_supported = binary float literal is not supported +parse_bounds_not_allowed_on_trait_aliases = bounds are not allowed on trait aliases -parse_field_expression_with_generic = field expressions cannot have generic arguments +parse_box_not_pat = expected pattern, found {$descr} + .note = `box` is a reserved keyword + .suggestion = escape `box` to use it as an identifier -parse_macro_invocation_with_qualified_path = macros cannot use qualified paths +parse_box_syntax_removed = `box_syntax` has been removed + .suggestion = use `Box::new()` instead -parse_unexpected_token_after_label = expected `while`, `for`, `loop` or `{"{"}` after a label - .suggestion_remove_label = consider removing the label - .suggestion_enclose_in_block = consider enclosing expression in a block +parse_cannot_be_raw_ident = `{$ident}` cannot be a raw identifier -parse_require_colon_after_labeled_expression = labeled expression must be followed by `:` - .note = labels are used before loops and blocks, allowing e.g., `break 'label` to them - .label = the label - .suggestion = add `:` after the label +parse_catch_after_try = keyword `catch` cannot follow a `try` block + .help = try using `match` on the result of the `try` block instead + +parse_cfg_attr_bad_delim = wrong `cfg_attr` delimiters +parse_colon_as_semi = statements are terminated with a semicolon + .suggestion = use a semicolon instead + +parse_comma_after_base_struct = cannot use a comma after the base struct + .note = the base struct must always be the last field + .suggestion = remove this comma + +parse_comparison_interpreted_as_generic = + `<` is interpreted as a start of generic arguments for `{$type}`, not a comparison + .label_args = interpreted as generic arguments + .label_comparison = not interpreted as comparison + .suggestion = try comparing the cast value + +parse_comparison_operators_cannot_be_chained = comparison operators cannot be chained + .sugg_parentheses_for_function_args = or use `(...)` if you meant to specify fn arguments + .sugg_split_comparison = split the comparison into two + .sugg_parenthesize = parenthesize the comparison +parse_compound_assignment_expression_in_let = can't reassign to an uninitialized variable + .suggestion = initialize the variable + .help = if you meant to overwrite, remove the `let` binding + +parse_const_bounds_missing_tilde = const bounds must start with `~` + .suggestion = add `~` + +parse_const_generic_without_braces = expressions must be enclosed in braces to be used as const generic arguments + .suggestion = enclose the `const` expression in braces + +parse_const_global_cannot_be_mutable = const globals cannot be mutable + .label = cannot be mutable + .suggestion = you might want to declare a static instead + +parse_const_let_mutually_exclusive = `const` and `let` are mutually exclusive + .suggestion = remove `let` + +parse_cr_doc_comment = bare CR not allowed in {$block -> + [true] block doc-comment + *[false] doc-comment +} + +parse_default_not_followed_by_item = `default` is not followed by an item + .label = the `default` qualifier + .note = only `fn`, `const`, `type`, or `impl` items may be prefixed by `default` parse_do_catch_syntax_removed = found removed `do catch` syntax .note = following RFC #2388, the new non-placeholder syntax is `try` .suggestion = replace with the new syntax -parse_float_literal_requires_integer_part = float literals must have an integer part - .suggestion = must have an integer part +parse_doc_comment_does_not_document_anything = found a documentation comment that doesn't document anything + .help = doc comments must come before what they document, if a comment was intended use `//` + .suggestion = missing comma here -parse_invalid_int_literal_width = invalid width `{$width}` for integer literal - .help = valid widths are 8, 16, 32, 64 and 128 +parse_doc_comment_on_param_type = documentation comments cannot be applied to a function parameter's type + .label = doc comments are not allowed here -parse_invalid_num_literal_base_prefix = invalid base prefix for number literal - .note = base prefixes (`0xff`, `0b1010`, `0o755`) are lowercase - .suggestion = try making the prefix lowercase +parse_dot_dot_dot_for_remaining_fields = expected field pattern, found `{$token_str}` + .suggestion = to omit remaining fields, use `..` -parse_invalid_num_literal_suffix = invalid suffix `{$suffix}` for number literal - .label = invalid suffix `{$suffix}` - .help = the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.) +parse_dot_dot_dot_range_to_pattern_not_allowed = range-to patterns with `...` are not allowed + .suggestion = use `..=` instead -parse_invalid_float_literal_width = invalid width `{$width}` for float literal - .help = valid widths are 32 and 64 +parse_dotdotdot = unexpected token: `...` + .suggest_exclusive_range = use `..` for an exclusive range + .suggest_inclusive_range = or `..=` for an inclusive range -parse_invalid_float_literal_suffix = invalid suffix `{$suffix}` for float literal - .label = invalid suffix `{$suffix}` - .help = valid suffixes are `f32` and `f64` +parse_dotdotdot_rest_pattern = unexpected `...` + .label = not a valid pattern + .suggestion = for a rest pattern, use `..` instead of `...` -parse_int_literal_too_large = integer literal is too large +parse_double_colon_in_bound = expected `:` followed by trait or lifetime + .suggestion = use single colon -parse_missing_semicolon_before_array = expected `;`, found `[` - .suggestion = consider adding `;` here +parse_dyn_after_mut = `mut` must precede `dyn` + .suggestion = place `mut` before `dyn` -parse_invalid_block_macro_segment = cannot use a `block` macro fragment here - .label = the `block` fragment is within this context +parse_empty_exponent_float = expected at least one digit in exponent -parse_expect_dotdot_not_dotdotdot = expected `..`, found `...` - .suggestion = use `..` to fill in the rest of the fields +parse_empty_unicode_escape = empty unicode escape + .label = this escape must have at least 1 hex digit -parse_if_expression_missing_then_block = this `if` expression is missing a block after the condition - .add_then_block = add a block here - .condition_possibly_unfinished = this binary operation is possibly unfinished +parse_enum_pattern_instead_of_identifier = expected identifier, found enum pattern -parse_if_expression_missing_condition = missing condition for `if` expression - .condition_label = expected condition here - .block_label = if this block is the condition of the `if` expression, then it must be followed by another block +parse_enum_struct_mutually_exclusive = `enum` and `struct` are mutually exclusive + .suggestion = replace `enum struct` with -parse_expected_expression_found_let = expected expression, found `let` statement +parse_eq_field_init = expected `:`, found `=` + .suggestion = replace equals symbol with a colon + +parse_equals_struct_default = default values on `struct` fields aren't supported + .suggestion = remove this unsupported default value + +parse_escape_only_char = {$byte -> + [true] byte + *[false] character + } constant must be escaped: `{$escaped_msg}` + .escape = escape the character + +parse_expect_dotdot_not_dotdotdot = expected `..`, found `...` + .suggestion = use `..` to fill in the rest of the fields parse_expect_eq_instead_of_eqeq = expected `=`, found `==` .suggestion = consider using `=` here +parse_expect_label_found_ident = expected a label, found an identifier + .suggestion = labels start with a tick + +parse_expect_path = expected a path + +parse_expected_binding_left_of_at = left-hand side of `@` must be a binding + .label_lhs = interpreted as a pattern, not a binding + .label_rhs = also a pattern + .note = bindings are `x`, `mut x`, `ref x`, and `ref mut x` + +parse_expected_builtin_ident = expected identifier after `builtin #` + +parse_expected_comma_after_pattern_field = expected `,` + parse_expected_else_block = expected `{"{"}`, found {$first_tok} .label = expected an `if` or a block after this `else` .suggestion = add an `if` if this is the condition of a chained `else if` statement -parse_outer_attribute_not_allowed_on_if_else = outer attributes are not allowed on `if` and `else` branches - .branch_label = the attributes are attached to this branch - .ctx_label = the branch belongs to this `{$ctx}` - .suggestion = remove the attributes +parse_expected_expression_found_let = expected expression, found `let` statement -parse_missing_in_in_for_loop = missing `in` in `for` loop - .use_in_not_of = try using `in` here instead - .add_in = try adding `in` here +parse_expected_fn_path_found_fn_keyword = expected identifier, found keyword `fn` + .suggestion = use `Fn` to refer to the trait -parse_missing_expression_in_for_loop = missing expression to iterate on in `for` loop - .suggestion = try adding an expression to the `for` loop +parse_expected_identifier = expected identifier -parse_loop_else = `{$loop_kind}...else` loops are not supported - .note = consider moving this `else` clause to a separate `if` statement and use a `bool` variable to control if it should run - .loop_keyword = `else` is attached to this loop +parse_expected_identifier_found_doc_comment = expected identifier, found doc comment +parse_expected_identifier_found_doc_comment_str = expected identifier, found doc comment `{$token}` +parse_expected_identifier_found_keyword = expected identifier, found keyword +parse_expected_identifier_found_keyword_str = expected identifier, found keyword `{$token}` +parse_expected_identifier_found_reserved_identifier = expected identifier, found reserved identifier +parse_expected_identifier_found_reserved_identifier_str = expected identifier, found reserved identifier `{$token}` +parse_expected_identifier_found_reserved_keyword = expected identifier, found reserved keyword +parse_expected_identifier_found_reserved_keyword_str = expected identifier, found reserved keyword `{$token}` +parse_expected_identifier_found_str = expected identifier, found `{$token}` -parse_missing_comma_after_match_arm = expected `,` following `match` arm - .suggestion = missing a comma here to end this `match` arm +parse_expected_mut_or_const_in_raw_pointer_type = expected `mut` or `const` keyword in raw pointer type + .suggestion = add `mut` or `const` here -parse_catch_after_try = keyword `catch` cannot follow a `try` block - .help = try using `match` on the result of the `try` block instead +parse_expected_semi_found_doc_comment_str = expected `;`, found doc comment `{$token}` +parse_expected_semi_found_keyword_str = expected `;`, found keyword `{$token}` +parse_expected_semi_found_reserved_identifier_str = expected `;`, found reserved identifier `{$token}` +parse_expected_semi_found_reserved_keyword_str = expected `;`, found reserved keyword `{$token}` +parse_expected_semi_found_str = expected `;`, found `{$token}` -parse_comma_after_base_struct = cannot use a comma after the base struct - .note = the base struct must always be the last field - .suggestion = remove this comma +parse_expected_statement_after_outer_attr = expected statement after outer attribute -parse_eq_field_init = expected `:`, found `=` - .suggestion = replace equals symbol with a colon +parse_expected_trait_in_trait_impl_found_type = expected a trait, found type -parse_dotdotdot = unexpected token: `...` - .suggest_exclusive_range = use `..` for an exclusive range - .suggest_inclusive_range = or `..=` for an inclusive range +parse_extern_crate_name_with_dashes = crate name using dashes are not valid in `extern crate` statements + .label = dash-separated idents are not valid + .suggestion = if the original crate name uses dashes you need to use underscores in the code -parse_left_arrow_operator = unexpected token: `<-` - .suggestion = if you meant to write a comparison against a negative value, add a space in between `<` and `-` +parse_extern_item_cannot_be_const = extern items cannot be `const` + .suggestion = try using a static value + .note = for more information, visit https://doc.rust-lang.org/std/keyword.extern.html -parse_remove_let = expected pattern, found `let` - .suggestion = remove the unnecessary `let` keyword +parse_extra_if_in_let_else = remove the `if` if you meant to write a `let...else` statement -parse_use_eq_instead = unexpected `==` - .suggestion = try using `=` instead +parse_extra_impl_keyword_in_trait_impl = unexpected `impl` keyword + .suggestion = remove the extra `impl` + .note = this is parsed as an `impl Trait` type, but a trait is expected at this position -parse_use_empty_block_not_semi = expected { "`{}`" }, found `;` - .suggestion = try using { "`{}`" } instead -parse_comparison_interpreted_as_generic = - `<` is interpreted as a start of generic arguments for `{$type}`, not a comparison - .label_args = interpreted as generic arguments - .label_comparison = not interpreted as comparison - .suggestion = try comparing the cast value +parse_field_expression_with_generic = field expressions cannot have generic arguments -parse_shift_interpreted_as_generic = - `<<` is interpreted as a start of generic arguments for `{$type}`, not a shift - .label_args = interpreted as generic arguments - .label_comparison = not interpreted as shift - .suggestion = try shifting the cast value +parse_float_literal_requires_integer_part = float literals must have an integer part + .suggestion = must have an integer part + +parse_float_literal_unsupported_base = {$base} float literal is not supported + +parse_fn_pointer_cannot_be_async = an `fn` pointer type cannot be `async` + .label = `async` because of this + .suggestion = remove the `async` qualifier + +parse_fn_pointer_cannot_be_const = an `fn` pointer type cannot be `const` + .label = `const` because of this + .suggestion = remove the `const` qualifier + +parse_fn_ptr_with_generics = function pointer types may not have generic parameters + .suggestion = consider moving the lifetime {$arity -> + [one] parameter + *[other] parameters + } to {$for_param_list_exists -> + [true] the + *[false] a + } `for` parameter list + +parse_forgot_paren = perhaps you forgot parentheses? parse_found_expr_would_be_stmt = expected expression, found `{$token}` .label = expected expression -parse_leading_plus_not_supported = leading `+` is not supported - .label = unexpected `+` - .suggestion_remove_plus = try removing the `+` +parse_function_body_equals_expr = function body cannot be `= expression;` + .suggestion = surround the expression with `{"{"}` and `{"}"}` instead of `=` and `;` -parse_parentheses_with_struct_fields = invalid `struct` delimiters or `fn` call arguments - .suggestion_braces_for_struct = if `{$type}` is a struct, use braces as delimiters - .suggestion_no_fields_for_fn = if `{$type}` is a function, use the arguments directly +parse_generic_parameters_without_angle_brackets = generic parameters without surrounding angle brackets + .suggestion = surround the type parameters with angle brackets -parse_labeled_loop_in_break = parentheses are required around this expression to avoid confusion with a labeled break expression +parse_generics_in_path = unexpected generic arguments in path -parse_sugg_wrap_expression_in_parentheses = wrap the expression in parentheses +parse_help_set_edition_cargo = set `edition = "{$edition}"` in `Cargo.toml` +parse_help_set_edition_standalone = pass `--edition {$edition}` to `rustc` +parse_hexadecimal_float_literal_not_supported = hexadecimal float literal is not supported +parse_if_expression_missing_condition = missing condition for `if` expression + .condition_label = expected condition here + .block_label = if this block is the condition of the `if` expression, then it must be followed by another block -parse_array_brackets_instead_of_braces = this is a block expression, not an array - .suggestion = to make an array, use square brackets instead of curly braces +parse_if_expression_missing_then_block = this `if` expression is missing a block after the condition + .add_then_block = add a block here + .condition_possibly_unfinished = this binary operation is possibly unfinished -parse_match_arm_body_without_braces = `match` arm body without braces - .label_statements = {$num_statements -> - [one] this statement is not surrounded by a body - *[other] these statements are not surrounded by a body - } - .label_arrow = while parsing the `match` arm starting here - .suggestion_add_braces = surround the {$num_statements -> - [one] statement - *[other] statements - } with a body - .suggestion_use_comma_not_semicolon = replace `;` with `,` to end a `match` arm expression +parse_in_in_typo = + expected iterable, found keyword `in` + .suggestion = remove the duplicated `in` + +parse_inappropriate_default = {$article} {$descr} cannot be `default` + .label = `default` because of this + .note = only associated `fn`, `const`, and `type` items can be `default` parse_inclusive_range_extra_equals = unexpected `=` after inclusive range .suggestion_remove_eq = use `..=` instead @@ -238,36 +306,18 @@ parse_inclusive_range_no_end = inclusive range with no end .suggestion_open_range = use `..` instead .note = inclusive ranges must be bounded at the end (`..=b` or `a..=b`) -parse_struct_literal_not_allowed_here = struct literals are not allowed here - .suggestion = surround the struct literal with parentheses - -parse_invalid_interpolated_expression = invalid interpolated expression - -parse_hexadecimal_float_literal_not_supported = hexadecimal float literal is not supported -parse_octal_float_literal_not_supported = octal float literal is not supported -parse_binary_float_literal_not_supported = binary float literal is not supported -parse_not_supported = not supported - -parse_invalid_literal_suffix = suffixes on {$kind} literals are invalid - .label = invalid suffix `{$suffix}` - -parse_invalid_literal_suffix_on_tuple_index = suffixes on a tuple index are invalid - .label = invalid suffix `{$suffix}` - .tuple_exception_line_1 = `{$suffix}` is *temporarily* accepted on tuple index fields as it was incorrectly accepted on stable for a few releases - .tuple_exception_line_2 = on proc macros, you'll want to use `syn::Index::from` or `proc_macro::Literal::*_unsuffixed` for code that will desugar to tuple field access - .tuple_exception_line_3 = see issue #60210 <https://github.com/rust-lang/rust/issues/60210> for more information - -parse_expected_builtin_ident = expected identifier after `builtin #` - -parse_unknown_builtin_construct = unknown `builtin #` construct `{$name}` +parse_incorrect_braces_trait_bounds = incorrect braces around trait bounds + .suggestion = remove the parentheses -parse_non_string_abi_literal = non-string ABI literal - .suggestion = specify the ABI with a string literal +parse_incorrect_semicolon = + expected item, found `;` + .suggestion = remove this semicolon + .help = {$name} declarations are not followed by a semicolon -parse_mismatched_closing_delimiter = mismatched closing delimiter: `{$delimiter}` - .label_unmatched = mismatched closing delimiter - .label_opening_candidate = closing delimiter possibly meant for this - .label_unclosed = unclosed delimiter +parse_incorrect_use_of_await = + incorrect use of `await` + .parentheses_suggestion = `await` is not a method call, remove the parentheses + .postfix_suggestion = `await` is a postfix operation parse_incorrect_visibility_restriction = incorrect visibility restriction .help = some possible visibility restrictions are: @@ -276,36 +326,8 @@ parse_incorrect_visibility_restriction = incorrect visibility restriction `pub(in path::to::module)`: visible only on the specified path .suggestion = make this visible only to module `{$inner_str}` with `in` -parse_assignment_else_not_allowed = <assignment> ... else {"{"} ... {"}"} is not allowed - -parse_expected_statement_after_outer_attr = expected statement after outer attribute - -parse_doc_comment_does_not_document_anything = found a documentation comment that doesn't document anything - .help = doc comments must come before what they document, if a comment was intended use `//` - .suggestion = missing comma here - -parse_const_let_mutually_exclusive = `const` and `let` are mutually exclusive - .suggestion = remove `let` - -parse_invalid_expression_in_let_else = a `{$operator}` expression cannot be directly assigned in `let...else` -parse_invalid_curly_in_let_else = right curly brace `{"}"}` before `else` in a `let...else` statement not allowed -parse_extra_if_in_let_else = remove the `if` if you meant to write a `let...else` statement - -parse_compound_assignment_expression_in_let = can't reassign to an uninitialized variable - .suggestion = initialize the variable - .help = if you meant to overwrite, remove the `let` binding - -parse_suffixed_literal_in_attribute = suffixed literals are not allowed in attributes - .help = instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.) - -parse_invalid_meta_item = expected unsuffixed literal or identifier, found `{$token}` - -parse_label_inner_attr_does_not_annotate_this = the inner attribute doesn't annotate this {$item} -parse_sugg_change_inner_attr_to_outer = to annotate the {$item}, change the attribute from inner to outer style - -parse_inner_attr_not_permitted_after_outer_doc_comment = an inner attribute is not permitted following an outer doc comment - .label_attr = not permitted following an outer doc comment - .label_prev_doc_comment = previous doc comment +parse_inner_attr_explanation = inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files +parse_inner_attr_not_permitted = an inner attribute is not permitted in this context .label_does_not_annotate_this = {parse_label_inner_attr_does_not_annotate_this} .sugg_change_inner_to_outer = {parse_sugg_change_inner_attr_to_outer} @@ -315,149 +337,189 @@ parse_inner_attr_not_permitted_after_outer_attr = an inner attribute is not perm .label_does_not_annotate_this = {parse_label_inner_attr_does_not_annotate_this} .sugg_change_inner_to_outer = {parse_sugg_change_inner_attr_to_outer} -parse_inner_attr_not_permitted = an inner attribute is not permitted in this context +parse_inner_attr_not_permitted_after_outer_doc_comment = an inner attribute is not permitted following an outer doc comment + .label_attr = not permitted following an outer doc comment + .label_prev_doc_comment = previous doc comment .label_does_not_annotate_this = {parse_label_inner_attr_does_not_annotate_this} .sugg_change_inner_to_outer = {parse_sugg_change_inner_attr_to_outer} -parse_inner_attr_explanation = inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files -parse_outer_attr_explanation = outer attributes, like `#[test]`, annotate the item following them - parse_inner_doc_comment_not_permitted = expected outer doc comment .note = inner doc comments like this (starting with `//!` or `/*!`) can only appear before items .suggestion = you might have meant to write a regular comment .label_does_not_annotate_this = the inner doc comment doesn't annotate this {$item} .sugg_change_inner_to_outer = to annotate the {$item}, change the doc comment from inner to outer style -parse_expected_identifier_found_reserved_identifier_str = expected identifier, found reserved identifier `{$token}` -parse_expected_identifier_found_keyword_str = expected identifier, found keyword `{$token}` -parse_expected_identifier_found_reserved_keyword_str = expected identifier, found reserved keyword `{$token}` -parse_expected_identifier_found_doc_comment_str = expected identifier, found doc comment `{$token}` -parse_expected_identifier_found_str = expected identifier, found `{$token}` +parse_int_literal_too_large = integer literal is too large -parse_expected_identifier_found_reserved_identifier = expected identifier, found reserved identifier -parse_expected_identifier_found_keyword = expected identifier, found keyword -parse_expected_identifier_found_reserved_keyword = expected identifier, found reserved keyword -parse_expected_identifier_found_doc_comment = expected identifier, found doc comment -parse_expected_identifier = expected identifier +parse_invalid_block_macro_segment = cannot use a `block` macro fragment here + .label = the `block` fragment is within this context -parse_sugg_escape_identifier = escape `{$ident_name}` to use it as an identifier +parse_invalid_char_in_escape = {parse_invalid_char_in_escape_msg}: `{$ch}` + .label = {parse_invalid_char_in_escape_msg} -parse_sugg_remove_comma = remove this comma -parse_sugg_add_let_for_stmt = you might have meant to introduce a new binding +parse_invalid_char_in_escape_msg = invalid character in {$is_hex -> + [true] numeric character + *[false] unicode + } escape -parse_expected_semi_found_reserved_identifier_str = expected `;`, found reserved identifier `{$token}` -parse_expected_semi_found_keyword_str = expected `;`, found keyword `{$token}` -parse_expected_semi_found_reserved_keyword_str = expected `;`, found reserved keyword `{$token}` -parse_expected_semi_found_doc_comment_str = expected `;`, found doc comment `{$token}` -parse_expected_semi_found_str = expected `;`, found `{$token}` +parse_invalid_comparison_operator = invalid comparison operator `{$invalid}` + .use_instead = `{$invalid}` is not a valid comparison operator, use `{$correct}` + .spaceship_operator_invalid = `<=>` is not a valid comparison operator, use `std::cmp::Ordering` -parse_sugg_change_this_to_semi = change this to `;` -parse_sugg_add_semi = add `;` here -parse_label_unexpected_token = unexpected token +parse_invalid_curly_in_let_else = right curly brace `{"}"}` before `else` in a `let...else` statement not allowed +parse_invalid_digit_literal = invalid digit for a base {$base} literal -parse_unmatched_angle_brackets = {$num_extra_brackets -> - [one] unmatched angle bracket - *[other] unmatched angle brackets +parse_invalid_dyn_keyword = invalid `dyn` keyword + .help = `dyn` is only needed at the start of a trait `+`-separated list + .suggestion = remove this keyword + +parse_invalid_expression_in_let_else = a `{$operator}` expression cannot be directly assigned in `let...else` +parse_invalid_float_literal_suffix = invalid suffix `{$suffix}` for float literal + .label = invalid suffix `{$suffix}` + .help = valid suffixes are `f32` and `f64` + +parse_invalid_float_literal_width = invalid width `{$width}` for float literal + .help = valid widths are 32 and 64 + +parse_invalid_identifier_with_leading_number = identifiers cannot start with a number + +parse_invalid_int_literal_width = invalid width `{$width}` for integer literal + .help = valid widths are 8, 16, 32, 64 and 128 + +parse_invalid_interpolated_expression = invalid interpolated expression + +parse_invalid_literal_suffix = suffixes on {$kind} literals are invalid + .label = invalid suffix `{$suffix}` + +parse_invalid_literal_suffix_on_tuple_index = suffixes on a tuple index are invalid + .label = invalid suffix `{$suffix}` + .tuple_exception_line_1 = `{$suffix}` is *temporarily* accepted on tuple index fields as it was incorrectly accepted on stable for a few releases + .tuple_exception_line_2 = on proc macros, you'll want to use `syn::Index::from` or `proc_macro::Literal::*_unsuffixed` for code that will desugar to tuple field access + .tuple_exception_line_3 = see issue #60210 <https://github.com/rust-lang/rust/issues/60210> for more information + +parse_invalid_logical_operator = `{$incorrect}` is not a logical operator + .note = unlike in e.g., Python and PHP, `&&` and `||` are used for logical operators + .use_amp_amp_for_conjunction = use `&&` to perform logical conjunction + .use_pipe_pipe_for_disjunction = use `||` to perform logical disjunction + +parse_invalid_meta_item = expected unsuffixed literal or identifier, found `{$token}` + +parse_invalid_num_literal_base_prefix = invalid base prefix for number literal + .note = base prefixes (`0xff`, `0b1010`, `0o755`) are lowercase + .suggestion = try making the prefix lowercase + +parse_invalid_num_literal_suffix = invalid suffix `{$suffix}` for number literal + .label = invalid suffix `{$suffix}` + .help = the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.) + +parse_invalid_unicode_escape = invalid unicode character escape + .label = invalid escape + .help = unicode escape must {$surrogate -> + [true] not be a surrogate + *[false] be at most 10FFFF } - .suggestion = {$num_extra_brackets -> - [one] remove extra angle bracket - *[other] remove extra angle brackets - } -parse_generic_parameters_without_angle_brackets = generic parameters without surrounding angle brackets - .suggestion = surround the type parameters with angle brackets +parse_invalid_variable_declaration = + invalid variable declaration -parse_comparison_operators_cannot_be_chained = comparison operators cannot be chained - .sugg_parentheses_for_function_args = or use `(...)` if you meant to specify fn arguments - .sugg_split_comparison = split the comparison into two - .sugg_parenthesize = parenthesize the comparison -parse_sugg_turbofish_syntax = use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments +parse_kw_bad_case = keyword `{$kw}` is written in the wrong case + .suggestion = write it in the correct case -parse_question_mark_in_type = invalid `?` in type - .label = `?` is only allowed on expressions, not types - .suggestion = if you meant to express that the type might not contain a value, use the `Option` wrapper type +parse_label_inner_attr_does_not_annotate_this = the inner attribute doesn't annotate this {$item} +parse_label_unexpected_token = unexpected token -parse_unexpected_parentheses_in_for_head = unexpected parentheses surrounding `for` loop head - .suggestion = remove parentheses in `for` loop +parse_label_while_parsing_or_pattern_here = while parsing this or-pattern starting here -parse_doc_comment_on_param_type = documentation comments cannot be applied to a function parameter's type - .label = doc comments are not allowed here +parse_labeled_loop_in_break = parentheses are required around this expression to avoid confusion with a labeled break expression -parse_attribute_on_param_type = attributes cannot be applied to a function parameter's type - .label = attributes are not allowed here +parse_leading_plus_not_supported = leading `+` is not supported + .label = unexpected `+` + .suggestion_remove_plus = try removing the `+` -parse_pattern_method_param_without_body = patterns aren't allowed in methods without bodies - .suggestion = give this argument a name or use an underscore to ignore it +parse_leading_underscore_unicode_escape = {parse_leading_underscore_unicode_escape_label}: `_` +parse_leading_underscore_unicode_escape_label = invalid start of unicode escape -parse_self_param_not_first = unexpected `self` parameter in function - .label = must be the first parameter of an associated function +parse_left_arrow_operator = unexpected token: `<-` + .suggestion = if you meant to write a comparison against a negative value, add a space in between `<` and `-` -parse_const_generic_without_braces = expressions must be enclosed in braces to be used as const generic arguments - .suggestion = enclose the `const` expression in braces +parse_lifetime_after_mut = lifetime must precede `mut` + .suggestion = place the lifetime before `mut` -parse_unexpected_const_param_declaration = unexpected `const` parameter declaration - .label = expected a `const` expression, not a parameter declaration - .suggestion = `const` parameters must be declared for the `impl` +parse_lifetime_in_borrow_expression = borrow expressions cannot be annotated with lifetimes + .suggestion = remove the lifetime annotation + .label = annotated with lifetime here -parse_unexpected_const_in_generic_param = expected lifetime, type, or constant, found keyword `const` - .suggestion = the `const` keyword is only needed in the definition of the type +parse_lone_slash = invalid trailing slash in literal + .label = {parse_lone_slash} -parse_async_move_order_incorrect = the order of `move` and `async` is incorrect - .suggestion = try switching the order +parse_loop_else = `{$loop_kind}...else` loops are not supported + .note = consider moving this `else` clause to a separate `if` statement and use a `bool` variable to control if it should run + .loop_keyword = `else` is attached to this loop -parse_double_colon_in_bound = expected `:` followed by trait or lifetime - .suggestion = use single colon +parse_macro_invocation_visibility = can't qualify macro invocation with `pub` + .suggestion = remove the visibility + .help = try adjusting the macro to put `{$vis}` inside the invocation -parse_fn_ptr_with_generics = function pointer types may not have generic parameters - .suggestion = consider moving the lifetime {$arity -> - [one] parameter - *[other] parameters - } to {$for_param_list_exists -> - [true] the - *[false] a - } `for` parameter list +parse_macro_invocation_with_qualified_path = macros cannot use qualified paths -parse_invalid_identifier_with_leading_number = identifiers cannot start with a number +parse_macro_name_remove_bang = macro names aren't followed by a `!` + .suggestion = remove the `!` -parse_maybe_fn_typo_with_impl = you might have meant to write `impl` instead of `fn` - .suggestion = replace `fn` with `impl` here +parse_macro_rules_missing_bang = expected `!` after `macro_rules` + .suggestion = add a `!` -parse_expected_fn_path_found_fn_keyword = expected identifier, found keyword `fn` - .suggestion = use `Fn` to refer to the trait +parse_macro_rules_visibility = can't qualify macro_rules invocation with `{$vis}` + .suggestion = try exporting the macro -parse_path_single_colon = path separator must be a double colon - .suggestion = use a double colon instead +parse_malformed_cfg_attr = malformed `cfg_attr` attribute input + .suggestion = missing condition and attribute + .note = for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute> -parse_colon_as_semi = statements are terminated with a semicolon - .suggestion = use a semicolon instead +parse_malformed_loop_label = malformed loop label + .suggestion = use the correct loop label format -parse_type_ascription_removed = - if you meant to annotate an expression with a type, the type ascription syntax has been removed, see issue #101728 <https://github.com/rust-lang/rust/issues/101728> +parse_match_arm_body_without_braces = `match` arm body without braces + .label_statements = {$num_statements -> + [one] this statement is not surrounded by a body + *[other] these statements are not surrounded by a body + } + .label_arrow = while parsing the `match` arm starting here + .suggestion_add_braces = surround the {$num_statements -> + [one] statement + *[other] statements + } with a body + .suggestion_use_comma_not_semicolon = replace `;` with `,` to end a `match` arm expression -parse_where_clause_before_tuple_struct_body = where clauses are not allowed before tuple struct bodies - .label = unexpected where clause - .name_label = while parsing this tuple struct - .body_label = the struct body - .suggestion = move the body before the where clause +parse_maybe_fn_typo_with_impl = you might have meant to write `impl` instead of `fn` + .suggestion = replace `fn` with `impl` here -parse_async_fn_in_2015 = `async fn` is not permitted in Rust 2015 - .label = to use `async fn`, switch to Rust 2018 or later +parse_maybe_recover_from_bad_qpath_stage_2 = + missing angle brackets in associated item path + .suggestion = try: `{$ty}` -parse_async_block_in_2015 = `async` blocks are only allowed in Rust 2018 or later +parse_maybe_recover_from_bad_type_plus = + expected a path on the left-hand side of `+`, not `{$ty}` -parse_self_argument_pointer = cannot pass `self` by raw pointer - .label = cannot pass `self` by raw pointer +parse_maybe_report_ambiguous_plus = + ambiguous `+` in a type + .suggestion = use parentheses to disambiguate -parse_visibility_not_followed_by_item = visibility `{$vis}` is not followed by an item - .label = the visibility - .help = you likely meant to define an item, e.g., `{$vis} fn foo() {"{}"}` +parse_meta_bad_delim = wrong meta list delimiters +parse_meta_bad_delim_suggestion = the delimiters should be `(` and `)` -parse_default_not_followed_by_item = `default` is not followed by an item - .label = the `default` qualifier - .note = only `fn`, `const`, `type`, or `impl` items may be prefixed by `default` +parse_mismatched_closing_delimiter = mismatched closing delimiter: `{$delimiter}` + .label_unmatched = mismatched closing delimiter + .label_opening_candidate = closing delimiter possibly meant for this + .label_unclosed = unclosed delimiter -parse_missing_struct_for_struct_definition = missing `struct` for struct definition - .suggestion = add `struct` here to parse `{$ident}` as a public struct +parse_missing_comma_after_match_arm = expected `,` following `match` arm + .suggestion = missing a comma here to end this `match` arm + +parse_missing_const_type = missing type for `{$kind}` item + .suggestion = provide a type for the item + +parse_missing_expression_in_for_loop = missing expression to iterate on in `for` loop + .suggestion = try adding an expression to the `for` loop parse_missing_fn_for_function_definition = missing `fn` for function definition .suggestion = add `fn` here to parse `{$ident}` as a public function @@ -465,267 +527,275 @@ parse_missing_fn_for_function_definition = missing `fn` for function definition parse_missing_fn_for_method_definition = missing `fn` for method definition .suggestion = add `fn` here to parse `{$ident}` as a public method -parse_ambiguous_missing_keyword_for_item_definition = missing `fn` or `struct` for function or struct definition - .suggestion = if you meant to call a macro, try - .help = if you meant to call a macro, remove the `pub` and add a trailing `!` after the identifier - -parse_missing_trait_in_trait_impl = missing trait in a trait impl - .suggestion_add_trait = add a trait here - .suggestion_remove_for = for an inherent impl, drop this `for` - parse_missing_for_in_trait_impl = missing `for` in a trait impl .suggestion = add `for` here -parse_expected_trait_in_trait_impl_found_type = expected a trait, found type +parse_missing_in_in_for_loop = missing `in` in `for` loop + .use_in_not_of = try using `in` here instead + .add_in = try adding `in` here -parse_extra_impl_keyword_in_trait_impl = unexpected `impl` keyword - .suggestion = remove the extra `impl` - .note = this is parsed as an `impl Trait` type, but a trait is expected at this position +parse_missing_let_before_mut = missing keyword +parse_missing_plus_in_bounds = expected `+` between lifetime and {$sym} + .suggestion = add `+` +parse_missing_semicolon_before_array = expected `;`, found `[` + .suggestion = consider adding `;` here -parse_non_item_in_item_list = non-item in item list - .suggestion_use_const_not_let = consider using `const` instead of `let` for associated const - .label_list_start = item list starts here - .label_non_item = non-item starts here - .label_list_end = item list ends here - .suggestion_remove_semicolon = consider removing this semicolon +parse_missing_struct_for_struct_definition = missing `struct` for struct definition + .suggestion = add `struct` here to parse `{$ident}` as a public struct -parse_bounds_not_allowed_on_trait_aliases = bounds are not allowed on trait aliases +parse_missing_trait_in_trait_impl = missing trait in a trait impl + .suggestion_add_trait = add a trait here + .suggestion_remove_for = for an inherent impl, drop this `for` -parse_trait_alias_cannot_be_auto = trait aliases cannot be `auto` -parse_trait_alias_cannot_be_unsafe = trait aliases cannot be `unsafe` +parse_modifier_lifetime = `{$sigil}` may only modify trait bounds, not lifetime bounds + .suggestion = remove the `{$sigil}` -parse_associated_static_item_not_allowed = associated `static` items are not allowed +parse_more_than_one_char = character literal may only contain one codepoint + .followed_by = this `{$chr}` is followed by the combining {$len -> + [one] mark + *[other] marks + } `{$escaped_marks}` + .non_printing = there are non-printing characters, the full sequence is `{$escaped}` + .consider_normalized = consider using the normalized form `{$ch}` of this character + .remove_non = consider removing the non-printing characters + .use_double_quotes = if you meant to write a {$is_byte -> + [true] byte string + *[false] `str` + } literal, use double quotes -parse_extern_crate_name_with_dashes = crate name using dashes are not valid in `extern crate` statements - .label = dash-separated idents are not valid - .suggestion = if the original crate name uses dashes you need to use underscores in the code +parse_multiple_skipped_lines = multiple lines skipped by escaped newline + .label = skipping everything up to and including this point -parse_extern_item_cannot_be_const = extern items cannot be `const` - .suggestion = try using a static value - .note = for more information, visit https://doc.rust-lang.org/std/keyword.extern.html +parse_multiple_where_clauses = cannot define duplicate `where` clauses on an item + .label = previous `where` clause starts here + .suggestion = consider joining the two `where` clauses into one -parse_const_global_cannot_be_mutable = const globals cannot be mutable - .label = cannot be mutable - .suggestion = you might want to declare a static instead +parse_mut_on_nested_ident_pattern = `mut` must be attached to each individual binding + .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_missing_const_type = missing type for `{$kind}` item - .suggestion = provide a type for the item +parse_nested_adt = `{$kw_str}` definition cannot be nested inside `{$keyword}` + .suggestion = consider creating a new `{$kw_str}` definition instead of nesting -parse_enum_struct_mutually_exclusive = `enum` and `struct` are mutually exclusive - .suggestion = replace `enum struct` with +parse_nested_c_variadic_type = C-variadic type `...` may not be nested inside another type -parse_unexpected_token_after_struct_name = expected `where`, `{"{"}`, `(`, or `;` after struct name -parse_unexpected_token_after_struct_name_found_reserved_identifier = expected `where`, `{"{"}`, `(`, or `;` after struct name, found reserved identifier `{$token}` -parse_unexpected_token_after_struct_name_found_keyword = expected `where`, `{"{"}`, `(`, or `;` after struct name, found keyword `{$token}` -parse_unexpected_token_after_struct_name_found_reserved_keyword = expected `where`, `{"{"}`, `(`, or `;` after struct name, found reserved keyword `{$token}` -parse_unexpected_token_after_struct_name_found_doc_comment = expected `where`, `{"{"}`, `(`, or `;` after struct name, found doc comment `{$token}` -parse_unexpected_token_after_struct_name_found_other = expected `where`, `{"{"}`, `(`, or `;` after struct name, found `{$token}` +parse_no_brace_unicode_escape = incorrect unicode escape sequence + .label = {parse_no_brace_unicode_escape} + .use_braces = format of unicode escape sequences uses braces + .format_of_unicode = format of unicode escape sequences is `\u{"{...}"}` -parse_unexpected_self_in_generic_parameters = unexpected keyword `Self` in generic parameters - .note = you cannot use `Self` as a generic parameter because it is reserved for associated items +parse_no_digits_literal = no valid digits found for number -parse_unexpected_default_value_for_lifetime_in_generic_parameters = unexpected default lifetime parameter - .label = lifetime parameters cannot have default values +parse_non_item_in_item_list = non-item in item list + .suggestion_use_const_not_let = consider using `const` instead of `let` for associated const + .label_list_start = item list starts here + .label_non_item = non-item starts here + .label_list_end = item list ends here + .suggestion_remove_semicolon = consider removing this semicolon -parse_multiple_where_clauses = cannot define duplicate `where` clauses on an item - .label = previous `where` clause starts here - .suggestion = consider joining the two `where` clauses into one +parse_non_string_abi_literal = non-string ABI literal + .suggestion = specify the ABI with a string literal -parse_nonterminal_expected_item_keyword = expected an item keyword -parse_nonterminal_expected_statement = expected a statement parse_nonterminal_expected_ident = expected ident, found `{$token}` +parse_nonterminal_expected_item_keyword = expected an item keyword parse_nonterminal_expected_lifetime = expected a lifetime, found `{$token}` -parse_or_pattern_not_allowed_in_let_binding = top-level or-patterns are not allowed in `let` bindings -parse_or_pattern_not_allowed_in_fn_parameters = top-level or-patterns are not allowed in function parameters -parse_sugg_remove_leading_vert_in_pattern = remove the `|` -parse_sugg_wrap_pattern_in_parens = wrap the pattern in parentheses +parse_nonterminal_expected_statement = expected a statement +parse_not_supported = not supported + +parse_note_edition_guide = for more on editions, read https://doc.rust-lang.org/edition-guide + +parse_note_mut_pattern_usage = `mut` may be followed by `variable` and `variable @ pattern` parse_note_pattern_alternatives_use_single_vert = alternatives in or-patterns are separated with `|`, not `||` -parse_unexpected_vert_vert_before_function_parameter = unexpected `||` before function parameter - .suggestion = remove the `||` +parse_octal_float_literal_not_supported = octal float literal is not supported +parse_or_pattern_not_allowed_in_fn_parameters = top-level or-patterns are not allowed in function parameters +parse_or_pattern_not_allowed_in_let_binding = top-level or-patterns are not allowed in `let` bindings +parse_out_of_range_hex_escape = out of range hex escape + .label = must be a character in the range [\x00-\x7f] -parse_label_while_parsing_or_pattern_here = while parsing this or-pattern starting here +parse_outer_attr_explanation = outer attributes, like `#[test]`, annotate the item following them -parse_unexpected_vert_vert_in_pattern = unexpected token `||` in pattern - .suggestion = use a single `|` to separate multiple alternative patterns +parse_outer_attribute_not_allowed_on_if_else = outer attributes are not allowed on `if` and `else` branches + .branch_label = the attributes are attached to this branch + .ctx_label = the branch belongs to this `{$ctx}` + .suggestion = remove the attributes -parse_trailing_vert_not_allowed = a trailing `|` is not allowed in an or-pattern - .suggestion = remove the `{$token}` +parse_overlong_unicode_escape = overlong unicode escape + .label = must have at most 6 hex digits -parse_dotdotdot_rest_pattern = unexpected `...` - .label = not a valid pattern - .suggestion = for a rest pattern, use `..` instead of `...` +parse_parentheses_with_struct_fields = invalid `struct` delimiters or `fn` call arguments + .suggestion_braces_for_struct = if `{$type}` is a struct, use braces as delimiters + .suggestion_no_fields_for_fn = if `{$type}` is a function, use the arguments directly + +parse_parenthesized_lifetime = parenthesized lifetime bounds are not supported + .suggestion = remove the parentheses + +parse_path_single_colon = path separator must be a double colon + .suggestion = use a double colon instead + +parse_pattern_method_param_without_body = patterns aren't allowed in methods without bodies + .suggestion = give this argument a name or use an underscore to ignore it parse_pattern_on_wrong_side_of_at = pattern on wrong side of `@` .label_pattern = pattern on the left, should be on the right .label_binding = binding on the right, should be on the left .suggestion = switch the order -parse_expected_binding_left_of_at = left-hand side of `@` must be a binding - .label_lhs = interpreted as a pattern, not a binding - .label_rhs = also a pattern - .note = bindings are `x`, `mut x`, `ref x`, and `ref mut x` - -parse_ambiguous_range_pattern = the range pattern here has ambiguous interpretation - .suggestion = add parentheses to clarify the precedence +parse_question_mark_in_type = invalid `?` in type + .label = `?` is only allowed on expressions, not types + .suggestion = if you meant to express that the type might not contain a value, use the `Option` wrapper type -parse_unexpected_lifetime_in_pattern = unexpected lifetime `{$symbol}` in pattern - .suggestion = remove the lifetime +parse_recover_import_as_use = expected item, found {$token_name} + .suggestion = items are imported using the `use` keyword parse_ref_mut_order_incorrect = the order of `mut` and `ref` is incorrect .suggestion = try switching the order -parse_mut_on_nested_ident_pattern = `mut` must be attached to each individual binding - .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_note_mut_pattern_usage = `mut` may be followed by `variable` and `variable @ pattern` +parse_remove_let = expected pattern, found `let` + .suggestion = remove the unnecessary `let` keyword parse_repeated_mut_in_pattern = `mut` on a binding may not be repeated .suggestion = remove the additional `mut`s -parse_dot_dot_dot_range_to_pattern_not_allowed = range-to patterns with `...` are not allowed - .suggestion = use `..=` instead +parse_require_colon_after_labeled_expression = labeled expression must be followed by `:` + .note = labels are used before loops and blocks, allowing e.g., `break 'label` to them + .label = the label + .suggestion = add `:` after the label -parse_enum_pattern_instead_of_identifier = expected identifier, found enum pattern +parse_return_types_use_thin_arrow = return types are denoted using `->` + .suggestion = use `->` instead -parse_dot_dot_dot_for_remaining_fields = expected field pattern, found `{$token_str}` - .suggestion = to omit remaining fields, use `..` +parse_self_argument_pointer = cannot pass `self` by raw pointer + .label = cannot pass `self` by raw pointer -parse_expected_comma_after_pattern_field = expected `,` +parse_self_param_not_first = unexpected `self` parameter in function + .label = must be the first parameter of an associated function -parse_return_types_use_thin_arrow = return types are denoted using `->` - .suggestion = use `->` instead +parse_shift_interpreted_as_generic = + `<<` is interpreted as a start of generic arguments for `{$type}`, not a shift + .label_args = interpreted as generic arguments + .label_comparison = not interpreted as shift + .suggestion = try shifting the cast value -parse_need_plus_after_trait_object_lifetime = lifetime in trait object type must be followed by `+` +parse_single_colon_import_path = expected `::`, found `:` + .suggestion = use double colon + .note = import paths are delimited using `::` -parse_expected_mut_or_const_in_raw_pointer_type = expected `mut` or `const` keyword in raw pointer type - .suggestion = add `mut` or `const` here +parse_single_colon_struct_type = found single colon in a struct field type path + .suggestion = write a path separator here -parse_lifetime_after_mut = lifetime must precede `mut` - .suggestion = place the lifetime before `mut` +parse_struct_literal_body_without_path = + struct literal body without path + .suggestion = you might have forgotten to add the struct literal inside the block -parse_dyn_after_mut = `mut` must precede `dyn` - .suggestion = place `mut` before `dyn` +parse_struct_literal_needing_parens = + invalid struct literal + .suggestion = you might need to surround the struct literal in parentheses -parse_fn_pointer_cannot_be_const = an `fn` pointer type cannot be `const` - .label = `const` because of this - .suggestion = remove the `const` qualifier +parse_struct_literal_not_allowed_here = struct literals are not allowed here + .suggestion = surround the struct literal with parentheses -parse_fn_pointer_cannot_be_async = an `fn` pointer type cannot be `async` - .label = `async` because of this - .suggestion = remove the `async` qualifier +parse_suffixed_literal_in_attribute = suffixed literals are not allowed in attributes + .help = instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.) -parse_nested_c_variadic_type = C-variadic type `...` may not be nested inside another type +parse_sugg_add_let_for_stmt = you might have meant to introduce a new binding -parse_invalid_dyn_keyword = invalid `dyn` keyword - .help = `dyn` is only needed at the start of a trait `+`-separated list - .suggestion = remove this keyword +parse_sugg_add_semi = add `;` here +parse_sugg_change_inner_attr_to_outer = to annotate the {$item}, change the attribute from inner to outer style -parse_help_set_edition_cargo = set `edition = "{$edition}"` in `Cargo.toml` -parse_help_set_edition_standalone = pass `--edition {$edition}` to `rustc` -parse_note_edition_guide = for more on editions, read https://doc.rust-lang.org/edition-guide +parse_sugg_change_this_to_semi = change this to `;` +parse_sugg_escape_identifier = escape `{$ident_name}` to use it as an identifier -parse_unexpected_token_after_dot = unexpected token: `{$actual}` +parse_sugg_remove_comma = remove this comma +parse_sugg_remove_leading_vert_in_pattern = remove the `|` +parse_sugg_turbofish_syntax = use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments -parse_cannot_be_raw_ident = `{$ident}` cannot be a raw identifier +parse_sugg_wrap_expression_in_parentheses = wrap the expression in parentheses -parse_cr_doc_comment = bare CR not allowed in {$block -> - [true] block doc-comment - *[false] doc-comment -} +parse_sugg_wrap_pattern_in_parens = wrap the pattern in parentheses -parse_no_digits_literal = no valid digits found for number +parse_switch_mut_let_order = + switch the order of `mut` and `let` +parse_tilde_const_lifetime = `~const` may only modify trait bounds, not lifetime bounds -parse_invalid_digit_literal = invalid digit for a base {$base} literal +parse_tilde_is_not_unary_operator = `~` cannot be used as a unary operator + .suggestion = use `!` to perform bitwise not -parse_empty_exponent_float = expected at least one digit in exponent +parse_too_many_hashes = too many `#` symbols: raw strings may be delimited by up to 255 `#` symbols, but found {$num} -parse_float_literal_unsupported_base = {$base} float literal is not supported +parse_too_short_hex_escape = numeric character escape is too short -parse_more_than_one_char = character literal may only contain one codepoint - .followed_by = this `{$chr}` is followed by the combining {$len -> - [one] mark - *[other] marks - } `{$escaped_marks}` - .non_printing = there are non-printing characters, the full sequence is `{$escaped}` - .consider_normalized = consider using the normalized form `{$ch}` of this character - .remove_non = consider removing the non-printing characters - .use_double_quotes = if you meant to write a {$is_byte -> - [true] byte string - *[false] `str` - } literal, use double quotes +parse_trailing_vert_not_allowed = a trailing `|` is not allowed in an or-pattern + .suggestion = remove the `{$token}` -parse_no_brace_unicode_escape = incorrect unicode escape sequence - .label = {parse_no_brace_unicode_escape} - .use_braces = format of unicode escape sequences uses braces - .format_of_unicode = format of unicode escape sequences is `\u{"{...}"}` +parse_trait_alias_cannot_be_auto = trait aliases cannot be `auto` +parse_trait_alias_cannot_be_unsafe = trait aliases cannot be `unsafe` -parse_invalid_unicode_escape = invalid unicode character escape - .label = invalid escape - .help = unicode escape must {$surrogate -> - [true] not be a surrogate - *[false] be at most 10FFFF - } +parse_type_ascription_removed = + if you meant to annotate an expression with a type, the type ascription syntax has been removed, see issue #101728 <https://github.com/rust-lang/rust/issues/101728> -parse_escape_only_char = {$byte -> - [true] byte - *[false] character - } constant must be escaped: `{$escaped_msg}` - .escape = escape the character +parse_unclosed_unicode_escape = unterminated unicode escape + .label = missing a closing `{"}"}` + .terminate = terminate the unicode escape -parse_bare_cr = {$double_quotes -> - [true] bare CR not allowed in string, use `\r` instead - *[false] character constant must be escaped: `\r` - } - .escape = escape the character +parse_underscore_literal_suffix = underscore literal suffix is not allowed -parse_bare_cr_in_raw_string = bare CR not allowed in raw string +parse_unexpected_const_in_generic_param = expected lifetime, type, or constant, found keyword `const` + .suggestion = the `const` keyword is only needed in the definition of the type -parse_too_short_hex_escape = numeric character escape is too short +parse_unexpected_const_param_declaration = unexpected `const` parameter declaration + .label = expected a `const` expression, not a parameter declaration + .suggestion = `const` parameters must be declared for the `impl` -parse_invalid_char_in_escape = {parse_invalid_char_in_escape_msg}: `{$ch}` - .label = {parse_invalid_char_in_escape_msg} +parse_unexpected_default_value_for_lifetime_in_generic_parameters = unexpected default lifetime parameter + .label = lifetime parameters cannot have default values -parse_invalid_char_in_escape_msg = invalid character in {$is_hex -> - [true] numeric character - *[false] unicode - } escape +parse_unexpected_if_with_if = unexpected `if` in the condition expression + .suggestion = remove the `if` -parse_out_of_range_hex_escape = out of range hex escape - .label = must be a character in the range [\x00-\x7f] +parse_unexpected_lifetime_in_pattern = unexpected lifetime `{$symbol}` in pattern + .suggestion = remove the lifetime -parse_leading_underscore_unicode_escape = {parse_leading_underscore_unicode_escape_label}: `_` -parse_leading_underscore_unicode_escape_label = invalid start of unicode escape +parse_unexpected_parentheses_in_for_head = unexpected parentheses surrounding `for` loop head + .suggestion = remove parentheses in `for` loop -parse_overlong_unicode_escape = overlong unicode escape - .label = must have at most 6 hex digits +parse_unexpected_self_in_generic_parameters = unexpected keyword `Self` in generic parameters + .note = you cannot use `Self` as a generic parameter because it is reserved for associated items -parse_unclosed_unicode_escape = unterminated unicode escape - .label = missing a closing `{"}"}` - .terminate = terminate the unicode escape +parse_unexpected_token_after_dot = unexpected token: `{$actual}` -parse_unicode_escape_in_byte = unicode escape in byte string - .label = {parse_unicode_escape_in_byte} - .help = unicode escape sequences cannot be used as a byte or in a byte string +parse_unexpected_token_after_label = expected `while`, `for`, `loop` or `{"{"}` after a label + .suggestion_remove_label = consider removing the label + .suggestion_enclose_in_block = consider enclosing expression in a block -parse_empty_unicode_escape = empty unicode escape - .label = this escape must have at least 1 hex digit +parse_unexpected_token_after_not = unexpected {$negated_desc} after identifier +parse_unexpected_token_after_not_bitwise = use `!` to perform bitwise not +parse_unexpected_token_after_not_default = use `!` to perform logical negation or bitwise not -parse_zero_chars = empty character literal - .label = {parse_zero_chars} +parse_unexpected_token_after_not_logical = use `!` to perform logical negation +parse_unexpected_token_after_struct_name = expected `where`, `{"{"}`, `(`, or `;` after struct name +parse_unexpected_token_after_struct_name_found_doc_comment = expected `where`, `{"{"}`, `(`, or `;` after struct name, found doc comment `{$token}` +parse_unexpected_token_after_struct_name_found_keyword = expected `where`, `{"{"}`, `(`, or `;` after struct name, found keyword `{$token}` +parse_unexpected_token_after_struct_name_found_other = expected `where`, `{"{"}`, `(`, or `;` after struct name, found `{$token}` -parse_lone_slash = invalid trailing slash in literal - .label = {parse_lone_slash} +parse_unexpected_token_after_struct_name_found_reserved_identifier = expected `where`, `{"{"}`, `(`, or `;` after struct name, found reserved identifier `{$token}` +parse_unexpected_token_after_struct_name_found_reserved_keyword = expected `where`, `{"{"}`, `(`, or `;` after struct name, found reserved keyword `{$token}` +parse_unexpected_vert_vert_before_function_parameter = unexpected `||` before function parameter + .suggestion = remove the `||` -parse_unskipped_whitespace = whitespace symbol '{$ch}' is not skipped - .label = {parse_unskipped_whitespace} +parse_unexpected_vert_vert_in_pattern = unexpected token `||` in pattern + .suggestion = use a single `|` to separate multiple alternative patterns -parse_multiple_skipped_lines = multiple lines skipped by escaped newline - .label = skipping everything up to and including this point +parse_unicode_escape_in_byte = unicode escape in byte string + .label = {parse_unicode_escape_in_byte} + .help = unicode escape sequences cannot be used as a byte or in a byte string + +parse_unknown_builtin_construct = unknown `builtin #` construct `{$name}` parse_unknown_prefix = prefix `{$prefix}` is unknown .label = unknown prefix @@ -733,8 +803,6 @@ parse_unknown_prefix = prefix `{$prefix}` is unknown .suggestion_br = use `br` for a raw byte string .suggestion_whitespace = consider inserting whitespace here -parse_too_many_hashes = too many `#` symbols: raw strings may be delimited by up to 255 `#` symbols, but found {$num} - parse_unknown_start_of_token = unknown start of token: {$escaped} .sugg_quotes = Unicode characters '“' (Left Double Quotation Mark) and '”' (Right Double Quotation Mark) look like '{$ascii_str}' ({$ascii_name}), but are not .sugg_other = Unicode character '{$ch}' ({$u_name}) looks like '{$ascii_str}' ({$ascii_name}), but it is not @@ -744,94 +812,6 @@ parse_unknown_start_of_token = unknown start of token: {$escaped} *[other] {$repeats} more times } -parse_box_syntax_removed = `box_syntax` has been removed - .suggestion = use `Box::new()` instead - -parse_bad_return_type_notation_output = - return type not allowed with return type notation - .suggestion = remove the return type - -parse_bad_return_type_notation_dotdot = - return type notation uses `()` instead of `(..)` for elided arguments - .suggestion = remove the `..` - -parse_bad_assoc_type_bounds = bounds on associated types do not belong here - .label = belongs in `where` clause - -parse_attr_after_generic = trailing attribute after generic parameter - .label = attributes must go before parameters - -parse_attr_without_generics = attribute without generic parameters - .label = attributes are only permitted when preceding parameters - -parse_where_generics = generic parameters on `where` clauses are reserved for future use - .label = currently unsupported - -parse_generics_in_path = unexpected generic arguments in path - -parse_assoc_lifetime = associated lifetimes are not supported - .label = the lifetime is given here - .help = if you meant to specify a trait object, write `dyn Trait + 'lifetime` - -parse_tilde_const_lifetime = `~const` may only modify trait bounds, not lifetime bounds - -parse_modifier_lifetime = `{$sigil}` may only modify trait bounds, not lifetime bounds - .suggestion = remove the `{$sigil}` - -parse_parenthesized_lifetime = parenthesized lifetime bounds are not supported - .suggestion = remove the parentheses - -parse_const_bounds_missing_tilde = const bounds must start with `~` - .suggestion = add `~` - -parse_underscore_literal_suffix = underscore literal suffix is not allowed - -parse_expect_label_found_ident = expected a label, found an identifier - .suggestion = labels start with a tick - -parse_inappropriate_default = {$article} {$descr} cannot be `default` - .label = `default` because of this - .note = only associated `fn`, `const`, and `type` items can be `default` - -parse_recover_import_as_use = expected item, found {$token_name} - .suggestion = items are imported using the `use` keyword - -parse_single_colon_import_path = expected `::`, found `:` - .suggestion = use double colon - .note = import paths are delimited using `::` - -parse_bad_item_kind = {$descr} is not supported in {$ctx} - .help = consider moving the {$descr} out to a nearby module scope - -parse_single_colon_struct_type = found single colon in a struct field type path - .suggestion = write a path separator here - -parse_equals_struct_default = default values on `struct` fields aren't supported - .suggestion = remove this unsupported default value - -parse_macro_rules_missing_bang = expected `!` after `macro_rules` - .suggestion = add a `!` - -parse_macro_name_remove_bang = macro names aren't followed by a `!` - .suggestion = remove the `!` - -parse_macro_rules_visibility = can't qualify macro_rules invocation with `{$vis}` - .suggestion = try exporting the macro - -parse_macro_invocation_visibility = can't qualify macro invocation with `pub` - .suggestion = remove the visibility - .help = try adjusting the macro to put `{$vis}` inside the invocation - -parse_nested_adt = `{$kw_str}` definition cannot be nested inside `{$keyword}` - .suggestion = consider creating a new `{$kw_str}` definition instead of nesting - -parse_function_body_equals_expr = function body cannot be `= expression;` - .suggestion = surround the expression with `{"{"}` and `{"}"}` instead of `=` and `;` - -parse_box_not_pat = expected pattern, found {$descr} - .note = `box` is a reserved keyword - .suggestion = escape `box` to use it as an identifier - parse_unmatched_angle = unmatched angle {$plural -> [true] brackets *[false] bracket @@ -841,19 +821,39 @@ parse_unmatched_angle = unmatched angle {$plural -> *[false] bracket } -parse_missing_plus_in_bounds = expected `+` between lifetime and {$sym} - .suggestion = add `+` +parse_unmatched_angle_brackets = {$num_extra_brackets -> + [one] unmatched angle bracket + *[other] unmatched angle brackets + } + .suggestion = {$num_extra_brackets -> + [one] remove extra angle bracket + *[other] remove extra angle brackets + } -parse_incorrect_braces_trait_bounds = incorrect braces around trait bounds - .suggestion = remove the parentheses +parse_unskipped_whitespace = whitespace symbol '{$ch}' is not skipped + .label = {parse_unskipped_whitespace} -parse_kw_bad_case = keyword `{$kw}` is written in the wrong case - .suggestion = write it in the correct case +parse_use_empty_block_not_semi = expected { "`{}`" }, found `;` + .suggestion = try using { "`{}`" } instead -parse_meta_bad_delim = wrong meta list delimiters -parse_cfg_attr_bad_delim = wrong `cfg_attr` delimiters -parse_meta_bad_delim_suggestion = the delimiters should be `(` and `)` +parse_use_eq_instead = unexpected `==` + .suggestion = try using `=` instead -parse_malformed_cfg_attr = malformed `cfg_attr` attribute input - .suggestion = missing condition and attribute - .note = for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute> +parse_use_let_not_auto = write `let` instead of `auto` to introduce a new variable +parse_use_let_not_var = write `let` instead of `var` to introduce a new variable + +parse_visibility_not_followed_by_item = visibility `{$vis}` is not followed by an item + .label = the visibility + .help = you likely meant to define an item, e.g., `{$vis} fn foo() {"{}"}` + +parse_where_clause_before_tuple_struct_body = where clauses are not allowed before tuple struct bodies + .label = unexpected where clause + .name_label = while parsing this tuple struct + .body_label = the struct body + .suggestion = move the body before the where clause + +parse_where_generics = generic parameters on `where` clauses are reserved for future use + .label = currently unsupported + +parse_zero_chars = empty character literal + .label = {parse_zero_chars} diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs index cd779b0b43e..8ab38c4fb8b 100644 --- a/compiler/rustc_parse/src/parser/generics.rs +++ b/compiler/rustc_parse/src/parser/generics.rs @@ -43,6 +43,15 @@ impl<'a> Parser<'a> { fn parse_ty_param(&mut self, preceding_attrs: AttrVec) -> PResult<'a, GenericParam> { let ident = self.parse_ident()?; + // We might have a typo'd `Const` that was parsed as a type parameter. + if self.may_recover() + && ident.name.as_str().to_ascii_lowercase() == kw::Const.as_str() + && self.check_ident() + // `Const` followed by IDENT + { + return Ok(self.recover_const_param_with_mistyped_const(preceding_attrs, ident)?); + } + // Parse optional colon and param bounds. let mut colon_span = None; let bounds = if self.eat(&token::Colon) { @@ -120,6 +129,41 @@ impl<'a> Parser<'a> { }) } + pub(crate) fn recover_const_param_with_mistyped_const( + &mut self, + preceding_attrs: AttrVec, + mistyped_const_ident: Ident, + ) -> PResult<'a, GenericParam> { + let ident = self.parse_ident()?; + self.expect(&token::Colon)?; + let ty = self.parse_ty()?; + + // Parse optional const generics default value. + let default = if self.eat(&token::Eq) { Some(self.parse_const_arg()?) } else { None }; + + let mut err = self.struct_span_err( + mistyped_const_ident.span, + format!("`const` keyword was mistyped as `{}`", mistyped_const_ident.as_str()), + ); + err.span_suggestion_verbose( + mistyped_const_ident.span, + "use the `const` keyword", + kw::Const.as_str(), + Applicability::MachineApplicable, + ); + err.emit(); + + Ok(GenericParam { + ident, + id: ast::DUMMY_NODE_ID, + attrs: preceding_attrs, + bounds: Vec::new(), + kind: GenericParamKind::Const { ty, kw_span: mistyped_const_ident.span, default }, + is_placeholder: false, + colon_span: None, + }) + } + /// Parses a (possibly empty) list of lifetime and type parameters, possibly including /// a trailing comma and erroneous trailing attributes. pub(super) fn parse_generic_params(&mut self) -> PResult<'a, ThinVec<ast::GenericParam>> { diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 0c265d7af0e..c23420661fa 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -536,7 +536,9 @@ impl<'a> Parser<'a> { } else if inedible.contains(&self.token.kind) { // leave it in the input Ok(false) - } else if self.last_unexpected_token_span == Some(self.token.span) { + } else if self.token.kind != token::Eof + && self.last_unexpected_token_span == Some(self.token.span) + { FatalError.raise(); } else { self.expected_one_of_not_found(edible, inedible) diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 54f9fc5d2b9..9fcf51a04ec 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -23,6 +23,7 @@ use rustc_errors::{Applicability, DiagnosticBuilder, ErrorGuaranteed, PResult}; use rustc_span::source_map::{BytePos, Span}; use rustc_span::symbol::{kw, sym, Ident}; +use std::borrow::Cow; use std::mem; use thin_vec::{thin_vec, ThinVec}; @@ -364,7 +365,7 @@ impl<'a> Parser<'a> { // `let...else if`. Emit the same error that `parse_block()` would, // but explicitly point out that this pattern is not allowed. let msg = "conditional `else if` is not supported for `let...else`"; - return Err(self.error_block_no_opening_brace_msg(msg)); + return Err(self.error_block_no_opening_brace_msg(Cow::from(msg))); } let els = self.parse_block()?; self.check_let_else_init_bool_expr(&init); @@ -438,7 +439,7 @@ impl<'a> Parser<'a> { fn error_block_no_opening_brace_msg( &mut self, - msg: &str, + msg: Cow<'static, str>, ) -> DiagnosticBuilder<'a, ErrorGuaranteed> { let sp = self.token.span; let mut e = self.struct_span_err(sp, msg); @@ -502,7 +503,7 @@ impl<'a> Parser<'a> { fn error_block_no_opening_brace<T>(&mut self) -> PResult<'a, T> { let tok = super::token_descr(&self.token); let msg = format!("expected `{{`, found {}", tok); - Err(self.error_block_no_opening_brace_msg(&msg)) + Err(self.error_block_no_opening_brace_msg(Cow::from(msg))) } /// Parses a block. Inner attributes are allowed. diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 40680150601..7f9222dac6c 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -4,118 +4,185 @@ -passes_see_issue = see issue #{$issue} <https://github.com/rust-lang/rust/issues/{$issue}> for more information -passes_incorrect_do_not_recommend_location = - `#[do_not_recommend]` can only be placed on trait implementations +passes_abi = + abi: {$abi} -passes_outer_crate_level_attr = - crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` +passes_align = + align: {$align} -passes_inner_crate_level_attr = - crate-level attribute should be in the root module +passes_allow_incoherent_impl = + `rustc_allow_incoherent_impl` attribute should be applied to impl items. + .label = the only currently supported targets are inherent methods -passes_ignored_attr_with_macro = - `#[{$sym}]` is ignored on struct fields, match arms and macro defs - .warn = {-passes_previously_accepted} - .note = {-passes_see_issue(issue: "80564")} +passes_allow_internal_unstable = + attribute should be applied to a macro + .label = not a macro -passes_ignored_attr = - `#[{$sym}]` is ignored on struct fields and match arms - .warn = {-passes_previously_accepted} - .note = {-passes_see_issue(issue: "80564")} +passes_attr_application_enum = + attribute should be applied to an enum + .label = not an enum -passes_inline_ignored_function_prototype = - `#[inline]` is ignored on function prototypes +passes_attr_application_struct = + attribute should be applied to a struct + .label = not a struct -passes_inline_ignored_constants = - `#[inline]` is ignored on constants - .warn = {-passes_previously_accepted} - .note = {-passes_see_issue(issue: "65833")} +passes_attr_application_struct_enum_function_method_union = + attribute should be applied to a struct, enum, function, associated function, or union + .label = not a struct, enum, function, associated function, or union -passes_inline_not_fn_or_closure = - attribute should be applied to function or closure - .label = not a function or closure +passes_attr_application_struct_enum_union = + attribute should be applied to a struct, enum, or union + .label = not a struct, enum, or union -passes_no_coverage_ignored_function_prototype = - `#[no_coverage]` is ignored on function prototypes +passes_attr_application_struct_union = + attribute should be applied to a struct or union + .label = not a struct or union -passes_no_coverage_propagate = - `#[no_coverage]` does not propagate into items and must be applied to the contained functions directly +passes_attr_crate_level = + this attribute can only be applied at the crate level + .suggestion = to apply to the crate, use an inner attribute + .note = read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level> for more information -passes_no_coverage_fn_defn = - `#[no_coverage]` may only be applied to function definitions +passes_attr_only_in_functions = + `{$attr}` attribute can only be used on functions -passes_no_coverage_not_coverable = - `#[no_coverage]` must be applied to coverable code - .label = not coverable code +passes_attr_only_on_main = + `{$attr}` attribute can only be used on `fn main()` -passes_should_be_applied_to_fn = - attribute should be applied to a function definition - .label = {$on_crate -> - [true] cannot be applied to crates - *[false] not a function definition - } +passes_attr_only_on_root_main = + `{$attr}` attribute can only be used on root `fn main()` -passes_naked_tracked_caller = - cannot use `#[track_caller]` with `#[naked]` +passes_both_ffi_const_and_pure = + `#[ffi_const]` function cannot be `#[ffi_pure]` -passes_should_be_applied_to_struct_enum = - attribute should be applied to a struct or enum - .label = not a struct or enum +passes_break_inside_async_block = + `{$name}` inside of an `async` block + .label = cannot `{$name}` inside of an `async` block + .async_block_label = enclosing `async` block -passes_should_be_applied_to_trait = - attribute should be applied to a trait - .label = not a trait +passes_break_inside_closure = + `{$name}` inside of a closure + .label = cannot `{$name}` inside of a closure + .closure_label = enclosing closure -passes_target_feature_on_statement = +passes_break_non_loop = + `break` with value from a `{$kind}` loop + .label = can only break with a value inside `loop` or breakable block + .label2 = you can't `break` with a value in a `{$kind}` loop + .suggestion = use `break` on its own without a value inside this `{$kind}` loop + .break_expr_suggestion = alternatively, you might have meant to use the available loop label + +passes_cannot_inline_naked_function = + naked functions cannot be inlined + +passes_cannot_stabilize_deprecated = + an API can't be stabilized after it is deprecated + .label = invalid version + .item = the stability attribute annotates this item + +passes_change_fields_to_be_of_unit_type = + consider changing the { $num -> + [one] field + *[other] fields + } to be of unit type to suppress this warning while preserving the field numbering, or remove the { $num -> + [one] field + *[other] fields + } + +passes_cold = {passes_should_be_applied_to_fn} .warn = {-passes_previously_accepted} .label = {passes_should_be_applied_to_fn.label} -passes_should_be_applied_to_static = - attribute should be applied to a static - .label = not a static +passes_collapse_debuginfo = + `collapse_debuginfo` attribute should be applied to macro definitions + .label = not a macro definition -passes_doc_expect_str = - doc {$attr_name} attribute expects a string: #[doc({$attr_name} = "a")] +passes_const_impl_const_trait = + const `impl`s must be for traits marked with `#[const_trait]` + .note = this trait must be annotated with `#[const_trait]` -passes_doc_alias_empty = - {$attr_str} attribute cannot have empty value +passes_const_trait = + attribute should be applied to a trait + +passes_continue_labeled_block = + `continue` pointing to a labeled block + .label = labeled blocks cannot be `continue`'d + .block_label = labeled block the `continue` points to + +passes_dead_codes = + { $multiple -> + *[true] multiple {$descr}s are + [false] { $num -> + [one] {$descr} {$name_list} is + *[other] {$descr}s {$name_list} are + } + } never {$participle} + +passes_debug_visualizer_invalid = + invalid argument + .note_1 = expected: `natvis_file = "..."` + .note_2 = OR + .note_3 = expected: `gdb_script_file = "..."` + +passes_debug_visualizer_placement = + attribute should be applied to a module + +passes_debug_visualizer_unreadable = + couldn't read {$file}: {$error} + +passes_deprecated = + attribute is ignored here + +passes_deprecated_annotation_has_no_effect = + this `#[deprecated]` annotation has no effect + .suggestion = remove the unnecessary deprecation attribute + +passes_deprecated_attribute = + deprecated attribute must be paired with either stable or unstable attribute + +passes_diagnostic_item_first_defined = + the diagnostic item is first defined here passes_doc_alias_bad_char = {$char_} character isn't allowed in {$attr_str} -passes_doc_alias_start_end = - {$attr_str} cannot start or end with ' ' - passes_doc_alias_bad_location = {$attr_str} isn't allowed on {$location} -passes_doc_alias_not_an_alias = - {$attr_str} is the same as the item's name - passes_doc_alias_duplicated = doc alias is duplicated .label = first defined here -passes_doc_alias_not_string_literal = - `#[doc(alias("a"))]` expects string literals +passes_doc_alias_empty = + {$attr_str} attribute cannot have empty value passes_doc_alias_malformed = doc alias attribute expects a string `#[doc(alias = "a")]` or a list of strings `#[doc(alias("a", "b"))]` -passes_doc_keyword_empty_mod = - `#[doc(keyword = "...")]` should be used on empty modules +passes_doc_alias_not_an_alias = + {$attr_str} is the same as the item's name -passes_doc_keyword_not_mod = - `#[doc(keyword = "...")]` should be used on modules +passes_doc_alias_not_string_literal = + `#[doc(alias("a"))]` expects string literals -passes_doc_keyword_invalid_ident = - `{$doc_keyword}` is not a valid identifier +passes_doc_alias_start_end = + {$attr_str} cannot start or end with ' ' + +passes_doc_attr_not_crate_level = + `#![doc({$attr_name} = "...")]` isn't allowed as a crate-level attribute + +passes_doc_cfg_hide_takes_list = + `#[doc(cfg_hide(...)]` takes a list of attributes + +passes_doc_expect_str = + doc {$attr_name} attribute expects a string: #[doc({$attr_name} = "a")] passes_doc_fake_variadic_not_valid = `#[doc(fake_variadic)]` must be used on the first of a set of tuple or fn pointer trait impls with varying arity -passes_doc_keyword_only_impl = - `#[doc(keyword = "...")]` should be used on impl blocks +passes_doc_inline_conflict = + conflicting doc inlining attributes + .help = remove one of the conflicting attributes passes_doc_inline_conflict_first = this attribute... @@ -123,383 +190,274 @@ passes_doc_inline_conflict_first = passes_doc_inline_conflict_second = {"."}..conflicts with this attribute -passes_doc_inline_conflict = - conflicting doc inlining attributes - .help = remove one of the conflicting attributes - passes_doc_inline_only_use = this attribute can only be applied to a `use` item .label = only applicable on `use` items .not_a_use_item_label = not a `use` item .note = read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#inline-and-no_inline> for more information -passes_doc_attr_not_crate_level = - `#![doc({$attr_name} = "...")]` isn't allowed as a crate-level attribute +passes_doc_invalid = + invalid `doc` attribute -passes_attr_crate_level = - this attribute can only be applied at the crate level - .suggestion = to apply to the crate, use an inner attribute - .note = read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level> for more information +passes_doc_keyword_empty_mod = + `#[doc(keyword = "...")]` should be used on empty modules -passes_doc_test_unknown = - unknown `doc(test)` attribute `{$path}` +passes_doc_keyword_invalid_ident = + `{$doc_keyword}` is not a valid identifier + +passes_doc_keyword_not_mod = + `#[doc(keyword = "...")]` should be used on modules + +passes_doc_keyword_only_impl = + `#[doc(keyword = "...")]` should be used on impl blocks passes_doc_test_takes_list = `#[doc(test(...)]` takes a list of attributes -passes_doc_cfg_hide_takes_list = - `#[doc(cfg_hide(...)]` takes a list of attributes +passes_doc_test_unknown = + unknown `doc(test)` attribute `{$path}` passes_doc_test_unknown_any = unknown `doc` attribute `{$path}` +passes_doc_test_unknown_include = + unknown `doc` attribute `{$path}` + .suggestion = use `doc = include_str!` instead + passes_doc_test_unknown_spotlight = unknown `doc` attribute `{$path}` .note = `doc(spotlight)` was renamed to `doc(notable_trait)` .suggestion = use `notable_trait` instead .no_op_note = `doc(spotlight)` is now a no-op -passes_doc_test_unknown_include = - unknown `doc` attribute `{$path}` - .suggestion = use `doc = include_str!` instead +passes_duplicate_diagnostic_item_in_crate = + duplicate diagnostic item in crate `{$crate_name}`: `{$name}`. + .note = the diagnostic item is first defined in crate `{$orig_crate_name}`. -passes_doc_invalid = - invalid `doc` attribute +passes_duplicate_feature_err = + the feature `{$feature}` has already been declared -passes_pass_by_value = - `pass_by_value` attribute should be applied to a struct, enum or type alias - .label = is not a struct, enum or type alias +passes_duplicate_lang_item = + found duplicate lang item `{$lang_item_name}` + .first_defined_span = the lang item is first defined here + .first_defined_crate_depends = the lang item is first defined in crate `{$orig_crate_name}` (which `{$orig_dependency_of}` depends on) + .first_defined_crate = the lang item is first defined in crate `{$orig_crate_name}`. + .first_definition_local = first definition in the local crate (`{$orig_crate_name}`) + .second_definition_local = second definition in the local crate (`{$crate_name}`) + .first_definition_path = first definition in `{$orig_crate_name}` loaded from {$orig_path} + .second_definition_path = second definition in `{$crate_name}` loaded from {$path} -passes_allow_incoherent_impl = - `rustc_allow_incoherent_impl` attribute should be applied to impl items. - .label = the only currently supported targets are inherent methods +passes_duplicate_lang_item_crate = + duplicate lang item in crate `{$crate_name}`: `{$lang_item_name}`. + .first_defined_span = the lang item is first defined here + .first_defined_crate_depends = the lang item is first defined in crate `{$orig_crate_name}` (which `{$orig_dependency_of}` depends on) + .first_defined_crate = the lang item is first defined in crate `{$orig_crate_name}`. + .first_definition_local = first definition in the local crate (`{$orig_crate_name}`) + .second_definition_local = second definition in the local crate (`{$crate_name}`) + .first_definition_path = first definition in `{$orig_crate_name}` loaded from {$orig_path} + .second_definition_path = second definition in `{$crate_name}` loaded from {$path} -passes_has_incoherent_inherent_impl = - `rustc_has_incoherent_inherent_impls` attribute should be applied to types or traits. - .label = only adts, extern types and traits are supported +passes_duplicate_lang_item_crate_depends = + duplicate lang item in crate `{$crate_name}` (which `{$dependency_of}` depends on): `{$lang_item_name}`. + .first_defined_span = the lang item is first defined here + .first_defined_crate_depends = the lang item is first defined in crate `{$orig_crate_name}` (which `{$orig_dependency_of}` depends on) + .first_defined_crate = the lang item is first defined in crate `{$orig_crate_name}`. + .first_definition_local = first definition in the local crate (`{$orig_crate_name}`) + .second_definition_local = second definition in the local crate (`{$crate_name}`) + .first_definition_path = first definition in `{$orig_crate_name}` loaded from {$orig_path} + .second_definition_path = second definition in `{$crate_name}` loaded from {$path} -passes_both_ffi_const_and_pure = - `#[ffi_const]` function cannot be `#[ffi_pure]` +passes_export_name = + attribute should be applied to a free function, impl method or static + .label = not a free function, impl method or static -passes_ffi_pure_invalid_target = - `#[ffi_pure]` may only be used on foreign functions +passes_expr_not_allowed_in_context = + {$expr} is not allowed in a `{$context}` + +passes_extern_main = + the `main` function cannot be declared in an `extern` block + +passes_feature_only_on_nightly = + `#![feature]` may not be used on the {$release_channel} release channel + +passes_feature_previously_declared = + feature `{$feature}` is declared {$declared}, but was previously declared {$prev_declared} + +passes_feature_stable_twice = + feature `{$feature}` is declared stable since {$since}, but was previously declared stable since {$prev_since} passes_ffi_const_invalid_target = `#[ffi_const]` may only be used on foreign functions +passes_ffi_pure_invalid_target = + `#[ffi_pure]` may only be used on foreign functions + passes_ffi_returns_twice_invalid_target = `#[ffi_returns_twice]` may only be used on foreign functions -passes_must_use_async = - `must_use` attribute on `async` functions applies to the anonymous `Future` returned by the function, not the value within - .label = this attribute does nothing, the `Future`s returned by async functions are already `must_use` - -passes_must_use_no_effect = - `#[must_use]` has no effect when applied to {$article} {$target} - -passes_must_not_suspend = - `must_not_suspend` attribute should be applied to a struct, enum, or trait - .label = is not a struct, enum, or trait +passes_has_incoherent_inherent_impl = + `rustc_has_incoherent_inherent_impls` attribute should be applied to types or traits. + .label = only adts, extern types and traits are supported -passes_cold = - {passes_should_be_applied_to_fn} - .warn = {-passes_previously_accepted} - .label = {passes_should_be_applied_to_fn.label} +passes_homogeneous_aggregate = + homogeneous_aggregate: {$homogeneous_aggregate} -passes_link = - attribute should be applied to an `extern` block with non-Rust ABI +passes_ignored_attr = + `#[{$sym}]` is ignored on struct fields and match arms .warn = {-passes_previously_accepted} - .label = not an `extern` block + .note = {-passes_see_issue(issue: "80564")} -passes_link_name = - attribute should be applied to a foreign function or static +passes_ignored_attr_with_macro = + `#[{$sym}]` is ignored on struct fields, match arms and macro defs .warn = {-passes_previously_accepted} - .label = not a foreign function or static - .help = try `#[link(name = "{$value}")]` instead - -passes_no_link = - attribute should be applied to an `extern crate` item - .label = not an `extern crate` item - -passes_export_name = - attribute should be applied to a free function, impl method or static - .label = not a free function, impl method or static - -passes_rustc_layout_scalar_valid_range_not_struct = - attribute should be applied to a struct - .label = not a struct + .note = {-passes_see_issue(issue: "80564")} -passes_rustc_layout_scalar_valid_range_arg = - expected exactly one integer literal argument +passes_ignored_derived_impls = + `{$name}` has {$trait_list_len -> + [one] a derived impl + *[other] derived impls + } for the {$trait_list_len -> + [one] trait {$trait_list}, but this is + *[other] traits {$trait_list}, but these are + } intentionally ignored during dead code analysis -passes_rustc_legacy_const_generics_only = - #[rustc_legacy_const_generics] functions must only have const generics - .label = non-const generic parameter +passes_implied_feature_not_exist = + feature `{$implied_by}` implying `{$feature}` does not exist -passes_rustc_legacy_const_generics_index = - #[rustc_legacy_const_generics] must have one index for each generic parameter - .label = generic parameters +passes_incorrect_do_not_recommend_location = + `#[do_not_recommend]` can only be placed on trait implementations -passes_rustc_legacy_const_generics_index_exceed = - index exceeds number of arguments - .label = there {$arg_count -> - [one] is - *[other] are - } only {$arg_count} {$arg_count -> +passes_incorrect_target = + `{$name}` language item must be applied to a {$kind} with {$at_least -> + [true] at least {$num} + *[false] {$num} + } generic {$num -> + [one] argument + *[other] arguments + } + .label = this {$kind} has {$actual_num} generic {$actual_num -> [one] argument *[other] arguments } -passes_rustc_legacy_const_generics_index_negative = - arguments should be non-negative integers - -passes_rustc_dirty_clean = - attribute requires -Z query-dep-graph to be enabled - -passes_link_section = - attribute should be applied to a function or static - .warn = {-passes_previously_accepted} - .label = not a function or static - -passes_no_mangle_foreign = - `#[no_mangle]` has no effect on a foreign {$foreign_item_kind} - .warn = {-passes_previously_accepted} - .label = foreign {$foreign_item_kind} - .note = symbol names in extern blocks are not mangled - .suggestion = remove this attribute +passes_ineffective_unstable_impl = an `#[unstable]` annotation here has no effect + .note = see issue #55436 <https://github.com/rust-lang/rust/issues/55436> for more information -passes_no_mangle = - attribute should be applied to a free function, impl method or static +passes_inline_ignored_constants = + `#[inline]` is ignored on constants .warn = {-passes_previously_accepted} - .label = not a free function, impl method or static - -passes_repr_ident = - meta item in `repr` must be an identifier - -passes_repr_conflicting = - conflicting representation hints - -passes_used_static = - attribute must be applied to a `static` variable - -passes_used_compiler_linker = - `used(compiler)` and `used(linker)` can't be used together - -passes_allow_internal_unstable = - attribute should be applied to a macro - .label = not a macro - -passes_debug_visualizer_placement = - attribute should be applied to a module - -passes_debug_visualizer_invalid = - invalid argument - .note_1 = expected: `natvis_file = "..."` - .note_2 = OR - .note_3 = expected: `gdb_script_file = "..."` - -passes_debug_visualizer_unreadable = - couldn't read {$file}: {$error} - -passes_rustc_allow_const_fn_unstable = - attribute should be applied to `const fn` - .label = not a `const fn` - -passes_rustc_std_internal_symbol = - attribute should be applied to functions or statics - .label = not a function or static - -passes_const_trait = - attribute should be applied to a trait - -passes_stability_promotable = - attribute cannot be applied to an expression - -passes_deprecated = - attribute is ignored here - -passes_macro_use = - `#[{$name}]` only has an effect on `extern crate` and modules - -passes_macro_export = - `#[macro_export]` only has an effect on macro definitions - -passes_plugin_registrar = - `#[plugin_registrar]` only has an effect on functions - -passes_unused_empty_lints_note = - attribute `{$name}` with an empty list has no effect - -passes_unused_no_lints_note = - attribute `{$name}` without any lints has no effect - -passes_unused_default_method_body_const_note = - `default_method_body_is_const` has been replaced with `#[const_trait]` on traits + .note = {-passes_see_issue(issue: "65833")} -passes_unused = - unused attribute - .suggestion = remove this attribute +passes_inline_ignored_function_prototype = + `#[inline]` is ignored on function prototypes -passes_non_exported_macro_invalid_attrs = +passes_inline_not_fn_or_closure = attribute should be applied to function or closure .label = not a function or closure -passes_unused_duplicate = - unused attribute - .suggestion = remove this attribute - .note = attribute also specified here - .warn = {-passes_previously_accepted} - -passes_unused_multiple = - multiple `{$name}` attributes - .suggestion = remove this attribute - .note = attribute also specified here - -passes_rustc_lint_opt_ty = - `#[rustc_lint_opt_ty]` should be applied to a struct - .label = not a struct - -passes_rustc_lint_opt_deny_field_access = - `#[rustc_lint_opt_deny_field_access]` should be applied to a field - .label = not a field - -passes_link_ordinal = - attribute should be applied to a foreign function or static - .label = not a foreign function or static - -passes_collapse_debuginfo = - `collapse_debuginfo` attribute should be applied to macro definitions - .label = not a macro definition - -passes_deprecated_annotation_has_no_effect = - this `#[deprecated]` annotation has no effect - .suggestion = remove the unnecessary deprecation attribute - -passes_unknown_external_lang_item = - unknown external lang item: `{$lang_item}` - -passes_missing_panic_handler = - `#[panic_handler]` function required, but not found - -passes_missing_lang_item = - language item required, but not found: `{$name}` - .note = this can occur when a binary crate with `#![no_std]` is compiled for a target where `{$name}` is defined in the standard library - .help = you may be able to compile for a target that doesn't need `{$name}`, specify a target with `--target` or in `.cargo/config` - -passes_lang_item_on_incorrect_target = - `{$name}` language item must be applied to a {$expected_target} - .label = attribute should be applied to a {$expected_target}, not a {$actual_target} - -passes_unknown_lang_item = - definition of an unknown language item: `{$name}` - .label = definition of unknown language item `{$name}` +passes_inner_crate_level_attr = + crate-level attribute should be in the root module passes_invalid_attr_at_crate_level = `{$name}` attribute cannot be used at crate level .suggestion = perhaps you meant to use an outer attribute -passes_duplicate_diagnostic_item_in_crate = - duplicate diagnostic item in crate `{$crate_name}`: `{$name}`. - .note = the diagnostic item is first defined in crate `{$orig_crate_name}`. +passes_invalid_deprecation_version = + invalid deprecation version found + .label = invalid deprecation version + .item = the stability attribute annotates this item -passes_diagnostic_item_first_defined = - the diagnostic item is first defined here +passes_invalid_macro_export_arguments = `{$name}` isn't a valid `#[macro_export]` argument -passes_abi = - abi: {$abi} +passes_invalid_macro_export_arguments_too_many_items = `#[macro_export]` can only take 1 or 0 arguments -passes_align = - align: {$align} +passes_invalid_stability = + invalid stability version found + .label = invalid stability version + .item = the stability attribute annotates this item -passes_size = - size: {$size} +passes_lang_item_on_incorrect_target = + `{$name}` language item must be applied to a {$expected_target} + .label = attribute should be applied to a {$expected_target}, not a {$actual_target} -passes_homogeneous_aggregate = - homogeneous_aggregate: {$homogeneous_aggregate} +passes_layout = + layout error: {$layout_error} passes_layout_of = layout_of({$normalized_ty}) = {$ty_layout} -passes_unrecognized_field = - unrecognized field name `{$name}` - -passes_layout = - layout error: {$layout_error} +passes_link = + attribute should be applied to an `extern` block with non-Rust ABI + .warn = {-passes_previously_accepted} + .label = not an `extern` block -passes_feature_stable_twice = - feature `{$feature}` is declared stable since {$since}, but was previously declared stable since {$prev_since} +passes_link_name = + attribute should be applied to a foreign function or static + .warn = {-passes_previously_accepted} + .label = not a foreign function or static + .help = try `#[link(name = "{$value}")]` instead -passes_feature_previously_declared = - feature `{$feature}` is declared {$declared}, but was previously declared {$prev_declared} +passes_link_ordinal = + attribute should be applied to a foreign function or static + .label = not a foreign function or static -passes_expr_not_allowed_in_context = - {$expr} is not allowed in a `{$context}` +passes_link_section = + attribute should be applied to a function or static + .warn = {-passes_previously_accepted} + .label = not a function or static -passes_const_impl_const_trait = - const `impl`s must be for traits marked with `#[const_trait]` - .note = this trait must be annotated with `#[const_trait]` +passes_macro_export = + `#[macro_export]` only has an effect on macro definitions -passes_break_non_loop = - `break` with value from a `{$kind}` loop - .label = can only break with a value inside `loop` or breakable block - .label2 = you can't `break` with a value in a `{$kind}` loop - .suggestion = use `break` on its own without a value inside this `{$kind}` loop - .break_expr_suggestion = alternatively, you might have meant to use the available loop label +passes_macro_use = + `#[{$name}]` only has an effect on `extern crate` and modules -passes_continue_labeled_block = - `continue` pointing to a labeled block - .label = labeled blocks cannot be `continue`'d - .block_label = labeled block the `continue` points to +passes_maybe_string_interpolation = you might have meant to use string interpolation in this string literal +passes_missing_const_err = + attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const` + .help = make the function or method const + .label = attribute specified here -passes_break_inside_closure = - `{$name}` inside of a closure - .label = cannot `{$name}` inside of a closure - .closure_label = enclosing closure +passes_missing_const_stab_attr = + {$descr} has missing const stability attribute -passes_break_inside_async_block = - `{$name}` inside of an `async` block - .label = cannot `{$name}` inside of an `async` block - .async_block_label = enclosing `async` block +passes_missing_lang_item = + language item required, but not found: `{$name}` + .note = this can occur when a binary crate with `#![no_std]` is compiled for a target where `{$name}` is defined in the standard library + .help = you may be able to compile for a target that doesn't need `{$name}`, specify a target with `--target` or in `.cargo/config` -passes_outside_loop = - `{$name}` outside of a loop{$is_break -> - [true] {" or labeled block"} - *[false] {""} - } - .label = cannot `{$name}` outside of a loop{$is_break -> - [true] {" or labeled block"} - *[false] {""} - } +passes_missing_panic_handler = + `#[panic_handler]` function required, but not found -passes_unlabeled_in_labeled_block = - unlabeled `{$cf_type}` inside of a labeled block - .label = `{$cf_type}` statements that would diverge to or through a labeled block need to bear a label +passes_missing_stability_attr = + {$descr} has missing stability attribute -passes_unlabeled_cf_in_while_condition = - `break` or `continue` with no label in the condition of a `while` loop - .label = unlabeled `{$cf_type}` in the condition of a `while` loop +passes_multiple_rustc_main = + multiple functions with a `#[rustc_main]` attribute + .first = first `#[rustc_main]` function + .additional = additional `#[rustc_main]` function -passes_cannot_inline_naked_function = - naked functions cannot be inlined +passes_multiple_start_functions = + multiple `start` functions + .label = multiple `start` functions + .previous = previous `#[start]` function here -passes_undefined_naked_function_abi = - Rust ABI is unsupported in naked functions +passes_must_not_suspend = + `must_not_suspend` attribute should be applied to a struct, enum, or trait + .label = is not a struct, enum, or trait -passes_no_patterns = - patterns not allowed in naked function parameters +passes_must_use_async = + `must_use` attribute on `async` functions applies to the anonymous `Future` returned by the function, not the value within + .label = this attribute does nothing, the `Future`s returned by async functions are already `must_use` -passes_params_not_allowed = - referencing function parameters is not allowed in naked functions - .help = follow the calling convention in asm block to use parameters +passes_must_use_no_effect = + `#[must_use]` has no effect when applied to {$article} {$target} passes_naked_functions_asm_block = naked functions must contain a single asm block .label_multiple_asm = multiple asm blocks are unsupported in naked functions .label_non_asm = non-asm is unsupported in naked functions -passes_naked_functions_operands = - only `const` and `sym` operands are supported in naked functions - passes_naked_functions_asm_options = asm options unsupported in naked functions: {$unsupported_options} @@ -507,30 +465,28 @@ passes_naked_functions_must_use_noreturn = asm in naked functions must use `noreturn` option .suggestion = consider specifying that the asm block is responsible for returning from the function -passes_attr_only_on_main = - `{$attr}` attribute can only be used on `fn main()` +passes_naked_functions_operands = + only `const` and `sym` operands are supported in naked functions -passes_attr_only_on_root_main = - `{$attr}` attribute can only be used on root `fn main()` +passes_naked_tracked_caller = + cannot use `#[track_caller]` with `#[naked]` -passes_attr_only_in_functions = - `{$attr}` attribute can only be used on functions +passes_no_coverage_fn_defn = + `#[no_coverage]` may only be applied to function definitions -passes_multiple_rustc_main = - multiple functions with a `#[rustc_main]` attribute - .first = first `#[rustc_main]` function - .additional = additional `#[rustc_main]` function +passes_no_coverage_ignored_function_prototype = + `#[no_coverage]` is ignored on function prototypes -passes_multiple_start_functions = - multiple `start` functions - .label = multiple `start` functions - .previous = previous `#[start]` function here +passes_no_coverage_not_coverable = + `#[no_coverage]` must be applied to coverable code + .label = not coverable code -passes_extern_main = - the `main` function cannot be declared in an `extern` block +passes_no_coverage_propagate = + `#[no_coverage]` does not propagate into items and must be applied to the contained functions directly -passes_unix_sigpipe_values = - valid values for `#[unix_sigpipe = "..."]` are `inherit`, `sig_ign`, or `sig_dfl` +passes_no_link = + attribute should be applied to an `extern crate` item + .label = not an `extern crate` item passes_no_main_function = `main` function not found in crate `{$crate_name}` @@ -546,54 +502,27 @@ passes_no_main_function = .teach_note = If you don't know the basics of Rust, you can go look to the Rust Book to get started: https://doc.rust-lang.org/book/ .non_function_main = non-function item at `crate::main` is found -passes_duplicate_lang_item = - found duplicate lang item `{$lang_item_name}` - .first_defined_span = the lang item is first defined here - .first_defined_crate_depends = the lang item is first defined in crate `{$orig_crate_name}` (which `{$orig_dependency_of}` depends on) - .first_defined_crate = the lang item is first defined in crate `{$orig_crate_name}`. - .first_definition_local = first definition in the local crate (`{$orig_crate_name}`) - .second_definition_local = second definition in the local crate (`{$crate_name}`) - .first_definition_path = first definition in `{$orig_crate_name}` loaded from {$orig_path} - .second_definition_path = second definition in `{$crate_name}` loaded from {$path} +passes_no_mangle = + attribute should be applied to a free function, impl method or static + .warn = {-passes_previously_accepted} + .label = not a free function, impl method or static -passes_duplicate_lang_item_crate = - duplicate lang item in crate `{$crate_name}`: `{$lang_item_name}`. - .first_defined_span = the lang item is first defined here - .first_defined_crate_depends = the lang item is first defined in crate `{$orig_crate_name}` (which `{$orig_dependency_of}` depends on) - .first_defined_crate = the lang item is first defined in crate `{$orig_crate_name}`. - .first_definition_local = first definition in the local crate (`{$orig_crate_name}`) - .second_definition_local = second definition in the local crate (`{$crate_name}`) - .first_definition_path = first definition in `{$orig_crate_name}` loaded from {$orig_path} - .second_definition_path = second definition in `{$crate_name}` loaded from {$path} +passes_no_mangle_foreign = + `#[no_mangle]` has no effect on a foreign {$foreign_item_kind} + .warn = {-passes_previously_accepted} + .label = foreign {$foreign_item_kind} + .note = symbol names in extern blocks are not mangled + .suggestion = remove this attribute -passes_duplicate_lang_item_crate_depends = - duplicate lang item in crate `{$crate_name}` (which `{$dependency_of}` depends on): `{$lang_item_name}`. - .first_defined_span = the lang item is first defined here - .first_defined_crate_depends = the lang item is first defined in crate `{$orig_crate_name}` (which `{$orig_dependency_of}` depends on) - .first_defined_crate = the lang item is first defined in crate `{$orig_crate_name}`. - .first_definition_local = first definition in the local crate (`{$orig_crate_name}`) - .second_definition_local = second definition in the local crate (`{$crate_name}`) - .first_definition_path = first definition in `{$orig_crate_name}` loaded from {$orig_path} - .second_definition_path = second definition in `{$crate_name}` loaded from {$path} +passes_no_patterns = + patterns not allowed in naked function parameters -passes_incorrect_target = - `{$name}` language item must be applied to a {$kind} with {$at_least -> - [true] at least {$num} - *[false] {$num} - } generic {$num -> - [one] argument - *[other] arguments - } - .label = this {$kind} has {$actual_num} generic {$actual_num -> - [one] argument - *[other] arguments - } +passes_non_exported_macro_invalid_attrs = + attribute should be applied to function or closure + .label = not a function or closure -passes_useless_assignment = - useless assignment of {$is_field_assign -> - [true] field - *[false] variable - } of type `{$ty}` to itself +passes_object_lifetime_err = + {$repr} passes_only_has_effect_on = `#[{$attr_name}]` only has an effect on {$target_name -> @@ -603,165 +532,236 @@ passes_only_has_effect_on = *[unspecified] (unspecified--this is a compiler bug) } -passes_object_lifetime_err = - {$repr} +passes_outer_crate_level_attr = + crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` -passes_unrecognized_repr_hint = - unrecognized representation hint - .help = valid reprs are `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize` +passes_outside_loop = + `{$name}` outside of a loop{$is_break -> + [true] {" or labeled block"} + *[false] {""} + } + .label = cannot `{$name}` outside of a loop{$is_break -> + [true] {" or labeled block"} + *[false] {""} + } -passes_attr_application_enum = - attribute should be applied to an enum - .label = not an enum +passes_params_not_allowed = + referencing function parameters is not allowed in naked functions + .help = follow the calling convention in asm block to use parameters -passes_attr_application_struct = +passes_parent_info = + {$num -> + [one] {$descr} + *[other] {$descr}s + } in this {$parent_descr} + +passes_pass_by_value = + `pass_by_value` attribute should be applied to a struct, enum or type alias + .label = is not a struct, enum or type alias + +passes_plugin_registrar = + `#[plugin_registrar]` only has an effect on functions + +passes_proc_macro_bad_sig = {$kind} has incorrect signature + +passes_repr_conflicting = + conflicting representation hints + +passes_repr_ident = + meta item in `repr` must be an identifier + +passes_rustc_allow_const_fn_unstable = + attribute should be applied to `const fn` + .label = not a `const fn` + +passes_rustc_dirty_clean = + attribute requires -Z query-dep-graph to be enabled + +passes_rustc_layout_scalar_valid_range_arg = + expected exactly one integer literal argument + +passes_rustc_layout_scalar_valid_range_not_struct = attribute should be applied to a struct .label = not a struct -passes_attr_application_struct_union = - attribute should be applied to a struct or union - .label = not a struct or union +passes_rustc_legacy_const_generics_index = + #[rustc_legacy_const_generics] must have one index for each generic parameter + .label = generic parameters -passes_attr_application_struct_enum_union = - attribute should be applied to a struct, enum, or union - .label = not a struct, enum, or union +passes_rustc_legacy_const_generics_index_exceed = + index exceeds number of arguments + .label = there {$arg_count -> + [one] is + *[other] are + } only {$arg_count} {$arg_count -> + [one] argument + *[other] arguments + } -passes_attr_application_struct_enum_function_method_union = - attribute should be applied to a struct, enum, function, associated function, or union - .label = not a struct, enum, function, associated function, or union +passes_rustc_legacy_const_generics_index_negative = + arguments should be non-negative integers -passes_transparent_incompatible = - transparent {$target} cannot have other repr hints +passes_rustc_legacy_const_generics_only = + #[rustc_legacy_const_generics] functions must only have const generics + .label = non-const generic parameter -passes_deprecated_attribute = - deprecated attribute must be paired with either stable or unstable attribute +passes_rustc_lint_opt_deny_field_access = + `#[rustc_lint_opt_deny_field_access]` should be applied to a field + .label = not a field -passes_useless_stability = - this stability annotation is useless - .label = useless stability annotation - .item = the stability attribute annotates this item +passes_rustc_lint_opt_ty = + `#[rustc_lint_opt_ty]` should be applied to a struct + .label = not a struct -passes_invalid_stability = - invalid stability version found - .label = invalid stability version - .item = the stability attribute annotates this item +passes_rustc_std_internal_symbol = + attribute should be applied to functions or statics + .label = not a function or static -passes_cannot_stabilize_deprecated = - an API can't be stabilized after it is deprecated - .label = invalid version - .item = the stability attribute annotates this item +passes_should_be_applied_to_fn = + attribute should be applied to a function definition + .label = {$on_crate -> + [true] cannot be applied to crates + *[false] not a function definition + } -passes_invalid_deprecation_version = - invalid deprecation version found - .label = invalid deprecation version - .item = the stability attribute annotates this item +passes_should_be_applied_to_static = + attribute should be applied to a static + .label = not a static -passes_missing_stability_attr = - {$descr} has missing stability attribute +passes_should_be_applied_to_struct_enum = + attribute should be applied to a struct or enum + .label = not a struct or enum -passes_missing_const_stab_attr = - {$descr} has missing const stability attribute +passes_should_be_applied_to_trait = + attribute should be applied to a trait + .label = not a trait -passes_trait_impl_const_stable = - trait implementations cannot be const stable yet - .note = see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information +passes_size = + size: {$size} -passes_feature_only_on_nightly = - `#![feature]` may not be used on the {$release_channel} release channel +passes_skipping_const_checks = skipping const checks -passes_unknown_feature = - unknown feature `{$feature}` +passes_stability_promotable = + attribute cannot be applied to an expression -passes_implied_feature_not_exist = - feature `{$implied_by}` implying `{$feature}` does not exist +passes_string_interpolation_only_works = string interpolation only works in `format!` invocations -passes_duplicate_feature_err = - the feature `{$feature}` has already been declared +passes_target_feature_on_statement = + {passes_should_be_applied_to_fn} + .warn = {-passes_previously_accepted} + .label = {passes_should_be_applied_to_fn.label} -passes_missing_const_err = - attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const` - .help = make the function or method const - .label = attribute specified here +passes_trait_impl_const_stable = + trait implementations cannot be const stable yet + .note = see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information -passes_dead_codes = - { $multiple -> - *[true] multiple {$descr}s are - [false] { $num -> - [one] {$descr} {$name_list} is - *[other] {$descr}s {$name_list} are - } - } never {$participle} +passes_transparent_incompatible = + transparent {$target} cannot have other repr hints -passes_change_fields_to_be_of_unit_type = - consider changing the { $num -> - [one] field - *[other] fields - } to be of unit type to suppress this warning while preserving the field numbering, or remove the { $num -> - [one] field - *[other] fields - } +passes_undefined_naked_function_abi = + Rust ABI is unsupported in naked functions -passes_parent_info = - {$num -> - [one] {$descr} - *[other] {$descr}s - } in this {$parent_descr} +passes_unix_sigpipe_values = + valid values for `#[unix_sigpipe = "..."]` are `inherit`, `sig_ign`, or `sig_dfl` -passes_ignored_derived_impls = - `{$name}` has {$trait_list_len -> - [one] a derived impl - *[other] derived impls - } for the {$trait_list_len -> - [one] trait {$trait_list}, but this is - *[other] traits {$trait_list}, but these are - } intentionally ignored during dead code analysis +passes_unknown_external_lang_item = + unknown external lang item: `{$lang_item}` -passes_proc_macro_bad_sig = {$kind} has incorrect signature +passes_unknown_feature = + unknown feature `{$feature}` -passes_skipping_const_checks = skipping const checks +passes_unknown_lang_item = + definition of an unknown language item: `{$name}` + .label = definition of unknown language item `{$name}` -passes_invalid_macro_export_arguments = `{$name}` isn't a valid `#[macro_export]` argument +passes_unlabeled_cf_in_while_condition = + `break` or `continue` with no label in the condition of a `while` loop + .label = unlabeled `{$cf_type}` in the condition of a `while` loop -passes_invalid_macro_export_arguments_too_many_items = `#[macro_export]` can only take 1 or 0 arguments +passes_unlabeled_in_labeled_block = + unlabeled `{$cf_type}` inside of a labeled block + .label = `{$cf_type}` statements that would diverge to or through a labeled block need to bear a label + +passes_unnecessary_partial_stable_feature = the feature `{$feature}` has been partially stabilized since {$since} and is succeeded by the feature `{$implies}` + .suggestion = if you are using features which are still unstable, change to using `{$implies}` + .suggestion_remove = if you are using features which are now stable, remove this line + +passes_unnecessary_stable_feature = the feature `{$feature}` has been stable since {$since} and no longer requires an attribute to enable passes_unreachable_due_to_uninhabited = unreachable {$descr} .label = unreachable {$descr} .label_orig = any code following this expression is unreachable .note = this expression has type `{$ty}`, which is uninhabited -passes_unused_var_maybe_capture_ref = unused variable: `{$name}` - .help = did you mean to capture by reference instead? +passes_unrecognized_field = + unrecognized field name `{$name}` + +passes_unrecognized_repr_hint = + unrecognized representation hint + .help = valid reprs are `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize` + +passes_unused = + unused attribute + .suggestion = remove this attribute + +passes_unused_assign = value assigned to `{$name}` is never read + .help = maybe it is overwritten before being read? + +passes_unused_assign_passed = value passed to `{$name}` is never read + .help = maybe it is overwritten before being read? passes_unused_capture_maybe_capture_ref = value captured by `{$name}` is never read .help = did you mean to capture by reference instead? -passes_unused_var_remove_field = unused variable: `{$name}` -passes_unused_var_remove_field_suggestion = try removing the field +passes_unused_default_method_body_const_note = + `default_method_body_is_const` has been replaced with `#[const_trait]` on traits -passes_unused_var_assigned_only = variable `{$name}` is assigned to, but never used - .note = consider using `_{$name}` instead +passes_unused_duplicate = + unused attribute + .suggestion = remove this attribute + .note = attribute also specified here + .warn = {-passes_previously_accepted} -passes_unnecessary_stable_feature = the feature `{$feature}` has been stable since {$since} and no longer requires an attribute to enable +passes_unused_empty_lints_note = + attribute `{$name}` with an empty list has no effect -passes_unnecessary_partial_stable_feature = the feature `{$feature}` has been partially stabilized since {$since} and is succeeded by the feature `{$implies}` - .suggestion = if you are using features which are still unstable, change to using `{$implies}` - .suggestion_remove = if you are using features which are now stable, remove this line +passes_unused_multiple = + multiple `{$name}` attributes + .suggestion = remove this attribute + .note = attribute also specified here -passes_ineffective_unstable_impl = an `#[unstable]` annotation here has no effect - .note = see issue #55436 <https://github.com/rust-lang/rust/issues/55436> for more information +passes_unused_no_lints_note = + attribute `{$name}` without any lints has no effect -passes_unused_assign = value assigned to `{$name}` is never read - .help = maybe it is overwritten before being read? +passes_unused_var_assigned_only = variable `{$name}` is assigned to, but never used + .note = consider using `_{$name}` instead -passes_unused_assign_passed = value passed to `{$name}` is never read - .help = maybe it is overwritten before being read? +passes_unused_var_maybe_capture_ref = unused variable: `{$name}` + .help = did you mean to capture by reference instead? -passes_maybe_string_interpolation = you might have meant to use string interpolation in this string literal -passes_string_interpolation_only_works = string interpolation only works in `format!` invocations +passes_unused_var_remove_field = unused variable: `{$name}` +passes_unused_var_remove_field_suggestion = try removing the field + +passes_unused_variable_try_ignore = unused variable: `{$name}` + .suggestion = try ignoring the field passes_unused_variable_try_prefix = unused variable: `{$name}` .label = unused variable .suggestion = if this is intentional, prefix it with an underscore -passes_unused_variable_try_ignore = unused variable: `{$name}` - .suggestion = try ignoring the field +passes_used_compiler_linker = + `used(compiler)` and `used(linker)` can't be used together + +passes_used_static = + attribute must be applied to a `static` variable + +passes_useless_assignment = + useless assignment of {$is_field_assign -> + [true] field + *[false] variable + } of type `{$ty}` to itself + +passes_useless_stability = + this stability annotation is useless + .label = useless stability annotation + .item = the stability attribute annotates this item diff --git a/compiler/rustc_privacy/messages.ftl b/compiler/rustc_privacy/messages.ftl index a26d1b2b381..b68e8a78aab 100644 --- a/compiler/rustc_privacy/messages.ftl +++ b/compiler/rustc_privacy/messages.ftl @@ -2,22 +2,22 @@ privacy_field_is_private = field `{$field_name}` of {$variant_descr} `{$def_path privacy_field_is_private_is_update_syntax_label = field `{$field_name}` is private privacy_field_is_private_label = private field -privacy_item_is_private = {$kind} `{$descr}` is private - .label = private {$kind} -privacy_unnamed_item_is_private = {$kind} is private - .label = private {$kind} +privacy_from_private_dep_in_public_interface = + {$kind} `{$descr}` from private dependency '{$krate}' in public interface privacy_in_public_interface = {$vis_descr} {$kind} `{$descr}` in public interface .label = can't leak {$vis_descr} {$kind} .visibility_label = `{$descr}` declared as {$vis_descr} -privacy_report_effective_visibility = {$descr} - -privacy_from_private_dep_in_public_interface = - {$kind} `{$descr}` from private dependency '{$krate}' in public interface - +privacy_item_is_private = {$kind} `{$descr}` is private + .label = private {$kind} privacy_private_in_public_lint = {$vis_descr} {$kind} `{$descr}` in public interface (error {$kind -> [trait] E0445 *[other] E0446 }) + +privacy_report_effective_visibility = {$descr} + +privacy_unnamed_item_is_private = {$kind} is private + .label = private {$kind} diff --git a/compiler/rustc_query_impl/Cargo.toml b/compiler/rustc_query_impl/Cargo.toml index e596993465c..c9353b6fc9f 100644 --- a/compiler/rustc_query_impl/Cargo.toml +++ b/compiler/rustc_query_impl/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" [dependencies] -memoffset = { version = "0.6.0", features = ["unstable_const"] } +memoffset = { version = "0.8.0", features = ["unstable_const"] } field-offset = "0.3.5" measureme = "10.0.0" rustc_ast = { path = "../rustc_ast" } diff --git a/compiler/rustc_query_system/messages.ftl b/compiler/rustc_query_system/messages.ftl index 0d01123ad88..49b423d1ade 100644 --- a/compiler/rustc_query_system/messages.ftl +++ b/compiler/rustc_query_system/messages.ftl @@ -1,30 +1,30 @@ -query_system_reentrant = internal compiler error: reentrant incremental verify failure, suppressing message - -query_system_increment_compilation = internal compiler error: encountered incremental compilation error with {$dep_node} - .help = This is a known issue with the compiler. Run {$run_cmd} to allow your project to compile - -query_system_increment_compilation_note1 = Please follow the instructions below to create a bug report with the provided information -query_system_increment_compilation_note2 = See <https://github.com/rust-lang/rust/issues/84970> for more information - query_system_cycle = cycle detected when {$stack_bottom} -query_system_cycle_usage = cycle used when {$usage} +query_system_cycle_recursive_trait_alias = trait aliases cannot be recursive -query_system_cycle_stack_single = ...which immediately requires {$stack_bottom} again +query_system_cycle_recursive_ty_alias = type aliases cannot be recursive +query_system_cycle_recursive_ty_alias_help1 = consider using a struct, enum, or union instead to break the cycle +query_system_cycle_recursive_ty_alias_help2 = see <https://doc.rust-lang.org/reference/types.html#recursive-types> for more information query_system_cycle_stack_middle = ...which requires {$desc}... query_system_cycle_stack_multiple = ...which again requires {$stack_bottom}, completing the cycle -query_system_cycle_recursive_ty_alias = type aliases cannot be recursive -query_system_cycle_recursive_ty_alias_help1 = consider using a struct, enum, or union instead to break the cycle -query_system_cycle_recursive_ty_alias_help2 = see <https://doc.rust-lang.org/reference/types.html#recursive-types> for more information +query_system_cycle_stack_single = ...which immediately requires {$stack_bottom} again -query_system_cycle_recursive_trait_alias = trait aliases cannot be recursive +query_system_cycle_usage = cycle used when {$usage} query_system_cycle_which_requires = ...which requires {$desc}... +query_system_increment_compilation = internal compiler error: encountered incremental compilation error with {$dep_node} + .help = This is a known issue with the compiler. Run {$run_cmd} to allow your project to compile + +query_system_increment_compilation_note1 = Please follow the instructions below to create a bug report with the provided information +query_system_increment_compilation_note2 = See <https://github.com/rust-lang/rust/issues/84970> for more information + +query_system_layout_of_depth = query depth increased by {$depth} when {$desc} + query_system_query_overflow = queries overflow the depth limit! .help = consider increasing the recursion limit by adding a `#![recursion_limit = "{$suggested_limit}"]` attribute to your crate (`{$crate_name}`) -query_system_layout_of_depth = query depth increased by {$depth} when {$desc} +query_system_reentrant = internal compiler error: reentrant incremental verify failure, suppressing message diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl index 345255c4c69..539b88aa9d3 100644 --- a/compiler/rustc_resolve/messages.ftl +++ b/compiler/rustc_resolve/messages.ftl @@ -1,79 +1,90 @@ -resolve_parent_module_reset_for_binding = - parent module is reset for binding +resolve_accessible_unsure = not sure whether the path is accessible or not + .note = the type may have associated items, but we are currently not checking them + +resolve_add_as_non_derive = + add as non-Derive macro + `#[{$macro_path}]` resolve_ampersand_used_without_explicit_lifetime_name = `&` without an explicit lifetime name cannot be used here .note = explicit lifetime name needed here -resolve_underscore_lifetime_name_cannot_be_used_here = - `'_` cannot be used here - .note = `'_` is a reserved lifetime name +resolve_ancestor_only = + visibilities can only be restricted to ancestor modules -resolve_crate_may_not_be_imported = - `$crate` may not be imported +resolve_associated_const_with_similar_name_exists = + there is an associated constant with a similar name -resolve_crate_root_imports_must_be_named_explicitly = - crate root imports need to be explicitly named: `use crate as name;` +resolve_associated_fn_with_similar_name_exists = + there is an associated function with a similar name -resolve_generic_params_from_outer_function = - can't use generic parameters from outer function - .label = use of generic parameter from outer function - .suggestion = try using a local generic parameter instead +resolve_associated_type_with_similar_name_exists = + there is an associated type with a similar name -resolve_self_type_implicitly_declared_by_impl = - `Self` type implicitly declared here, by this `impl` +resolve_attempt_to_use_non_constant_value_in_constant = + attempt to use a non-constant value in a constant + +resolve_attempt_to_use_non_constant_value_in_constant_label_with_suggestion = + non-constant value + +resolve_attempt_to_use_non_constant_value_in_constant_with_suggestion = + consider using `{$suggestion}` instead of `{$current}` + +resolve_attempt_to_use_non_constant_value_in_constant_without_suggestion = + this would need to be a `{$suggestion}` + +resolve_binding_shadows_something_unacceptable = + {$shadowing_binding}s cannot shadow {$shadowed_binding}s + .label = cannot be named the same as {$article} {$shadowed_binding} + .label_shadowed_binding = the {$shadowed_binding} `{$name}` is {$participle} here + +resolve_binding_shadows_something_unacceptable_suggestion = + try specify the pattern arguments + +resolve_cannot_capture_dynamic_environment_in_fn_item = + can't capture dynamic environment in a fn item + .help = use the `|| {"{"} ... {"}"}` closure form instead resolve_cannot_use_self_type_here = can't use `Self` here -resolve_use_a_type_here_instead = - use a type here instead - -resolve_type_param_from_outer_fn = - type parameter from outer function +resolve_const_not_member_of_trait = + const `{$const_}` is not a member of trait `{$trait_}` + .label = not a member of trait `{$trait_}` resolve_const_param_from_outer_fn = const parameter from outer function -resolve_try_using_local_generic_parameter = - try using a local generic parameter instead - -resolve_try_adding_local_generic_param_on_method = - try adding a local generic parameter in this method instead - -resolve_help_try_using_local_generic_param = - try using a local generic parameter instead +resolve_const_param_in_enum_discriminant = + const parameters may not be used in enum discriminant values -resolve_name_is_already_used_as_generic_parameter = - the name `{$name}` is already used for a generic parameter in this item's generic parameters - .label = already used - .first_use_of_name = first use of `{$name}` +resolve_const_param_in_non_trivial_anon_const = + const parameters may only be used as standalone arguments, i.e. `{$name}` -resolve_method_not_member_of_trait = - method `{$method}` is not a member of trait `{$trait_}` - .label = not a member of trait `{$trait_}` +resolve_const_param_in_ty_of_const_param = + const parameters may not be used in the type of const parameters -resolve_associated_fn_with_similar_name_exists = - there is an associated function with a similar name +resolve_crate_may_not_be_imported = + `$crate` may not be imported -resolve_type_not_member_of_trait = - type `{$type_}` is not a member of trait `{$trait_}` - .label = not a member of trait `{$trait_}` +resolve_crate_root_imports_must_be_named_explicitly = + crate root imports need to be explicitly named: `use crate as name;` -resolve_associated_type_with_similar_name_exists = - there is an associated type with a similar name +resolve_expected_found = + expected module, found {$res} `{$path_str}` + .label = not a module -resolve_const_not_member_of_trait = - const `{$const_}` is not a member of trait `{$trait_}` - .label = not a member of trait `{$trait_}` +resolve_forward_declared_generic_param = + generic parameters with a default cannot use forward declared identifiers + .label = defaulted generic parameters cannot be forward declared -resolve_associated_const_with_similar_name_exists = - there is an associated constant with a similar name +resolve_generic_params_from_outer_function = + can't use generic parameters from outer function + .label = use of generic parameter from outer function + .suggestion = try using a local generic parameter instead -resolve_variable_bound_with_different_mode = - variable `{$variable_name}` is bound inconsistently across alternatives separated by `|` - .label = bound in different ways - .first_binding_span = first binding +resolve_help_try_using_local_generic_param = + try using a local generic parameter instead resolve_ident_bound_more_than_once_in_parameter_list = identifier `{$identifier}` is bound more than once in this parameter list @@ -83,125 +94,104 @@ resolve_ident_bound_more_than_once_in_same_pattern = identifier `{$identifier}` is bound more than once in the same pattern .label = used in a pattern more than once -resolve_undeclared_label = - use of undeclared label `{$name}` - .label = undeclared label `{$name}` +resolve_imported_crate = `$crate` may not be imported -resolve_label_with_similar_name_reachable = - a label with a similar name is reachable +resolve_indeterminate = + cannot determine resolution for the visibility -resolve_try_using_similarly_named_label = - try using similarly named label +resolve_invalid_asm_sym = + invalid `sym` operand + .label = is a local variable + .help = `sym` operands must refer to either a function or a static -resolve_unreachable_label_with_similar_name_exists = - a label with a similar name exists but is unreachable +resolve_label_with_similar_name_reachable = + a label with a similar name is reachable -resolve_self_import_can_only_appear_once_in_the_list = - `self` import can only appear once in an import list - .label = can only appear once in an import list +resolve_lifetime_param_in_enum_discriminant = + lifetime parameters may not be used in enum discriminant values -resolve_self_import_only_in_import_list_with_non_empty_prefix = - `self` import can only appear in an import list with a non-empty prefix - .label = can only appear in an import list with a non-empty prefix +resolve_lifetime_param_in_non_trivial_anon_const = + lifetime parameters may not be used in const expressions -resolve_cannot_capture_dynamic_environment_in_fn_item = - can't capture dynamic environment in a fn item - .help = use the `|| {"{"} ... {"}"}` closure form instead +resolve_lifetime_param_in_ty_of_const_param = + lifetime parameters may not be used in the type of const parameters -resolve_attempt_to_use_non_constant_value_in_constant = +resolve_lowercase_self = attempt to use a non-constant value in a constant + .suggestion = try using `Self` -resolve_attempt_to_use_non_constant_value_in_constant_with_suggestion = - consider using `{$suggestion}` instead of `{$current}` - -resolve_attempt_to_use_non_constant_value_in_constant_label_with_suggestion = - non-constant value +resolve_macro_expected_found = + expected {$expected}, found {$found} `{$macro_path}` -resolve_attempt_to_use_non_constant_value_in_constant_without_suggestion = - this would need to be a `{$suggestion}` +resolve_macro_use_extern_crate_self = `#[macro_use]` is not supported on `extern crate self` -resolve_self_imports_only_allowed_within = - `self` imports are only allowed within a {"{"} {"}"} list +resolve_method_not_member_of_trait = + method `{$method}` is not a member of trait `{$trait_}` + .label = not a member of trait `{$trait_}` -resolve_self_imports_only_allowed_within_suggestion = - consider importing the module directly +resolve_module_only = + visibility must resolve to a module -resolve_self_imports_only_allowed_within_multipart_suggestion = - alternatively, use the multi-path `use` syntax to import `self` +resolve_name_is_already_used_as_generic_parameter = + the name `{$name}` is already used for a generic parameter in this item's generic parameters + .label = already used + .first_use_of_name = first use of `{$name}` -resolve_binding_shadows_something_unacceptable = - {$shadowing_binding}s cannot shadow {$shadowed_binding}s - .label = cannot be named the same as {$article} {$shadowed_binding} - .label_shadowed_binding = the {$shadowed_binding} `{$name}` is {$participle} here +resolve_param_in_enum_discriminant = + generic parameters may not be used in enum discriminant values + .label = cannot perform const operation using `{$name}` -resolve_binding_shadows_something_unacceptable_suggestion = - try specify the pattern arguments +resolve_param_in_non_trivial_anon_const = + generic parameters may not be used in const operations + .label = cannot perform const operation using `{$name}` -resolve_forward_declared_generic_param = - generic parameters with a default cannot use forward declared identifiers - .label = defaulted generic parameters cannot be forward declared +resolve_param_in_non_trivial_anon_const_help = + use `#![feature(generic_const_exprs)]` to allow generic const expressions resolve_param_in_ty_of_const_param = the type of const parameters must not depend on other generic parameters .label = the type must not depend on the parameter `{$name}` -resolve_type_param_in_ty_of_const_param = - type parameters may not be used in the type of const parameters - -resolve_const_param_in_ty_of_const_param = - const parameters may not be used in the type of const parameters - -resolve_lifetime_param_in_ty_of_const_param = - lifetime parameters may not be used in the type of const parameters - -resolve_self_in_generic_param_default = - generic parameters cannot use `Self` in their defaults - .label = `Self` in generic parameter default - -resolve_param_in_non_trivial_anon_const = - generic parameters may not be used in const operations - .label = cannot perform const operation using `{$name}` +resolve_parent_module_reset_for_binding = + parent module is reset for binding -resolve_param_in_non_trivial_anon_const_help = - use `#![feature(generic_const_exprs)]` to allow generic const expressions +resolve_proc_macro_same_crate = can't use a procedural macro from the same crate that defines it + .help = you can define integration tests in a directory named `tests` -resolve_type_param_in_non_trivial_anon_const = - type parameters may not be used in const expressions +resolve_relative_2018 = + relative paths are not supported in visibilities in 2018 edition or later + .suggestion = try -resolve_const_param_in_non_trivial_anon_const = - const parameters may only be used as standalone arguments, i.e. `{$name}` +resolve_remove_surrounding_derive = + remove from the surrounding `derive()` -resolve_lifetime_param_in_non_trivial_anon_const = - lifetime parameters may not be used in const expressions +resolve_self_import_can_only_appear_once_in_the_list = + `self` import can only appear once in an import list + .label = can only appear once in an import list -resolve_unreachable_label = - use of unreachable label `{$name}` - .label = unreachable label `{$name}` - .label_definition_span = unreachable label defined here - .note = labels are unreachable through functions, closures, async blocks and modules +resolve_self_import_only_in_import_list_with_non_empty_prefix = + `self` import can only appear in an import list with a non-empty prefix + .label = can only appear in an import list with a non-empty prefix -resolve_unreachable_label_suggestion_use_similarly_named = - try using similarly named label +resolve_self_imports_only_allowed_within = + `self` imports are only allowed within a {"{"} {"}"} list -resolve_unreachable_label_similar_name_reachable = - a label with a similar name is reachable +resolve_self_imports_only_allowed_within_multipart_suggestion = + alternatively, use the multi-path `use` syntax to import `self` -resolve_unreachable_label_similar_name_unreachable = - a label with a similar name exists but is also unreachable +resolve_self_imports_only_allowed_within_suggestion = + consider importing the module directly -resolve_trait_impl_mismatch = - item `{$name}` is an associated {$kind}, which doesn't match its trait `{$trait_path}` - .label = does not match trait - .label_trait_item = item in trait +resolve_self_in_generic_param_default = + generic parameters cannot use `Self` in their defaults + .label = `Self` in generic parameter default -resolve_invalid_asm_sym = - invalid `sym` operand - .label = is a local variable - .help = `sym` operands must refer to either a function or a static +resolve_self_type_implicitly_declared_by_impl = + `Self` type implicitly declared here, by this `impl` -resolve_lowercase_self = - attempt to use a non-constant value in a constant - .suggestion = try using `Self` +resolve_tool_module_imported = + cannot use a tool module through an import + .note = the tool module imported here resolve_trait_impl_duplicate = duplicate definitions with name `{$name}`: @@ -209,56 +199,66 @@ resolve_trait_impl_duplicate = .old_span_label = previous definition here .trait_item_span = item in trait -resolve_relative_2018 = - relative paths are not supported in visibilities in 2018 edition or later - .suggestion = try +resolve_trait_impl_mismatch = + item `{$name}` is an associated {$kind}, which doesn't match its trait `{$trait_path}` + .label = does not match trait + .label_trait_item = item in trait -resolve_ancestor_only = - visibilities can only be restricted to ancestor modules +resolve_try_adding_local_generic_param_on_method = + try adding a local generic parameter in this method instead -resolve_expected_found = - expected module, found {$res} `{$path_str}` - .label = not a module +resolve_try_using_local_generic_parameter = + try using a local generic parameter instead -resolve_indeterminate = - cannot determine resolution for the visibility +resolve_try_using_similarly_named_label = + try using similarly named label -resolve_tool_module_imported = - cannot use a tool module through an import - .note = the tool module imported here +resolve_type_not_member_of_trait = + type `{$type_}` is not a member of trait `{$trait_}` + .label = not a member of trait `{$trait_}` -resolve_module_only = - visibility must resolve to a module +resolve_type_param_from_outer_fn = + type parameter from outer function -resolve_macro_expected_found = - expected {$expected}, found {$found} `{$macro_path}` +resolve_type_param_in_enum_discriminant = + type parameters may not be used in enum discriminant values -resolve_remove_surrounding_derive = - remove from the surrounding `derive()` +resolve_type_param_in_non_trivial_anon_const = + type parameters may not be used in const expressions -resolve_add_as_non_derive = - add as non-Derive macro - `#[{$macro_path}]` +resolve_type_param_in_ty_of_const_param = + type parameters may not be used in the type of const parameters -resolve_proc_macro_same_crate = can't use a procedural macro from the same crate that defines it - .help = you can define integration tests in a directory named `tests` +resolve_undeclared_label = + use of undeclared label `{$name}` + .label = undeclared label `{$name}` -resolve_imported_crate = `$crate` may not be imported +resolve_underscore_lifetime_name_cannot_be_used_here = + `'_` cannot be used here + .note = `'_` is a reserved lifetime name -resolve_macro_use_extern_crate_self = `#[macro_use]` is not supported on `extern crate self` +resolve_unreachable_label = + use of unreachable label `{$name}` + .label = unreachable label `{$name}` + .label_definition_span = unreachable label defined here + .note = labels are unreachable through functions, closures, async blocks and modules -resolve_accessible_unsure = not sure whether the path is accessible or not - .note = the type may have associated items, but we are currently not checking them +resolve_unreachable_label_similar_name_reachable = + a label with a similar name is reachable -resolve_param_in_enum_discriminant = - generic parameters may not be used in enum discriminant values - .label = cannot perform const operation using `{$name}` +resolve_unreachable_label_similar_name_unreachable = + a label with a similar name exists but is also unreachable -resolve_type_param_in_enum_discriminant = - type parameters may not be used in enum discriminant values +resolve_unreachable_label_suggestion_use_similarly_named = + try using similarly named label -resolve_const_param_in_enum_discriminant = - const parameters may not be used in enum discriminant values +resolve_unreachable_label_with_similar_name_exists = + a label with a similar name exists but is unreachable -resolve_lifetime_param_in_enum_discriminant = - lifetime parameters may not be used in enum discriminant values +resolve_use_a_type_here_instead = + use a type here instead + +resolve_variable_bound_with_different_mode = + variable `{$variable_name}` is bound inconsistently across alternatives separated by `|` + .label = bound in different ways + .first_binding_span = first binding diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 8c6ac822a77..377652ce71b 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -2540,7 +2540,7 @@ fn show_candidates( err.note(msg); } if let Some(note) = (*note).as_deref() { - err.note(note); + err.note(note.to_string()); } } else { let (_, descr_first, _, _) = &inaccessible_path_strings[0]; diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 7c4c05d4b94..c1bb262c0d4 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -21,7 +21,8 @@ use rustc_middle::metadata::Reexport; use rustc_middle::span_bug; use rustc_middle::ty; use rustc_session::lint::builtin::{ - AMBIGUOUS_GLOB_REEXPORTS, PUB_USE_OF_PRIVATE_EXTERN_CRATE, UNUSED_IMPORTS, + AMBIGUOUS_GLOB_REEXPORTS, HIDDEN_GLOB_REEXPORTS, PUB_USE_OF_PRIVATE_EXTERN_CRATE, + UNUSED_IMPORTS, }; use rustc_session::lint::BuiltinLintDiagnostics; use rustc_span::edit_distance::find_best_match_for_name; @@ -526,31 +527,71 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } } - pub(crate) fn check_reexport_ambiguities( + pub(crate) fn check_hidden_glob_reexports( &mut self, exported_ambiguities: FxHashSet<Interned<'a, NameBinding<'a>>>, ) { for module in self.arenas.local_modules().iter() { - module.for_each_child(self, |this, ident, ns, binding| { - if let NameBindingKind::Import { import, .. } = binding.kind - && let Some((amb_binding, _)) = binding.ambiguity - && binding.res() != Res::Err - && exported_ambiguities.contains(&Interned::new_unchecked(binding)) - { - this.lint_buffer.buffer_lint_with_diagnostic( - AMBIGUOUS_GLOB_REEXPORTS, - import.root_id, - import.root_span, - "ambiguous glob re-exports", - BuiltinLintDiagnostics::AmbiguousGlobReexports { - name: ident.to_string(), - namespace: ns.descr().to_string(), - first_reexport_span: import.root_span, - duplicate_reexport_span: amb_binding.span, - }, - ); + for (key, resolution) in self.resolutions(module).borrow().iter() { + let resolution = resolution.borrow(); + + if let Some(binding) = resolution.binding { + if let NameBindingKind::Import { import, .. } = binding.kind + && let Some((amb_binding, _)) = binding.ambiguity + && binding.res() != Res::Err + && exported_ambiguities.contains(&Interned::new_unchecked(binding)) + { + self.lint_buffer.buffer_lint_with_diagnostic( + AMBIGUOUS_GLOB_REEXPORTS, + import.root_id, + import.root_span, + "ambiguous glob re-exports", + BuiltinLintDiagnostics::AmbiguousGlobReexports { + name: key.ident.to_string(), + namespace: key.ns.descr().to_string(), + first_reexport_span: import.root_span, + duplicate_reexport_span: amb_binding.span, + }, + ); + } + + 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_with_diagnostic( + HIDDEN_GLOB_REEXPORTS, + binding_id, + binding.span, + "private item shadows public glob re-export", + BuiltinLintDiagnostics::HiddenGlobReexports { + name: key.ident.name.to_string(), + namespace: key.ns.descr().to_owned(), + glob_reexport_span: glob_binding.span, + private_item_span: binding.span, + }, + ); + } + } } - }); + } } } diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index df65825802e..f79f8d0c6ca 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -29,6 +29,7 @@ use rustc_span::hygiene::MacroKind; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::Span; +use std::borrow::Cow; use std::iter; use std::ops::Deref; @@ -1248,7 +1249,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { }), ) if followed_by_brace => { if let Some(sp) = closing_brace { - err.span_label(span, fallback_label); + err.span_label(span, fallback_label.to_string()); err.multipart_suggestion( "surround the struct literal with parentheses", vec![ @@ -1320,7 +1321,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { ); } _ => { - err.span_label(span, fallback_label); + err.span_label(span, fallback_label.to_string()); } } }; @@ -1333,7 +1334,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { })) | PathSource::Struct, ) => { - err.span_label(span, fallback_label); + err.span_label(span, fallback_label.to_string()); err.span_suggestion_verbose( span.shrink_to_hi(), "use `!` to invoke the macro", @@ -1345,7 +1346,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { } } (Res::Def(DefKind::Macro(MacroKind::Bang), _), _) => { - err.span_label(span, fallback_label); + err.span_label(span, fallback_label.to_string()); } (Res::Def(DefKind::TyAlias, def_id), PathSource::Trait(_)) => { err.span_label(span, "type aliases cannot be used as traits"); @@ -1513,7 +1514,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { ); } (Res::SelfTyParam { .. } | Res::SelfTyAlias { .. }, _) if ns == ValueNS => { - err.span_label(span, fallback_label); + err.span_label(span, fallback_label.to_string()); err.note("can't use `Self` as a constructor, you must use the implemented struct"); } (Res::Def(DefKind::TyAlias | DefKind::AssocTy, _), _) if ns == ValueNS => { @@ -2243,7 +2244,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { &self, err: &mut Diagnostic, name: Option<&str>, - suggest: impl Fn(&mut Diagnostic, bool, Span, &str, String) -> bool, + suggest: impl Fn(&mut Diagnostic, bool, Span, Cow<'static, str>, String) -> bool, ) { let mut suggest_note = true; for rib in self.lifetime_ribs.iter().rev() { @@ -2288,22 +2289,23 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { (span, sugg) }; if higher_ranked { - let message = format!( + let message = Cow::from(format!( "consider making the {} lifetime-generic with a new `{}` lifetime", kind.descr(), name.unwrap_or("'a"), - ); - should_continue = suggest(err, true, span, &message, sugg); + )); + should_continue = suggest(err, true, span, message, sugg); err.note_once( "for more information on higher-ranked polymorphism, visit \ https://doc.rust-lang.org/nomicon/hrtb.html", ); } else if let Some(name) = name { - let message = format!("consider introducing lifetime `{}` here", name); - should_continue = suggest(err, false, span, &message, sugg); + let message = + Cow::from(format!("consider introducing lifetime `{}` here", name)); + should_continue = suggest(err, false, span, message, sugg); } else { - let message = "consider introducing a named lifetime parameter"; - should_continue = suggest(err, false, span, &message, sugg); + let message = Cow::from("consider introducing a named lifetime parameter"); + should_continue = suggest(err, false, span, message, sugg); } } LifetimeRibKind::Item => break, diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 3d2bd842906..fd977e8e254 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1496,8 +1496,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let exported_ambiguities = self.tcx.sess.time("compute_effective_visibilities", || { EffectiveVisibilitiesVisitor::compute_effective_visibilities(self, krate) }); - self.tcx.sess.time("check_reexport_ambiguities", || { - self.check_reexport_ambiguities(exported_ambiguities) + self.tcx.sess.time("check_hidden_glob_reexports", || { + self.check_hidden_glob_reexports(exported_ambiguities) }); self.tcx.sess.time("finalize_macro_resolutions", || self.finalize_macro_resolutions()); self.tcx.sess.time("late_resolve_crate", || self.late_resolve_crate(krate)); diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index df5c16a9375..d8a7bcbfff9 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -827,7 +827,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { if !is_allowed(feature) && !allowed_by_implication { let lint_buffer = &mut self.lint_buffer; let soft_handler = - |lint, span, msg: &_| lint_buffer.buffer_lint(lint, node_id, span, msg); + |lint, span, msg: String| lint_buffer.buffer_lint(lint, node_id, span, msg); stability::report_unstable( self.tcx.sess, feature, @@ -846,7 +846,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let (message, lint) = stability::deprecation_message_and_lint(depr, "macro", &path); stability::early_report_deprecation( &mut self.lint_buffer, - &message, + message, depr.suggestion, lint, span, diff --git a/compiler/rustc_session/messages.ftl b/compiler/rustc_session/messages.ftl index a8fe560d1a7..5a0b8f9f73c 100644 --- a/compiler/rustc_session/messages.ftl +++ b/compiler/rustc_session/messages.ftl @@ -1,13 +1,20 @@ -session_incorrect_cgu_reuse_type = - CGU-reuse for `{$cgu_user_name}` is `{$actual_reuse}` but should be {$at_least -> - [one] {"at least "} - *[other] {""} - }`{$expected_reuse}` +session_binary_float_literal_not_supported = binary float literal is not supported +session_branch_protection_requires_aarch64 = `-Zbranch-protection` is only supported on aarch64 + +session_cannot_enable_crt_static_linux = sanitizer is incompatible with statically linked libc, disable it using `-C target-feature=-crt-static` + +session_cannot_mix_and_match_sanitizers = `-Zsanitizer={$first}` is incompatible with `-Zsanitizer={$second}` session_cgu_not_recorded = CGU-reuse for `{$cgu_user_name}` is (mangled: `{$cgu_name}`) was not recorded -session_feature_gate_error = {$explain} +session_crate_name_does_not_match = `--crate-name` and `#[crate_name]` are required to match, but `{$s}` != `{$name}` + +session_crate_name_empty = crate name must not be empty + +session_crate_name_invalid = crate names cannot start with a `-`, but `{$s}` has a leading hyphen + +session_expr_parentheses_needed = parentheses are required to parse this as an expression session_feature_diagnostic_for_issue = see issue #{$n} <https://github.com/rust-lang/rust/issues/{$n}> for more information @@ -15,91 +22,84 @@ session_feature_diagnostic_for_issue = session_feature_diagnostic_help = add `#![feature({$feature})]` to the crate attributes to enable -session_not_circumvent_feature = `-Zunleash-the-miri-inside-of-you` may not be used to circumvent feature gates, except when testing error paths in the CTFE engine - -session_profile_use_file_does_not_exist = file `{$path}` passed to `-C profile-use` does not exist. - -session_linker_plugin_lto_windows_not_supported = linker plugin based LTO is not supported together with `-C prefer-dynamic` when targeting Windows-like targets +session_feature_gate_error = {$explain} -session_profile_sample_use_file_does_not_exist = file `{$path}` passed to `-C profile-sample-use` does not exist. +session_file_is_not_writeable = output file {$file} is not writeable -- check its permissions -session_target_requires_unwind_tables = target requires unwind tables, they cannot be disabled with `-C force-unwind-tables=no` +session_hexadecimal_float_literal_not_supported = hexadecimal float literal is not supported +session_incorrect_cgu_reuse_type = + CGU-reuse for `{$cgu_user_name}` is `{$actual_reuse}` but should be {$at_least -> + [one] {"at least "} + *[other] {""} + }`{$expected_reuse}` session_instrumentation_not_supported = {$us} instrumentation is not supported for this target -session_sanitizer_not_supported = {$us} sanitizer is not supported for this target - -session_sanitizers_not_supported = {$us} sanitizers are not supported for this target - -session_cannot_mix_and_match_sanitizers = `-Zsanitizer={$first}` is incompatible with `-Zsanitizer={$second}` - -session_cannot_enable_crt_static_linux = sanitizer is incompatible with statically linked libc, disable it using `-C target-feature=-crt-static` +session_int_literal_too_large = integer literal is too large + .note = value exceeds limit of `{$limit}` -session_sanitizer_cfi_requires_lto = `-Zsanitizer=cfi` requires `-Clto`, `-Clto=thin`, or `-Clinker-plugin-lto` +session_invalid_character_in_create_name = invalid character `{$character}` in crate name: `{$crate_name}` -session_sanitizer_cfi_canonical_jump_tables_requires_cfi = `-Zsanitizer-cfi-canonical-jump-tables` requires `-Zsanitizer=cfi` +session_invalid_float_literal_suffix = invalid suffix `{$suffix}` for float literal + .label = invalid suffix `{$suffix}` + .help = valid suffixes are `f32` and `f64` -session_sanitizer_cfi_generalize_pointers_requires_cfi = `-Zsanitizer-cfi-generalize-pointers` requires `-Zsanitizer=cfi` or `-Zsanitizer=kcfi` +session_invalid_float_literal_width = invalid width `{$width}` for float literal + .help = valid widths are 32 and 64 -session_sanitizer_cfi_normalize_integers_requires_cfi = `-Zsanitizer-cfi-normalize-integers` requires `-Zsanitizer=cfi` or `-Zsanitizer=kcfi` +session_invalid_int_literal_width = invalid width `{$width}` for integer literal + .help = valid widths are 8, 16, 32, 64 and 128 -session_split_lto_unit_requires_lto = `-Zsplit-lto-unit` requires `-Clto`, `-Clto=thin`, or `-Clinker-plugin-lto` +session_invalid_literal_suffix = suffixes on {$kind} literals are invalid + .label = invalid suffix `{$suffix}` -session_unstable_virtual_function_elimination = `-Zvirtual-function-elimination` requires `-Clto` +session_invalid_num_literal_base_prefix = invalid base prefix for number literal + .note = base prefixes (`0xff`, `0b1010`, `0o755`) are lowercase + .suggestion = try making the prefix lowercase -session_unsupported_dwarf_version = requested DWARF version {$dwarf_version} is greater than 5 +session_invalid_num_literal_suffix = invalid suffix `{$suffix}` for number literal + .label = invalid suffix `{$suffix}` + .help = the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.) -session_target_stack_protector_not_supported = `-Z stack-protector={$stack_protector}` is not supported for target {$target_triple} and will be ignored +session_linker_plugin_lto_windows_not_supported = linker plugin based LTO is not supported together with `-C prefer-dynamic` when targeting Windows-like targets -session_branch_protection_requires_aarch64 = `-Zbranch-protection` is only supported on aarch64 +session_not_circumvent_feature = `-Zunleash-the-miri-inside-of-you` may not be used to circumvent feature gates, except when testing error paths in the CTFE engine -session_split_debuginfo_unstable_platform = `-Csplit-debuginfo={$debuginfo}` is unstable on this platform +session_not_supported = not supported -session_file_is_not_writeable = output file {$file} is not writeable -- check its permissions +session_nul_in_c_str = null characters in C string literals are not supported -session_crate_name_does_not_match = `--crate-name` and `#[crate_name]` are required to match, but `{$s}` != `{$name}` +session_octal_float_literal_not_supported = octal float literal is not supported +session_optimization_fuel_exhausted = optimization-fuel-exhausted: {$msg} -session_crate_name_invalid = crate names cannot start with a `-`, but `{$s}` has a leading hyphen +session_profile_sample_use_file_does_not_exist = file `{$path}` passed to `-C profile-sample-use` does not exist. -session_crate_name_empty = crate name must not be empty +session_profile_use_file_does_not_exist = file `{$path}` passed to `-C profile-use` does not exist. -session_invalid_character_in_create_name = invalid character `{$character}` in crate name: `{$crate_name}` +session_sanitizer_cfi_canonical_jump_tables_requires_cfi = `-Zsanitizer-cfi-canonical-jump-tables` requires `-Zsanitizer=cfi` -session_expr_parentheses_needed = parentheses are required to parse this as an expression +session_sanitizer_cfi_generalize_pointers_requires_cfi = `-Zsanitizer-cfi-generalize-pointers` requires `-Zsanitizer=cfi` or `-Zsanitizer=kcfi` -session_skipping_const_checks = skipping const checks -session_unleashed_feature_help_named = skipping check for `{$gate}` feature -session_unleashed_feature_help_unnamed = skipping check that does not even have a feature gate +session_sanitizer_cfi_normalize_integers_requires_cfi = `-Zsanitizer-cfi-normalize-integers` requires `-Zsanitizer=cfi` or `-Zsanitizer=kcfi` -session_hexadecimal_float_literal_not_supported = hexadecimal float literal is not supported -session_octal_float_literal_not_supported = octal float literal is not supported -session_binary_float_literal_not_supported = binary float literal is not supported -session_not_supported = not supported +session_sanitizer_cfi_requires_lto = `-Zsanitizer=cfi` requires `-Clto`, `-Clto=thin`, or `-Clinker-plugin-lto` -session_invalid_literal_suffix = suffixes on {$kind} literals are invalid - .label = invalid suffix `{$suffix}` +session_sanitizer_not_supported = {$us} sanitizer is not supported for this target -session_invalid_num_literal_base_prefix = invalid base prefix for number literal - .note = base prefixes (`0xff`, `0b1010`, `0o755`) are lowercase - .suggestion = try making the prefix lowercase +session_sanitizers_not_supported = {$us} sanitizers are not supported for this target -session_invalid_num_literal_suffix = invalid suffix `{$suffix}` for number literal - .label = invalid suffix `{$suffix}` - .help = the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.) +session_skipping_const_checks = skipping const checks +session_split_debuginfo_unstable_platform = `-Csplit-debuginfo={$debuginfo}` is unstable on this platform -session_invalid_float_literal_width = invalid width `{$width}` for float literal - .help = valid widths are 32 and 64 +session_split_lto_unit_requires_lto = `-Zsplit-lto-unit` requires `-Clto`, `-Clto=thin`, or `-Clinker-plugin-lto` -session_invalid_float_literal_suffix = invalid suffix `{$suffix}` for float literal - .label = invalid suffix `{$suffix}` - .help = valid suffixes are `f32` and `f64` +session_target_requires_unwind_tables = target requires unwind tables, they cannot be disabled with `-C force-unwind-tables=no` -session_int_literal_too_large = integer literal is too large - .note = value exceeds limit of `{$limit}` +session_target_stack_protector_not_supported = `-Z stack-protector={$stack_protector}` is not supported for target {$target_triple} and will be ignored -session_invalid_int_literal_width = invalid width `{$width}` for integer literal - .help = valid widths are 8, 16, 32, 64 and 128 +session_unleashed_feature_help_named = skipping check for `{$gate}` feature +session_unleashed_feature_help_unnamed = skipping check that does not even have a feature gate -session_optimization_fuel_exhausted = optimization-fuel-exhausted: {$msg} +session_unstable_virtual_function_elimination = `-Zvirtual-function-elimination` requires `-Clto` -session_nul_in_c_str = null characters in C string literals are not supported +session_unsupported_dwarf_version = requested DWARF version {$dwarf_version} is greater than 5 diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 2c4c4a7a6ce..7cc2b2c880c 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -372,7 +372,7 @@ mod desc { pub const parse_opt_panic_strategy: &str = parse_panic_strategy; pub const parse_oom_strategy: &str = "either `panic` or `abort`"; pub const parse_relro_level: &str = "one of: `full`, `partial`, or `off`"; - pub const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `cfi`, `hwaddress`, `kcfi`, `kernel-address`, `leak`, `memory`, `memtag`, `shadow-call-stack`, or `thread`"; + pub const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `cfi`, `hwaddress`, `kcfi`, `kernel-address`, `leak`, `memory`, `memtag`, `safestack`, `shadow-call-stack`, or `thread`"; pub const parse_sanitizer_memory_track_origins: &str = "0, 1, or 2"; pub const parse_cfguard: &str = "either a boolean (`yes`, `no`, `on`, `off`, etc), `checks`, or `nochecks`"; @@ -694,6 +694,7 @@ mod parse { "shadow-call-stack" => SanitizerSet::SHADOWCALLSTACK, "thread" => SanitizerSet::THREAD, "hwaddress" => SanitizerSet::HWADDRESS, + "safestack" => SanitizerSet::SAFESTACK, _ => return false, } } @@ -1371,8 +1372,6 @@ options! { "set options for branch target identification and pointer authentication on AArch64"), cf_protection: CFProtection = (CFProtection::None, parse_cfprotection, [TRACKED], "instrument control-flow architecture protection"), - cgu_partitioning_strategy: Option<String> = (None, parse_opt_string, [TRACKED], - "the codegen unit partitioning strategy to use"), codegen_backend: Option<String> = (None, parse_opt_string, [TRACKED], "the backend to use"), combine_cgu: bool = (false, parse_bool, [TRACKED], diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index 7b396dde91b..a433e2371c9 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -84,6 +84,7 @@ impl SymbolGallery { /// Construct a diagnostic for a language feature error due to the given `span`. /// The `feature`'s `Symbol` is the one you used in `active.rs` and `rustc_span::symbols`. +#[track_caller] pub fn feature_err( sess: &ParseSess, feature: Symbol, @@ -123,7 +124,7 @@ pub fn feature_err_issue( /// Construct a future incompatibility diagnostic for a feature gate. /// /// This diagnostic is only a warning and *does not cause compilation to fail*. -pub fn feature_warn(sess: &ParseSess, feature: Symbol, span: Span, explain: &str) { +pub fn feature_warn(sess: &ParseSess, feature: Symbol, span: Span, explain: &'static str) { feature_warn_issue(sess, feature, span, GateIssue::Language, explain); } @@ -140,7 +141,7 @@ pub fn feature_warn_issue( feature: Symbol, span: Span, issue: GateIssue, - explain: &str, + explain: &'static str, ) { let mut err = sess.span_diagnostic.struct_span_warn(span, explain); add_feature_diagnostics_for_issue(&mut err, sess, feature, issue); diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs index 6af43f5d3f3..5572108f495 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -309,7 +309,7 @@ fn rustc_terminator_to_terminator( Terminate => Terminator::Abort, Return => Terminator::Return, Unreachable => Terminator::Unreachable, - Drop { place, target, unwind } => Terminator::Drop { + Drop { place, target, unwind, replace: _ } => Terminator::Drop { place: rustc_place_to_place(place), target: target.as_usize(), unwind: rustc_unwind_to_unwind(unwind), diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index 6755657c727..b219fde4da9 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -1147,7 +1147,6 @@ pub enum DesugaringKind { Await, ForLoop, WhileLoop, - Replace, } impl DesugaringKind { @@ -1163,7 +1162,6 @@ impl DesugaringKind { DesugaringKind::OpaqueTy => "`impl Trait`", DesugaringKind::ForLoop => "`for` loop", DesugaringKind::WhileLoop => "`while` loop", - DesugaringKind::Replace => "drop and replace", } } } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 874d578fe1d..1185563ea80 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1454,6 +1454,10 @@ symbols! { stop_after_dataflow, store, str, + str_from_utf8, + str_from_utf8_mut, + str_from_utf8_unchecked, + str_from_utf8_unchecked_mut, str_split_whitespace, str_trim, str_trim_end, diff --git a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs index 9fa49123a86..b245742e533 100644 --- a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs +++ b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs @@ -10,7 +10,6 @@ use core::fmt::Display; use rustc_data_structures::base_n; use rustc_data_structures::fx::FxHashMap; -use rustc_errors::DiagnosticMessage; use rustc_hir as hir; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef}; use rustc_middle::ty::{ @@ -534,10 +533,7 @@ fn encode_ty<'tcx>( tcx.sess .struct_span_err( cfi_encoding.span, - DiagnosticMessage::Str(format!( - "invalid `cfi_encoding` for `{:?}`", - ty.kind() - )), + format!("invalid `cfi_encoding` for `{:?}`", ty.kind()), ) .emit(); } @@ -589,10 +585,7 @@ fn encode_ty<'tcx>( tcx.sess .struct_span_err( cfi_encoding.span, - DiagnosticMessage::Str(format!( - "invalid `cfi_encoding` for `{:?}`", - ty.kind() - )), + format!("invalid `cfi_encoding` for `{:?}`", ty.kind()), ) .emit(); } diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 4cccc639892..0a805e2422d 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -274,7 +274,7 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> { let mut param_env = self.tcx.param_env_reveal_all_normalized(impl_def_id); if !substs.is_empty() { - param_env = EarlyBinder(param_env).subst(self.tcx, substs); + param_env = EarlyBinder::bind(param_env).subst(self.tcx, substs); } match &mut impl_trait_ref { diff --git a/compiler/rustc_target/src/spec/aarch64_apple_ios_macabi.rs b/compiler/rustc_target/src/spec/aarch64_apple_ios_macabi.rs index 2b135b67034..e2df7e0bdcc 100644 --- a/compiler/rustc_target/src/spec/aarch64_apple_ios_macabi.rs +++ b/compiler/rustc_target/src/spec/aarch64_apple_ios_macabi.rs @@ -2,7 +2,7 @@ use super::apple_base::{opts, Arch}; use crate::spec::{Cc, FramePointer, LinkerFlavor, Lld, Target, TargetOptions}; pub fn target() -> Target { - let llvm_target = "arm64-apple-ios-macabi"; + let llvm_target = "arm64-apple-ios14.0-macabi"; let arch = Arch::Arm64_macabi; let mut base = opts("ios", arch); diff --git a/compiler/rustc_target/src/spec/mips64_unknown_linux_gnuabi64.rs b/compiler/rustc_target/src/spec/mips64_unknown_linux_gnuabi64.rs index fc5dbd114e4..b9df0046b12 100644 --- a/compiler/rustc_target/src/spec/mips64_unknown_linux_gnuabi64.rs +++ b/compiler/rustc_target/src/spec/mips64_unknown_linux_gnuabi64.rs @@ -12,7 +12,7 @@ pub fn target() -> Target { endian: Endian::Big, // NOTE(mips64r2) matches C toolchain cpu: "mips64r2".into(), - features: "+mips64r2".into(), + features: "+mips64r2,+xgot".into(), max_atomic_width: Some(64), mcount: "_mcount".into(), diff --git a/compiler/rustc_target/src/spec/mips64el_unknown_linux_gnuabi64.rs b/compiler/rustc_target/src/spec/mips64el_unknown_linux_gnuabi64.rs index e0d5f6f57f1..57ad8c47399 100644 --- a/compiler/rustc_target/src/spec/mips64el_unknown_linux_gnuabi64.rs +++ b/compiler/rustc_target/src/spec/mips64el_unknown_linux_gnuabi64.rs @@ -10,7 +10,7 @@ pub fn target() -> Target { abi: "abi64".into(), // NOTE(mips64r2) matches C toolchain cpu: "mips64r2".into(), - features: "+mips64r2".into(), + features: "+mips64r2,+xgot".into(), max_atomic_width: Some(64), mcount: "_mcount".into(), diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index ba4b89c9ea1..62f94209cf0 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -815,6 +815,7 @@ bitflags::bitflags! { const SHADOWCALLSTACK = 1 << 7; const KCFI = 1 << 8; const KERNELADDRESS = 1 << 9; + const SAFESTACK = 1 << 10; } } @@ -831,6 +832,7 @@ impl SanitizerSet { SanitizerSet::LEAK => "leak", SanitizerSet::MEMORY => "memory", SanitizerSet::MEMTAG => "memtag", + SanitizerSet::SAFESTACK => "safestack", SanitizerSet::SHADOWCALLSTACK => "shadow-call-stack", SanitizerSet::THREAD => "thread", SanitizerSet::HWADDRESS => "hwaddress", @@ -871,6 +873,7 @@ impl IntoIterator for SanitizerSet { SanitizerSet::THREAD, SanitizerSet::HWADDRESS, SanitizerSet::KERNELADDRESS, + SanitizerSet::SAFESTACK, ] .iter() .copied() @@ -2364,6 +2367,7 @@ impl Target { Some("leak") => SanitizerSet::LEAK, Some("memory") => SanitizerSet::MEMORY, Some("memtag") => SanitizerSet::MEMTAG, + Some("safestack") => SanitizerSet::SAFESTACK, Some("shadow-call-stack") => SanitizerSet::SHADOWCALLSTACK, Some("thread") => SanitizerSet::THREAD, Some("hwaddress") => SanitizerSet::HWADDRESS, diff --git a/compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs b/compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs index 5a3e2a79bb9..9f3b0fab697 100644 --- a/compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs +++ b/compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs @@ -2,7 +2,7 @@ use super::apple_base::{opts, Arch}; use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetOptions}; pub fn target() -> Target { - let llvm_target = "x86_64-apple-ios-macabi"; + let llvm_target = "x86_64-apple-ios14.0-macabi"; let arch = Arch::X86_64_macabi; let mut base = opts("ios", arch); diff --git a/compiler/rustc_target/src/spec/x86_64_pc_solaris.rs b/compiler/rustc_target/src/spec/x86_64_pc_solaris.rs index cb62a817322..d2906d6c4ae 100644 --- a/compiler/rustc_target/src/spec/x86_64_pc_solaris.rs +++ b/compiler/rustc_target/src/spec/x86_64_pc_solaris.rs @@ -7,7 +7,7 @@ pub fn target() -> Target { base.vendor = "pc".into(); base.max_atomic_width = Some(64); base.stack_probes = StackProbeType::X86; - base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI; + base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::THREAD; Target { llvm_target: "x86_64-pc-solaris".into(), diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_illumos.rs b/compiler/rustc_target/src/spec/x86_64_unknown_illumos.rs index 04a12a7bfa6..ca5b62e279c 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_illumos.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_illumos.rs @@ -5,7 +5,7 @@ pub fn target() -> Target { base.add_pre_link_args(LinkerFlavor::Unix(Cc::Yes), &["-m64", "-std=c99"]); base.cpu = "x86-64".into(); base.max_atomic_width = Some(64); - base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI; + base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::THREAD; Target { // LLVM does not currently have a separate illumos target, diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs index 9af1049b870..deb15c02c68 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs @@ -11,6 +11,7 @@ pub fn target() -> Target { | SanitizerSet::CFI | SanitizerSet::LEAK | SanitizerSet::MEMORY + | SanitizerSet::SAFESTACK | SanitizerSet::THREAD; base.supports_xray = true; diff --git a/compiler/rustc_trait_selection/messages.ftl b/compiler/rustc_trait_selection/messages.ftl index 8fea3fc140d..217ba71b631 100644 --- a/compiler/rustc_trait_selection/messages.ftl +++ b/compiler/rustc_trait_selection/messages.ftl @@ -1,17 +1,13 @@ trait_selection_dump_vtable_entries = vtable entries for `{$trait_ref}`: {$entries} -trait_selection_unable_to_construct_constant_value = unable to construct a constant value for the unevaluated constant {$unevaluated} - trait_selection_empty_on_clause_in_rustc_on_unimplemented = empty `on`-clause in `#[rustc_on_unimplemented]` .label = empty on-clause here +trait_selection_inherent_projection_normalization_overflow = overflow evaluating associated type `{$ty}` + trait_selection_invalid_on_clause_in_rustc_on_unimplemented = invalid `on`-clause in `#[rustc_on_unimplemented]` .label = invalid on-clause here -trait_selection_no_value_in_rustc_on_unimplemented = this attribute must have a valid value - .label = expected value here - .note = eg `#[rustc_on_unimplemented(message="foo")]` - trait_selection_negative_positive_conflict = found both positive and negative implementation of trait `{$trait_desc}`{$self_desc -> [none] {""} *[default] {" "}for type `{$self_desc}` @@ -21,4 +17,8 @@ trait_selection_negative_positive_conflict = found both positive and negative im .positive_implementation_here = positive implementation here .positive_implementation_in_crate = positive implementation in crate `{$positive_impl_cname}` -trait_selection_inherent_projection_normalization_overflow = overflow evaluating associated type `{$ty}` +trait_selection_no_value_in_rustc_on_unimplemented = this attribute must have a valid value + .label = expected value here + .note = eg `#[rustc_on_unimplemented(message="foo")]` + +trait_selection_unable_to_construct_constant_value = unable to construct a constant value for the unevaluated constant {$unevaluated} diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs index 142c20014a0..312bd38178f 100644 --- a/compiler/rustc_trait_selection/src/infer.rs +++ b/compiler/rustc_trait_selection/src/infer.rs @@ -5,7 +5,7 @@ use rustc_hir::def_id::DefId; use rustc_hir::lang_items::LangItem; use rustc_middle::arena::ArenaAllocatable; use rustc_middle::infer::canonical::{Canonical, CanonicalQueryResponse, QueryResponse}; -use rustc_middle::traits::query::Fallible; +use rustc_middle::traits::query::NoSolution; use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitableExt}; use rustc_middle::ty::{GenericArg, ToPredicate}; use rustc_span::DUMMY_SP; @@ -82,8 +82,8 @@ pub trait InferCtxtBuilderExt<'tcx> { fn enter_canonical_trait_query<K, R>( &mut self, canonical_key: &Canonical<'tcx, K>, - operation: impl FnOnce(&ObligationCtxt<'_, 'tcx>, K) -> Fallible<R>, - ) -> Fallible<CanonicalQueryResponse<'tcx, R>> + operation: impl FnOnce(&ObligationCtxt<'_, 'tcx>, K) -> Result<R, NoSolution>, + ) -> Result<CanonicalQueryResponse<'tcx, R>, NoSolution> where K: TypeFoldable<TyCtxt<'tcx>>, R: Debug + TypeFoldable<TyCtxt<'tcx>>, @@ -110,8 +110,8 @@ impl<'tcx> InferCtxtBuilderExt<'tcx> for InferCtxtBuilder<'tcx> { fn enter_canonical_trait_query<K, R>( &mut self, canonical_key: &Canonical<'tcx, K>, - operation: impl FnOnce(&ObligationCtxt<'_, 'tcx>, K) -> Fallible<R>, - ) -> Fallible<CanonicalQueryResponse<'tcx, R>> + operation: impl FnOnce(&ObligationCtxt<'_, 'tcx>, K) -> Result<R, NoSolution>, + ) -> Result<CanonicalQueryResponse<'tcx, R>, NoSolution> where K: TypeFoldable<TyCtxt<'tcx>>, R: Debug + TypeFoldable<TyCtxt<'tcx>>, diff --git a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs index 0ede32c753c..0f3f8f1ac2c 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs @@ -96,7 +96,7 @@ pub(in crate::solve) fn replace_erased_lifetimes_with_bound_vars<'tcx>( let br = ty::BoundRegion { var: ty::BoundVar::from_u32(counter), kind: ty::BrAnon(None) }; counter += 1; - tcx.mk_re_late_bound(current_depth, br) + ty::Region::new_late_bound(tcx, current_depth, br) } // All free regions should be erased here. r => bug!("unexpected region: {r:?}"), @@ -148,11 +148,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<'tcx>( ty::Adt(def, substs) => { let sized_crit = def.sized_constraint(ecx.tcx()); - Ok(sized_crit - .0 - .iter() - .map(|ty| sized_crit.rebind(*ty).subst(ecx.tcx(), substs)) - .collect()) + Ok(sized_crit.subst_iter_copied(ecx.tcx(), substs).collect()) } } } diff --git a/compiler/rustc_trait_selection/src/solve/canonicalize.rs b/compiler/rustc_trait_selection/src/solve/canonicalize.rs index ff4bff10cc8..29bdb5ff67d 100644 --- a/compiler/rustc_trait_selection/src/solve/canonicalize.rs +++ b/compiler/rustc_trait_selection/src/solve/canonicalize.rs @@ -255,7 +255,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'_, 'tcx> { }), ); let br = ty::BoundRegion { var, kind: BrAnon(None) }; - self.interner().mk_re_late_bound(self.binder_index, br) + ty::Region::new_late_bound(self.interner(), self.binder_index, br) } fn fold_ty(&mut self, mut t: Ty<'tcx>) -> Ty<'tcx> { diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs index fdb209fbff8..bca2343e424 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs @@ -137,6 +137,13 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { #[instrument(level = "debug", skip(self), ret)] fn compute_external_query_constraints(&self) -> Result<ExternalConstraints<'tcx>, NoSolution> { + // We only check for leaks from universes which were entered inside + // of the query. + self.infcx.leak_check(self.max_input_universe, None).map_err(|e| { + debug!(?e, "failed the leak check"); + NoSolution + })?; + // Cannot use `take_registered_region_obligations` as we may compute the response // inside of a `probe` whenever we have multiple choices inside of the solver. let region_obligations = self.infcx.inner.borrow().region_obligations().to_owned(); diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index 26ace28f5fd..56a254d9c07 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -231,13 +231,21 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { let mut candidates = Vec::new(); // LHS normalizes-to RHS - candidates.extend( - evaluate_normalizes_to(self, alias_lhs, rhs, direction, Invert::No).ok(), - ); + candidates.extend(evaluate_normalizes_to( + self, + alias_lhs, + rhs, + direction, + Invert::No, + )); // RHS normalizes-to RHS - candidates.extend( - evaluate_normalizes_to(self, alias_rhs, lhs, direction, Invert::Yes).ok(), - ); + candidates.extend(evaluate_normalizes_to( + self, + alias_rhs, + lhs, + direction, + Invert::Yes, + )); // Relate via substs let subst_relate_response = self.probe(|ecx| { let span = tracing::span!( @@ -265,10 +273,18 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { if let Some(merged) = self.try_merge_responses(&candidates) { Ok(merged) - } else if let Ok(subst_relate_response) = subst_relate_response { - Ok(subst_relate_response) } else { - self.flounder(&candidates) + // When relating two aliases and we have ambiguity, we prefer + // relating the generic arguments of the aliases over normalizing + // them. This is necessary for inference during typeck. + // + // As this is incomplete, we must not do so during coherence. + match (self.solver_mode(), subst_relate_response) { + (SolverMode::Normal, Ok(response)) => Ok(response), + (SolverMode::Normal, Err(NoSolution)) | (SolverMode::Coherence, _) => { + self.flounder(&candidates) + } + } } } } diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index e8c5a8fab2a..d6fd457de06 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -5,7 +5,7 @@ //! [trait-specialization]: https://rustc-dev-guide.rust-lang.org/traits/specialization.html use crate::infer::outlives::env::OutlivesEnvironment; -use crate::infer::{CombinedSnapshot, InferOk}; +use crate::infer::InferOk; use crate::traits::outlives_bounds::InferCtxtExt as _; use crate::traits::select::IntercrateAmbiguityCause; use crate::traits::util::impl_subject_and_oblig; @@ -62,6 +62,21 @@ pub fn add_placeholder_note(err: &mut Diagnostic) { ); } +#[derive(Debug, Clone, Copy)] +enum TrackAmbiguityCauses { + Yes, + No, +} + +impl TrackAmbiguityCauses { + fn is_yes(self) -> bool { + match self { + TrackAmbiguityCauses::Yes => true, + TrackAmbiguityCauses::No => false, + } + } +} + /// If there are types that satisfy both impls, returns `Some` /// with a suitably-freshened `ImplHeader` with those types /// substituted. Otherwise, returns `None`. @@ -97,29 +112,28 @@ pub fn overlapping_impls( return None; } - let infcx = tcx - .infer_ctxt() - .with_opaque_type_inference(DefiningAnchor::Bubble) - .intercrate(true) - .build(); - let selcx = &mut SelectionContext::new(&infcx); - let overlaps = - overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id, overlap_mode).is_some(); - if !overlaps { - return None; - } + let _overlap_with_bad_diagnostics = overlap( + tcx, + TrackAmbiguityCauses::No, + skip_leak_check, + impl1_def_id, + impl2_def_id, + overlap_mode, + )?; // In the case where we detect an error, run the check again, but // this time tracking intercrate ambiguity causes for better // diagnostics. (These take time and can lead to false errors.) - let infcx = tcx - .infer_ctxt() - .with_opaque_type_inference(DefiningAnchor::Bubble) - .intercrate(true) - .build(); - let selcx = &mut SelectionContext::new(&infcx); - selcx.enable_tracking_intercrate_ambiguity_causes(); - Some(overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id, overlap_mode).unwrap()) + let overlap = overlap( + tcx, + TrackAmbiguityCauses::Yes, + skip_leak_check, + impl1_def_id, + impl2_def_id, + overlap_mode, + ) + .unwrap(); + Some(overlap) } fn with_fresh_ty_vars<'cx, 'tcx>( @@ -146,40 +160,34 @@ fn with_fresh_ty_vars<'cx, 'tcx>( /// Can both impl `a` and impl `b` be satisfied by a common type (including /// where-clauses)? If so, returns an `ImplHeader` that unifies the two impls. -fn overlap<'cx, 'tcx>( - selcx: &mut SelectionContext<'cx, 'tcx>, +#[instrument(level = "debug", skip(tcx))] +fn overlap<'tcx>( + tcx: TyCtxt<'tcx>, + track_ambiguity_causes: TrackAmbiguityCauses, skip_leak_check: SkipLeakCheck, impl1_def_id: DefId, impl2_def_id: DefId, overlap_mode: OverlapMode, ) -> Option<OverlapResult<'tcx>> { - debug!( - "overlap(impl1_def_id={:?}, impl2_def_id={:?}, overlap_mode={:?})", - impl1_def_id, impl2_def_id, overlap_mode - ); - - selcx.infcx.probe_maybe_skip_leak_check(skip_leak_check.is_yes(), |snapshot| { - overlap_within_probe(selcx, impl1_def_id, impl2_def_id, overlap_mode, snapshot) - }) -} - -fn overlap_within_probe<'cx, 'tcx>( - selcx: &mut SelectionContext<'cx, 'tcx>, - impl1_def_id: DefId, - impl2_def_id: DefId, - overlap_mode: OverlapMode, - snapshot: &CombinedSnapshot<'tcx>, -) -> Option<OverlapResult<'tcx>> { - let infcx = selcx.infcx; - if overlap_mode.use_negative_impl() { - if negative_impl(infcx.tcx, impl1_def_id, impl2_def_id) - || negative_impl(infcx.tcx, impl2_def_id, impl1_def_id) + if negative_impl(tcx, impl1_def_id, impl2_def_id) + || negative_impl(tcx, impl2_def_id, impl1_def_id) { return None; } } + let infcx = tcx + .infer_ctxt() + .with_opaque_type_inference(DefiningAnchor::Bubble) + .skip_leak_check(skip_leak_check.is_yes()) + .intercrate(true) + .build(); + let selcx = &mut SelectionContext::new(&infcx); + if track_ambiguity_causes.is_yes() { + selcx.enable_tracking_intercrate_ambiguity_causes(); + } + // For the purposes of this check, we don't bring any placeholder // types into scope; instead, we replace the generic types with // fresh type variables, and hence we do our evaluations in an @@ -198,18 +206,23 @@ fn overlap_within_probe<'cx, 'tcx>( } } - // We disable the leak when creating the `snapshot` by using - // `infcx.probe_maybe_disable_leak_check`. - if infcx.leak_check(true, snapshot).is_err() { + // We toggle the `leak_check` by using `skip_leak_check` when constructing the + // inference context, so this may be a noop. + if infcx.leak_check(ty::UniverseIndex::ROOT, None).is_err() { debug!("overlap: leak check failed"); return None; } let intercrate_ambiguity_causes = selcx.take_intercrate_ambiguity_causes(); debug!("overlap: intercrate_ambiguity_causes={:#?}", intercrate_ambiguity_causes); - - let involves_placeholder = - matches!(selcx.infcx.region_constraints_added_in_snapshot(snapshot), Some(true)); + let involves_placeholder = infcx + .inner + .borrow_mut() + .unwrap_region_constraints() + .data() + .constraints + .iter() + .any(|c| c.0.involves_placeholders()); let impl_header = selcx.infcx.resolve_vars_if_possible(impl1_header); Some(OverlapResult { impl_header, intercrate_ambiguity_causes, involves_placeholder }) diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs index 000427bbe83..2c5ffd664fe 100644 --- a/compiler/rustc_trait_selection/src/traits/engine.rs +++ b/compiler/rustc_trait_selection/src/traits/engine.rs @@ -14,11 +14,11 @@ use rustc_infer::infer::canonical::{ }; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk}; -use rustc_infer::traits::query::Fallible; use rustc_infer::traits::{ FulfillmentError, Obligation, ObligationCause, PredicateObligation, TraitEngineExt as _, }; use rustc_middle::arena::ArenaAllocatable; +use rustc_middle::traits::query::NoSolution; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::ToPredicate; use rustc_middle::ty::TypeFoldable; @@ -235,7 +235,7 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> { &self, inference_vars: CanonicalVarValues<'tcx>, answer: T, - ) -> Fallible<CanonicalQueryResponse<'tcx, T>> + ) -> Result<CanonicalQueryResponse<'tcx, T>, NoSolution> where T: Debug + TypeFoldable<TyCtxt<'tcx>>, Canonical<'tcx, QueryResponse<'tcx, T>>: ArenaAllocatable<'tcx>, diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index a10ececbb1e..9012bda4043 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -42,6 +42,7 @@ use rustc_session::Limit; use rustc_span::def_id::LOCAL_CRATE; use rustc_span::symbol::sym; use rustc_span::{ExpnKind, Span, DUMMY_SP}; +use std::borrow::Cow; use std::fmt; use std::iter; use std::ops::ControlFlow; @@ -1602,7 +1603,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { }), ) => Some(( ty.span, - with_forced_trimmed_paths!(format!( + with_forced_trimmed_paths!(Cow::from(format!( "type mismatch resolving `{}`", self.resolve_vars_if_possible(predicate) .print(FmtPrinter::new_with_limit( @@ -1612,7 +1613,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { )) .unwrap() .into_buffer() - )), + ))), )), _ => None, } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 82bad96ea42..b5b8c7fe3ac 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -38,6 +38,7 @@ use rustc_span::def_id::LocalDefId; use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::{BytePos, DesugaringKind, ExpnKind, MacroKind, Span, DUMMY_SP}; use rustc_target::spec::abi; +use std::borrow::Cow; use std::iter; use std::ops::Deref; @@ -186,7 +187,12 @@ pub trait TypeErrCtxtExt<'tcx> { trait_pred: ty::PolyTraitPredicate<'tcx>, ) -> bool; - fn get_closure_name(&self, def_id: DefId, err: &mut Diagnostic, msg: &str) -> Option<Symbol>; + fn get_closure_name( + &self, + def_id: DefId, + err: &mut Diagnostic, + msg: Cow<'static, str>, + ) -> Option<Symbol>; fn suggest_fn_call( &self, @@ -857,7 +863,12 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { /// Given a closure's `DefId`, return the given name of the closure. /// /// This doesn't account for reassignments, but it's only used for suggestions. - fn get_closure_name(&self, def_id: DefId, err: &mut Diagnostic, msg: &str) -> Option<Symbol> { + fn get_closure_name( + &self, + def_id: DefId, + err: &mut Diagnostic, + msg: Cow<'static, str>, + ) -> Option<Symbol> { let get_name = |err: &mut Diagnostic, kind: &hir::PatKind<'_>| -> Option<Symbol> { // Get the local name of this closure. This can be inaccurate because // of the possibility of reassignment, but this should be good enough. @@ -934,17 +945,17 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let msg = match def_id_or_name { DefIdOrName::DefId(def_id) => match self.tcx.def_kind(def_id) { DefKind::Ctor(CtorOf::Struct, _) => { - "use parentheses to construct this tuple struct".to_string() + Cow::from("use parentheses to construct this tuple struct") } DefKind::Ctor(CtorOf::Variant, _) => { - "use parentheses to construct this tuple variant".to_string() + Cow::from("use parentheses to construct this tuple variant") } - kind => format!( + kind => Cow::from(format!( "use parentheses to call this {}", self.tcx.def_kind_descr(kind, def_id) - ), + )), }, - DefIdOrName::Name(name) => format!("use parentheses to call this {name}"), + DefIdOrName::Name(name) => Cow::from(format!("use parentheses to call this {name}")), }; let args = inputs @@ -979,7 +990,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { .. })) => { err.span_label(*fn_decl_span, "consider calling this closure"); - let Some(name) = self.get_closure_name(def_id, err, &msg) else { + let Some(name) = self.get_closure_name(def_id, err, msg.clone()) else { return false; }; name.to_string() @@ -1341,7 +1352,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { err.note(msg); } else { err.message = - vec![(rustc_errors::DiagnosticMessage::Str(msg), Style::NoStyle)]; + vec![(rustc_errors::DiagnosticMessage::from(msg), Style::NoStyle)]; } err.span_label( span, @@ -2958,7 +2969,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { for ty in bound_tys.skip_binder() { with_forced_trimmed_paths!(write!(msg, "`{}`, ", ty).unwrap()); } - err.note(msg.trim_end_matches(", ")) + err.note(msg.trim_end_matches(", ").to_string()) } ty::GeneratorWitnessMIR(def_id, substs) => { use std::fmt::Write; @@ -2972,7 +2983,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let ty = bty.subst(tcx, substs); write!(msg, "`{}`, ", ty).unwrap(); } - err.note(msg.trim_end_matches(", ")) + err.note(msg.trim_end_matches(", ").to_string()) } ty::Generator(def_id, _, _) => { let sp = self.tcx.def_span(def_id); diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 2f85c32b575..88d2091de0f 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -116,6 +116,7 @@ impl<'a, 'tcx> FulfillmentContext<'tcx> { } impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { + #[inline] fn register_predicate_obligation( &mut self, infcx: &InferCtxt<'tcx>, diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index f265230ff77..4b38687eebe 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -14,10 +14,12 @@ mod object_safety; pub mod outlives_bounds; mod project; pub mod query; +#[cfg_attr(not(bootstrap), allow(hidden_glob_reexports))] mod select; mod specialize; mod structural_match; mod structural_normalize; +#[cfg_attr(not(bootstrap), allow(hidden_glob_reexports))] mod util; mod vtable; pub mod wf; @@ -485,7 +487,7 @@ fn is_impossible_method(tcx: TyCtxt<'_>, (impl_def_id, trait_item_def_id): (DefI tcx, ObligationCause::dummy_with_span(*span), param_env, - ty::EarlyBinder(*pred).subst(tcx, impl_trait_ref.substs), + ty::EarlyBinder::bind(*pred).subst(tcx, impl_trait_ref.substs), ) }) }); diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index c81bf6ebc2e..9582479941b 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -642,7 +642,7 @@ fn receiver_for_self_ty<'tcx>( if param.index == 0 { self_ty.into() } else { tcx.mk_param_from_def(param) } }); - let result = EarlyBinder(receiver_ty).subst(tcx, substs); + let result = EarlyBinder::bind(receiver_ty).subst(tcx, substs); debug!( "receiver_for_self_ty({:?}, {:?}, {:?}) = {:?}", receiver_ty, self_ty, method_def_id, result diff --git a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs index 0db80232891..f8d056e321e 100644 --- a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs @@ -1,9 +1,9 @@ use crate::infer::InferCtxt; -use crate::traits::query::type_op::{self, TypeOp, TypeOpOutput}; -use crate::traits::query::NoSolution; use crate::traits::{ObligationCause, ObligationCtxt}; use rustc_data_structures::fx::FxIndexSet; use rustc_infer::infer::resolve::OpportunisticRegionResolver; +use rustc_infer::infer::InferOk; +use rustc_middle::infer::canonical::{OriginalQueryValues, QueryRegionConstraints}; use rustc_middle::ty::{self, ParamEnv, Ty, TypeFolder, TypeVisitableExt}; use rustc_span::def_id::LocalDefId; @@ -68,24 +68,29 @@ impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> { return vec![]; } - let span = self.tcx.def_span(body_id); - let result = param_env - .and(type_op::implied_outlives_bounds::ImpliedOutlivesBounds { ty }) - .fully_perform(self); - let result = match result { - Ok(r) => r, - Err(NoSolution) => { - self.tcx.sess.delay_span_bug( - span, - "implied_outlives_bounds failed to solve all obligations", - ); - return vec![]; - } + let mut canonical_var_values = OriginalQueryValues::default(); + let canonical_ty = + self.canonicalize_query_keep_static(param_env.and(ty), &mut canonical_var_values); + let Ok(canonical_result) = self.tcx.implied_outlives_bounds(canonical_ty) else { + return vec![]; + }; + + let mut constraints = QueryRegionConstraints::default(); + let Ok(InferOk { value, obligations }) = self + .instantiate_nll_query_response_and_region_obligations( + &ObligationCause::dummy(), + param_env, + &canonical_var_values, + canonical_result, + &mut constraints, + ) else { + return vec![]; }; + assert_eq!(&obligations, &[]); - let TypeOpOutput { output, constraints, .. } = result; + if !constraints.is_empty() { + let span = self.tcx.def_span(body_id); - if let Some(constraints) = constraints { debug!(?constraints); if !constraints.member_constraints.is_empty() { span_bug!(span, "{:#?}", constraints.member_constraints); @@ -112,7 +117,7 @@ impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> { } }; - output + value } fn implied_bounds_tys( diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 51069897120..65af0bb1c4e 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -824,7 +824,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for BoundVarReplacer<'_, 'tcx> { let universe = self.universe_for(debruijn); let p = ty::PlaceholderRegion { universe, bound: br }; self.mapped_regions.insert(p, br); - self.infcx.tcx.mk_re_placeholder(p) + ty::Region::new_placeholder(self.infcx.tcx, p) } _ => r, } @@ -945,7 +945,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for PlaceholderReplacer<'_, 'tcx> { let db = ty::DebruijnIndex::from_usize( self.universe_indices.len() - index + self.current_index.as_usize() - 1, ); - self.interner().mk_re_late_bound(db, *replace_var) + ty::Region::new_late_bound(self.interner(), db, *replace_var) } None => r1, } diff --git a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs index 455b53bfb7d..709c3f432e6 100644 --- a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs +++ b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs @@ -1,6 +1,11 @@ -use rustc_middle::ty::{self, Ty, TyCtxt}; +use crate::traits::query::normalize::QueryNormalizeExt; +use crate::traits::query::NoSolution; +use crate::traits::{Normalized, ObligationCause, ObligationCtxt}; -pub use rustc_middle::traits::query::{DropckConstraint, DropckOutlivesResult}; +use rustc_data_structures::fx::FxHashSet; +use rustc_middle::traits::query::{DropckConstraint, DropckOutlivesResult}; +use rustc_middle::ty::{self, EarlyBinder, ParamEnvAnd, Ty, TyCtxt}; +use rustc_span::source_map::{Span, DUMMY_SP}; /// This returns true if the type `ty` is "trivial" for /// dropck-outlives -- that is, if it doesn't require any types to @@ -71,3 +76,263 @@ pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool { | ty::Generator(..) => false, } } + +pub fn compute_dropck_outlives_inner<'tcx>( + ocx: &ObligationCtxt<'_, 'tcx>, + goal: ParamEnvAnd<'tcx, Ty<'tcx>>, +) -> Result<DropckOutlivesResult<'tcx>, NoSolution> { + let tcx = ocx.infcx.tcx; + let ParamEnvAnd { param_env, value: for_ty } = goal; + + let mut result = DropckOutlivesResult { kinds: vec![], overflows: vec![] }; + + // A stack of types left to process. Each round, we pop + // something from the stack and invoke + // `dtorck_constraint_for_ty_inner`. This may produce new types that + // have to be pushed on the stack. This continues until we have explored + // all the reachable types from the type `for_ty`. + // + // Example: Imagine that we have the following code: + // + // ```rust + // struct A { + // value: B, + // children: Vec<A>, + // } + // + // struct B { + // value: u32 + // } + // + // fn f() { + // let a: A = ...; + // .. + // } // here, `a` is dropped + // ``` + // + // at the point where `a` is dropped, we need to figure out + // which types inside of `a` contain region data that may be + // accessed by any destructors in `a`. We begin by pushing `A` + // onto the stack, as that is the type of `a`. We will then + // invoke `dtorck_constraint_for_ty_inner` which will expand `A` + // into the types of its fields `(B, Vec<A>)`. These will get + // pushed onto the stack. Eventually, expanding `Vec<A>` will + // lead to us trying to push `A` a second time -- to prevent + // infinite recursion, we notice that `A` was already pushed + // once and stop. + let mut ty_stack = vec![(for_ty, 0)]; + + // Set used to detect infinite recursion. + let mut ty_set = FxHashSet::default(); + + let cause = ObligationCause::dummy(); + let mut constraints = DropckConstraint::empty(); + while let Some((ty, depth)) = ty_stack.pop() { + debug!( + "{} kinds, {} overflows, {} ty_stack", + result.kinds.len(), + result.overflows.len(), + ty_stack.len() + ); + dtorck_constraint_for_ty_inner(tcx, DUMMY_SP, for_ty, depth, ty, &mut constraints)?; + + // "outlives" represent types/regions that may be touched + // by a destructor. + result.kinds.append(&mut constraints.outlives); + result.overflows.append(&mut constraints.overflows); + + // If we have even one overflow, we should stop trying to evaluate further -- + // chances are, the subsequent overflows for this evaluation won't provide useful + // information and will just decrease the speed at which we can emit these errors + // (since we'll be printing for just that much longer for the often enormous types + // that result here). + if !result.overflows.is_empty() { + break; + } + + // dtorck types are "types that will get dropped but which + // do not themselves define a destructor", more or less. We have + // to push them onto the stack to be expanded. + for ty in constraints.dtorck_types.drain(..) { + let Normalized { value: ty, obligations } = + ocx.infcx.at(&cause, param_env).query_normalize(ty)?; + ocx.register_obligations(obligations); + + debug!("dropck_outlives: ty from dtorck_types = {:?}", ty); + + match ty.kind() { + // All parameters live for the duration of the + // function. + ty::Param(..) => {} + + // A projection that we couldn't resolve - it + // might have a destructor. + ty::Alias(..) => { + result.kinds.push(ty.into()); + } + + _ => { + if ty_set.insert(ty) { + ty_stack.push((ty, depth + 1)); + } + } + } + } + } + + debug!("dropck_outlives: result = {:#?}", result); + Ok(result) +} + +/// Returns a set of constraints that needs to be satisfied in +/// order for `ty` to be valid for destruction. +pub fn dtorck_constraint_for_ty_inner<'tcx>( + tcx: TyCtxt<'tcx>, + span: Span, + for_ty: Ty<'tcx>, + depth: usize, + ty: Ty<'tcx>, + constraints: &mut DropckConstraint<'tcx>, +) -> Result<(), NoSolution> { + debug!("dtorck_constraint_for_ty_inner({:?}, {:?}, {:?}, {:?})", span, for_ty, depth, ty); + + if !tcx.recursion_limit().value_within_limit(depth) { + constraints.overflows.push(ty); + return Ok(()); + } + + if trivial_dropck_outlives(tcx, ty) { + return Ok(()); + } + + match ty.kind() { + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Str + | ty::Never + | ty::Foreign(..) + | ty::RawPtr(..) + | ty::Ref(..) + | ty::FnDef(..) + | ty::FnPtr(_) + | ty::GeneratorWitness(..) + | ty::GeneratorWitnessMIR(..) => { + // these types never have a destructor + } + + ty::Array(ety, _) | ty::Slice(ety) => { + // single-element containers, behave like their element + rustc_data_structures::stack::ensure_sufficient_stack(|| { + dtorck_constraint_for_ty_inner(tcx, span, for_ty, depth + 1, *ety, constraints) + })?; + } + + ty::Tuple(tys) => rustc_data_structures::stack::ensure_sufficient_stack(|| { + for ty in tys.iter() { + dtorck_constraint_for_ty_inner(tcx, span, for_ty, depth + 1, ty, constraints)?; + } + Ok::<_, NoSolution>(()) + })?, + + ty::Closure(_, substs) => { + if !substs.as_closure().is_valid() { + // By the time this code runs, all type variables ought to + // be fully resolved. + + tcx.sess.delay_span_bug( + span, + format!("upvar_tys for closure not found. Expected capture information for closure {ty}",), + ); + return Err(NoSolution); + } + + rustc_data_structures::stack::ensure_sufficient_stack(|| { + for ty in substs.as_closure().upvar_tys() { + dtorck_constraint_for_ty_inner(tcx, span, for_ty, depth + 1, ty, constraints)?; + } + Ok::<_, NoSolution>(()) + })? + } + + ty::Generator(_, substs, _movability) => { + // rust-lang/rust#49918: types can be constructed, stored + // in the interior, and sit idle when generator yields + // (and is subsequently dropped). + // + // It would be nice to descend into interior of a + // generator to determine what effects dropping it might + // have (by looking at any drop effects associated with + // its interior). + // + // However, the interior's representation uses things like + // GeneratorWitness that explicitly assume they are not + // traversed in such a manner. So instead, we will + // simplify things for now by treating all generators as + // if they were like trait objects, where its upvars must + // all be alive for the generator's (potential) + // destructor. + // + // In particular, skipping over `_interior` is safe + // because any side-effects from dropping `_interior` can + // only take place through references with lifetimes + // derived from lifetimes attached to the upvars and resume + // argument, and we *do* incorporate those here. + + if !substs.as_generator().is_valid() { + // By the time this code runs, all type variables ought to + // be fully resolved. + tcx.sess.delay_span_bug( + span, + format!("upvar_tys for generator not found. Expected capture information for generator {ty}",), + ); + return Err(NoSolution); + } + + constraints.outlives.extend( + substs + .as_generator() + .upvar_tys() + .map(|t| -> ty::subst::GenericArg<'tcx> { t.into() }), + ); + constraints.outlives.push(substs.as_generator().resume_ty().into()); + } + + ty::Adt(def, substs) => { + let DropckConstraint { dtorck_types, outlives, overflows } = + tcx.at(span).adt_dtorck_constraint(def.did())?; + // FIXME: we can try to recursively `dtorck_constraint_on_ty` + // there, but that needs some way to handle cycles. + constraints + .dtorck_types + .extend(dtorck_types.iter().map(|t| EarlyBinder::bind(*t).subst(tcx, substs))); + constraints + .outlives + .extend(outlives.iter().map(|t| EarlyBinder::bind(*t).subst(tcx, substs))); + constraints + .overflows + .extend(overflows.iter().map(|t| EarlyBinder::bind(*t).subst(tcx, substs))); + } + + // Objects must be alive in order for their destructor + // to be called. + ty::Dynamic(..) => { + constraints.outlives.push(ty.into()); + } + + // Types that can't be resolved. Pass them forward. + ty::Alias(..) | ty::Param(..) => { + constraints.dtorck_types.push(ty); + } + + ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error(_) => { + // By the time this code runs, all type variables ought to + // be fully resolved. + return Err(NoSolution); + } + } + + Ok(()) +} diff --git a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs index edbe2de8105..a8a74d7501a 100644 --- a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs +++ b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs @@ -90,7 +90,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { Ok(EvaluationResult::EvaluatedToAmbig) } else if self.opaque_types_added_in_snapshot(snapshot) { Ok(EvaluationResult::EvaluatedToOkModuloOpaqueTypes) - } else if self.region_constraints_added_in_snapshot(snapshot).is_some() { + } else if self.region_constraints_added_in_snapshot(snapshot) { Ok(EvaluationResult::EvaluatedToOkModuloRegions) } else { Ok(EvaluationResult::EvaluatedToOk) diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs index e6db96c9e55..01d7a1e7913 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs @@ -1,8 +1,13 @@ use crate::infer::canonical::{Canonical, CanonicalQueryResponse}; -use crate::traits::query::Fallible; -use rustc_middle::ty::{ParamEnvAnd, TyCtxt}; +use crate::traits::ObligationCtxt; +use rustc_hir::def_id::{DefId, CRATE_DEF_ID}; +use rustc_infer::traits::Obligation; +use rustc_middle::traits::query::NoSolution; +use rustc_middle::traits::{ObligationCause, ObligationCauseCode}; +use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, UserSelfTy, UserSubsts, UserType}; pub use rustc_middle::traits::query::type_op::AscribeUserType; +use rustc_span::{Span, DUMMY_SP}; impl<'tcx> super::QueryTypeOp<'tcx> for AscribeUserType<'tcx> { type QueryResponse = (); @@ -17,7 +22,119 @@ impl<'tcx> super::QueryTypeOp<'tcx> for AscribeUserType<'tcx> { fn perform_query( tcx: TyCtxt<'tcx>, canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Self>>, - ) -> Fallible<CanonicalQueryResponse<'tcx, ()>> { + ) -> Result<CanonicalQueryResponse<'tcx, ()>, NoSolution> { tcx.type_op_ascribe_user_type(canonicalized) } + + fn perform_locally_in_new_solver( + ocx: &ObligationCtxt<'_, 'tcx>, + key: ParamEnvAnd<'tcx, Self>, + ) -> Result<Self::QueryResponse, NoSolution> { + type_op_ascribe_user_type_with_span(ocx, key, None) + } +} + +/// The core of the `type_op_ascribe_user_type` query: for diagnostics purposes in NLL HRTB errors, +/// this query can be re-run to better track the span of the obligation cause, and improve the error +/// message. Do not call directly unless you're in that very specific context. +pub fn type_op_ascribe_user_type_with_span<'tcx>( + ocx: &ObligationCtxt<'_, 'tcx>, + key: ParamEnvAnd<'tcx, AscribeUserType<'tcx>>, + span: Option<Span>, +) -> Result<(), NoSolution> { + let (param_env, AscribeUserType { mir_ty, user_ty }) = key.into_parts(); + debug!("type_op_ascribe_user_type: mir_ty={:?} user_ty={:?}", mir_ty, user_ty); + let span = span.unwrap_or(DUMMY_SP); + match user_ty { + UserType::Ty(user_ty) => relate_mir_and_user_ty(ocx, param_env, span, mir_ty, user_ty)?, + UserType::TypeOf(def_id, user_substs) => { + relate_mir_and_user_substs(ocx, param_env, span, mir_ty, def_id, user_substs)? + } + }; + Ok(()) +} + +#[instrument(level = "debug", skip(ocx, param_env, span))] +fn relate_mir_and_user_ty<'tcx>( + ocx: &ObligationCtxt<'_, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + span: Span, + mir_ty: Ty<'tcx>, + user_ty: Ty<'tcx>, +) -> Result<(), NoSolution> { + let cause = ObligationCause::dummy_with_span(span); + let user_ty = ocx.normalize(&cause, param_env, user_ty); + ocx.eq(&cause, param_env, mir_ty, user_ty)?; + + // FIXME(#104764): We should check well-formedness before normalization. + let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(user_ty.into())); + ocx.register_obligation(Obligation::new(ocx.infcx.tcx, cause, param_env, predicate)); + Ok(()) +} + +#[instrument(level = "debug", skip(ocx, param_env, span))] +fn relate_mir_and_user_substs<'tcx>( + ocx: &ObligationCtxt<'_, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + span: Span, + mir_ty: Ty<'tcx>, + def_id: DefId, + user_substs: UserSubsts<'tcx>, +) -> Result<(), NoSolution> { + let param_env = param_env.without_const(); + let UserSubsts { user_self_ty, substs } = user_substs; + let tcx = ocx.infcx.tcx; + let cause = ObligationCause::dummy_with_span(span); + + let ty = tcx.type_of(def_id).subst(tcx, substs); + let ty = ocx.normalize(&cause, param_env, ty); + debug!("relate_type_and_user_type: ty of def-id is {:?}", ty); + + ocx.eq(&cause, param_env, mir_ty, ty)?; + + // Prove the predicates coming along with `def_id`. + // + // Also, normalize the `instantiated_predicates` + // because otherwise we wind up with duplicate "type + // outlives" error messages. + let instantiated_predicates = tcx.predicates_of(def_id).instantiate(tcx, substs); + + debug!(?instantiated_predicates); + for (instantiated_predicate, predicate_span) in instantiated_predicates { + let span = if span == DUMMY_SP { predicate_span } else { span }; + let cause = ObligationCause::new( + span, + CRATE_DEF_ID, + ObligationCauseCode::AscribeUserTypeProvePredicate(predicate_span), + ); + let instantiated_predicate = + ocx.normalize(&cause.clone(), param_env, instantiated_predicate); + + ocx.register_obligation(Obligation::new(tcx, cause, param_env, instantiated_predicate)); + } + + if let Some(UserSelfTy { impl_def_id, self_ty }) = user_self_ty { + let self_ty = ocx.normalize(&cause, param_env, self_ty); + let impl_self_ty = tcx.type_of(impl_def_id).subst(tcx, substs); + let impl_self_ty = ocx.normalize(&cause, param_env, impl_self_ty); + + ocx.eq(&cause, param_env, self_ty, impl_self_ty)?; + let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(impl_self_ty.into())); + ocx.register_obligation(Obligation::new(tcx, cause.clone(), param_env, predicate)); + } + + // In addition to proving the predicates, we have to + // prove that `ty` is well-formed -- this is because + // the WF of `ty` is predicated on the substs being + // well-formed, and we haven't proven *that*. We don't + // want to prove the WF of types from `substs` directly because they + // haven't been normalized. + // + // FIXME(nmatsakis): Well, perhaps we should normalize + // them? This would only be relevant if some input + // type were ill-formed but did not appear in `ty`, + // which...could happen with normalization... + let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(ty.into())); + ocx.register_obligation(Obligation::new(tcx, cause, param_env, predicate)); + Ok(()) } diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs index 3d6c1d9e2b0..6d8d2103f39 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs @@ -1,11 +1,12 @@ use crate::infer::canonical::query_response; use crate::infer::InferCtxt; use crate::traits::query::type_op::TypeOpOutput; -use crate::traits::query::Fallible; use crate::traits::ObligationCtxt; +use rustc_errors::ErrorGuaranteed; use rustc_infer::infer::region_constraints::RegionConstraintData; use rustc_middle::traits::query::NoSolution; use rustc_span::source_map::DUMMY_SP; +use rustc_span::Span; use std::fmt; @@ -17,7 +18,7 @@ pub struct CustomTypeOp<F> { impl<F> CustomTypeOp<F> { pub fn new<'tcx, R>(closure: F, description: &'static str) -> Self where - F: FnOnce(&ObligationCtxt<'_, 'tcx>) -> Fallible<R>, + F: FnOnce(&ObligationCtxt<'_, 'tcx>) -> Result<R, NoSolution>, { CustomTypeOp { closure, description } } @@ -25,7 +26,7 @@ impl<F> CustomTypeOp<F> { impl<'tcx, F, R: fmt::Debug> super::TypeOp<'tcx> for CustomTypeOp<F> where - F: FnOnce(&ObligationCtxt<'_, 'tcx>) -> Fallible<R>, + F: FnOnce(&ObligationCtxt<'_, 'tcx>) -> Result<R, NoSolution>, { type Output = R; /// We can't do any custom error reporting for `CustomTypeOp`, so @@ -35,12 +36,16 @@ where /// Processes the operation and all resulting obligations, /// returning the final result along with any region constraints /// (they will be given over to the NLL region solver). - fn fully_perform(self, infcx: &InferCtxt<'tcx>) -> Fallible<TypeOpOutput<'tcx, Self>> { + fn fully_perform( + self, + infcx: &InferCtxt<'tcx>, + span: Span, + ) -> Result<TypeOpOutput<'tcx, Self>, ErrorGuaranteed> { if cfg!(debug_assertions) { info!("fully_perform({:?})", self); } - Ok(scrape_region_constraints(infcx, self.closure)?.0) + Ok(scrape_region_constraints(infcx, self.closure, self.description, span)?.0) } } @@ -54,8 +59,10 @@ impl<F> fmt::Debug for CustomTypeOp<F> { /// constraints that result, creating query-region-constraints. pub fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>( infcx: &InferCtxt<'tcx>, - op: impl FnOnce(&ObligationCtxt<'_, 'tcx>) -> Fallible<R>, -) -> Fallible<(TypeOpOutput<'tcx, Op>, RegionConstraintData<'tcx>)> { + op: impl FnOnce(&ObligationCtxt<'_, 'tcx>) -> Result<R, NoSolution>, + name: &'static str, + span: Span, +) -> Result<(TypeOpOutput<'tcx, Op>, RegionConstraintData<'tcx>), ErrorGuaranteed> { // During NLL, we expect that nobody will register region // obligations **except** as part of a custom type op (and, at the // end of each custom type op, we scrape out the region @@ -70,16 +77,17 @@ pub fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>( let value = infcx.commit_if_ok(|_| { let ocx = ObligationCtxt::new_in_snapshot(infcx); - let value = op(&ocx)?; + let value = op(&ocx).map_err(|_| { + infcx.tcx.sess.delay_span_bug(span, format!("error performing operation: {name}")) + })?; let errors = ocx.select_all_or_error(); if errors.is_empty() { Ok(value) } else { - infcx.tcx.sess.delay_span_bug( + Err(infcx.tcx.sess.delay_span_bug( DUMMY_SP, format!("errors selecting obligation during MIR typeck: {:?}", errors), - ); - Err(NoSolution) + )) } })?; diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/eq.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/eq.rs index 8c9b9610cb6..f6589308806 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/eq.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/eq.rs @@ -1,5 +1,7 @@ use crate::infer::canonical::{Canonical, CanonicalQueryResponse}; -use crate::traits::query::Fallible; +use crate::traits::ObligationCtxt; +use rustc_middle::traits::query::NoSolution; +use rustc_middle::traits::ObligationCause; use rustc_middle::ty::{ParamEnvAnd, TyCtxt}; pub use rustc_middle::traits::query::type_op::Eq; @@ -17,7 +19,15 @@ impl<'tcx> super::QueryTypeOp<'tcx> for Eq<'tcx> { fn perform_query( tcx: TyCtxt<'tcx>, canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Self>>, - ) -> Fallible<CanonicalQueryResponse<'tcx, ()>> { + ) -> Result<CanonicalQueryResponse<'tcx, ()>, NoSolution> { tcx.type_op_eq(canonicalized) } + + fn perform_locally_in_new_solver( + ocx: &ObligationCtxt<'_, 'tcx>, + key: ParamEnvAnd<'tcx, Self>, + ) -> Result<Self::QueryResponse, NoSolution> { + ocx.eq(&ObligationCause::dummy(), key.param_env, key.value.a, key.value.b)?; + Ok(()) + } } diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs index 18d7c9b1936..9989fc9c479 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs @@ -1,7 +1,15 @@ -use crate::infer::canonical::{Canonical, CanonicalQueryResponse}; -use crate::traits::query::Fallible; +use crate::traits::query::NoSolution; +use crate::traits::wf; +use crate::traits::ObligationCtxt; + +use rustc_infer::infer::canonical::Canonical; +use rustc_infer::infer::outlives::components::{push_outlives_components, Component}; use rustc_infer::traits::query::OutlivesBound; -use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt}; +use rustc_middle::infer::canonical::CanonicalQueryResponse; +use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt}; +use rustc_span::def_id::CRATE_DEF_ID; +use rustc_span::source_map::DUMMY_SP; +use smallvec::{smallvec, SmallVec}; #[derive(Copy, Clone, Debug, HashStable, TypeFoldable, TypeVisitable, Lift)] pub struct ImpliedOutlivesBounds<'tcx> { @@ -28,7 +36,7 @@ impl<'tcx> super::QueryTypeOp<'tcx> for ImpliedOutlivesBounds<'tcx> { fn perform_query( tcx: TyCtxt<'tcx>, canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Self>>, - ) -> Fallible<CanonicalQueryResponse<'tcx, Self::QueryResponse>> { + ) -> Result<CanonicalQueryResponse<'tcx, Self::QueryResponse>, NoSolution> { // FIXME this `unchecked_map` is only necessary because the // query is defined as taking a `ParamEnvAnd<Ty>`; it should // take an `ImpliedOutlivesBounds` instead @@ -39,4 +47,169 @@ impl<'tcx> super::QueryTypeOp<'tcx> for ImpliedOutlivesBounds<'tcx> { tcx.implied_outlives_bounds(canonicalized) } + + fn perform_locally_in_new_solver( + ocx: &ObligationCtxt<'_, 'tcx>, + key: ParamEnvAnd<'tcx, Self>, + ) -> Result<Self::QueryResponse, NoSolution> { + compute_implied_outlives_bounds_inner(ocx, key.param_env, key.value.ty) + } +} + +pub fn compute_implied_outlives_bounds_inner<'tcx>( + ocx: &ObligationCtxt<'_, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + ty: Ty<'tcx>, +) -> Result<Vec<OutlivesBound<'tcx>>, NoSolution> { + let tcx = ocx.infcx.tcx; + + // Sometimes when we ask what it takes for T: WF, we get back that + // U: WF is required; in that case, we push U onto this stack and + // process it next. Because the resulting predicates aren't always + // guaranteed to be a subset of the original type, so we need to store the + // WF args we've computed in a set. + let mut checked_wf_args = rustc_data_structures::fx::FxHashSet::default(); + let mut wf_args = vec![ty.into()]; + + let mut outlives_bounds: Vec<ty::OutlivesPredicate<ty::GenericArg<'tcx>, ty::Region<'tcx>>> = + vec![]; + + while let Some(arg) = wf_args.pop() { + if !checked_wf_args.insert(arg) { + continue; + } + + // Compute the obligations for `arg` to be well-formed. If `arg` is + // an unresolved inference variable, just substituted an empty set + // -- because the return type here is going to be things we *add* + // to the environment, it's always ok for this set to be smaller + // than the ultimate set. (Note: normally there won't be + // unresolved inference variables here anyway, but there might be + // during typeck under some circumstances.) + // + // FIXME(@lcnr): It's not really "always fine", having fewer implied + // bounds can be backward incompatible, e.g. #101951 was caused by + // us not dealing with inference vars in `TypeOutlives` predicates. + let obligations = wf::obligations(ocx.infcx, param_env, CRATE_DEF_ID, 0, arg, DUMMY_SP) + .unwrap_or_default(); + + for obligation in obligations { + debug!(?obligation); + assert!(!obligation.has_escaping_bound_vars()); + + // While these predicates should all be implied by other parts of + // the program, they are still relevant as they may constrain + // inference variables, which is necessary to add the correct + // implied bounds in some cases, mostly when dealing with projections. + // + // Another important point here: we only register `Projection` + // predicates, since otherwise we might register outlives + // predicates containing inference variables, and we don't + // learn anything new from those. + if obligation.predicate.has_non_region_infer() { + match obligation.predicate.kind().skip_binder() { + ty::PredicateKind::Clause(ty::Clause::Projection(..)) + | ty::PredicateKind::AliasRelate(..) => { + ocx.register_obligation(obligation.clone()); + } + _ => {} + } + } + + let pred = match obligation.predicate.kind().no_bound_vars() { + None => continue, + Some(pred) => pred, + }; + match pred { + ty::PredicateKind::Clause(ty::Clause::Trait(..)) + // FIXME(const_generics): Make sure that `<'a, 'b, const N: &'a &'b u32>` is sound + // if we ever support that + | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) + | ty::PredicateKind::Subtype(..) + | ty::PredicateKind::Coerce(..) + | ty::PredicateKind::Clause(ty::Clause::Projection(..)) + | ty::PredicateKind::ClosureKind(..) + | ty::PredicateKind::ObjectSafe(..) + | ty::PredicateKind::ConstEvaluatable(..) + | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::Ambiguous + | ty::PredicateKind::AliasRelate(..) + | ty::PredicateKind::TypeWellFormedFromEnv(..) => {} + + // We need to search through *all* WellFormed predicates + ty::PredicateKind::WellFormed(arg) => { + wf_args.push(arg); + } + + // We need to register region relationships + ty::PredicateKind::Clause(ty::Clause::RegionOutlives(ty::OutlivesPredicate( + r_a, + r_b, + ))) => outlives_bounds.push(ty::OutlivesPredicate(r_a.into(), r_b)), + + ty::PredicateKind::Clause(ty::Clause::TypeOutlives(ty::OutlivesPredicate( + ty_a, + r_b, + ))) => outlives_bounds.push(ty::OutlivesPredicate(ty_a.into(), r_b)), + } + } + } + + // This call to `select_all_or_error` is necessary to constrain inference variables, which we + // use further down when computing the implied bounds. + match ocx.select_all_or_error().as_slice() { + [] => (), + _ => return Err(NoSolution), + } + + // We lazily compute the outlives components as + // `select_all_or_error` constrains inference variables. + let implied_bounds = outlives_bounds + .into_iter() + .flat_map(|ty::OutlivesPredicate(a, r_b)| match a.unpack() { + ty::GenericArgKind::Lifetime(r_a) => vec![OutlivesBound::RegionSubRegion(r_b, r_a)], + ty::GenericArgKind::Type(ty_a) => { + let ty_a = ocx.infcx.resolve_vars_if_possible(ty_a); + let mut components = smallvec![]; + push_outlives_components(tcx, ty_a, &mut components); + implied_bounds_from_components(r_b, components) + } + ty::GenericArgKind::Const(_) => unreachable!(), + }) + .collect(); + + Ok(implied_bounds) +} + +/// When we have an implied bound that `T: 'a`, we can further break +/// this down to determine what relationships would have to hold for +/// `T: 'a` to hold. We get to assume that the caller has validated +/// those relationships. +fn implied_bounds_from_components<'tcx>( + sub_region: ty::Region<'tcx>, + sup_components: SmallVec<[Component<'tcx>; 4]>, +) -> Vec<OutlivesBound<'tcx>> { + sup_components + .into_iter() + .filter_map(|component| { + match component { + Component::Region(r) => Some(OutlivesBound::RegionSubRegion(sub_region, r)), + Component::Param(p) => Some(OutlivesBound::RegionSubParam(sub_region, p)), + Component::Alias(p) => Some(OutlivesBound::RegionSubAlias(sub_region, p)), + Component::EscapingAlias(_) => + // If the projection has escaping regions, don't + // try to infer any implied bounds even for its + // free components. This is conservative, because + // the caller will still have to prove that those + // free components outlive `sub_region`. But the + // idea is that the WAY that the caller proves + // that may change in the future and we want to + // give ourselves room to get smarter here. + { + None + } + Component::UnresolvedInferenceVariable(..) => None, + } + }) + .collect() } diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs index 9e8bc8bce9a..642fdec2d9a 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs @@ -2,13 +2,14 @@ use crate::infer::canonical::{ Canonical, CanonicalQueryResponse, OriginalQueryValues, QueryRegionConstraints, }; use crate::infer::{InferCtxt, InferOk}; -use crate::traits::query::Fallible; -use crate::traits::ObligationCause; +use crate::traits::{ObligationCause, ObligationCtxt}; +use rustc_errors::ErrorGuaranteed; use rustc_infer::infer::canonical::Certainty; -use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::PredicateObligations; +use rustc_middle::traits::query::NoSolution; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::{ParamEnvAnd, TyCtxt}; +use rustc_span::Span; use std::fmt; pub mod ascribe_user_type; @@ -22,6 +23,8 @@ pub mod subtype; pub use rustc_middle::traits::query::type_op::*; +use self::custom::scrape_region_constraints; + /// "Type ops" are used in NLL to perform some particular action and /// extract out the resulting region constraints (or an error if it /// cannot be completed). @@ -32,7 +35,11 @@ pub trait TypeOp<'tcx>: Sized + fmt::Debug { /// Processes the operation and all resulting obligations, /// returning the final result along with any region constraints /// (they will be given over to the NLL region solver). - fn fully_perform(self, infcx: &InferCtxt<'tcx>) -> Fallible<TypeOpOutput<'tcx, Self>>; + fn fully_perform( + self, + infcx: &InferCtxt<'tcx>, + span: Span, + ) -> Result<TypeOpOutput<'tcx, Self>, ErrorGuaranteed>; } /// The output from performing a type op @@ -74,18 +81,32 @@ pub trait QueryTypeOp<'tcx>: fmt::Debug + Copy + TypeFoldable<TyCtxt<'tcx>> + 't fn perform_query( tcx: TyCtxt<'tcx>, canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Self>>, - ) -> Fallible<CanonicalQueryResponse<'tcx, Self::QueryResponse>>; + ) -> Result<CanonicalQueryResponse<'tcx, Self::QueryResponse>, NoSolution>; + + /// In the new trait solver, we already do caching in the solver itself, + /// so there's no need to canonicalize and cache via the query system. + /// Additionally, even if we were to canonicalize, we'd still need to + /// make sure to feed it predefined opaque types and the defining anchor + /// and that would require duplicating all of the tcx queries. Instead, + /// just perform these ops locally. + fn perform_locally_in_new_solver( + ocx: &ObligationCtxt<'_, 'tcx>, + key: ParamEnvAnd<'tcx, Self>, + ) -> Result<Self::QueryResponse, NoSolution>; fn fully_perform_into( query_key: ParamEnvAnd<'tcx, Self>, infcx: &InferCtxt<'tcx>, output_query_region_constraints: &mut QueryRegionConstraints<'tcx>, - ) -> Fallible<( - Self::QueryResponse, - Option<Canonical<'tcx, ParamEnvAnd<'tcx, Self>>>, - PredicateObligations<'tcx>, - Certainty, - )> { + ) -> Result< + ( + Self::QueryResponse, + Option<Canonical<'tcx, ParamEnvAnd<'tcx, Self>>>, + PredicateObligations<'tcx>, + Certainty, + ), + NoSolution, + > { if let Some(result) = QueryTypeOp::try_fast_path(infcx.tcx, &query_key) { return Ok((result, None, vec![], Certainty::Proven)); } @@ -120,10 +141,26 @@ where type Output = Q::QueryResponse; type ErrorInfo = Canonical<'tcx, ParamEnvAnd<'tcx, Q>>; - fn fully_perform(self, infcx: &InferCtxt<'tcx>) -> Fallible<TypeOpOutput<'tcx, Self>> { + fn fully_perform( + self, + infcx: &InferCtxt<'tcx>, + span: Span, + ) -> Result<TypeOpOutput<'tcx, Self>, ErrorGuaranteed> { + if infcx.tcx.trait_solver_next() { + return Ok(scrape_region_constraints( + infcx, + |ocx| QueryTypeOp::perform_locally_in_new_solver(ocx, self), + "query type op", + span, + )? + .0); + } + let mut region_constraints = QueryRegionConstraints::default(); let (output, error_info, mut obligations, _) = - Q::fully_perform_into(self, infcx, &mut region_constraints)?; + Q::fully_perform_into(self, infcx, &mut region_constraints).map_err(|_| { + infcx.tcx.sess.delay_span_bug(span, format!("error performing {self:?}")) + })?; // Typically, instantiating NLL query results does not // create obligations. However, in some cases there @@ -151,7 +188,10 @@ where } } if !progress { - return Err(NoSolution); + return Err(infcx.tcx.sess.delay_span_bug( + span, + format!("ambiguity processing {obligations:?} from {self:?}"), + )); } } diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs index 5b216c07692..57ca14aa492 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs @@ -1,5 +1,7 @@ use crate::infer::canonical::{Canonical, CanonicalQueryResponse}; -use crate::traits::query::Fallible; +use crate::traits::ObligationCtxt; +use rustc_middle::traits::query::NoSolution; +use rustc_middle::traits::ObligationCause; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::{self, Lift, ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt}; use std::fmt; @@ -19,23 +21,31 @@ where fn perform_query( tcx: TyCtxt<'tcx>, canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Self>>, - ) -> Fallible<CanonicalQueryResponse<'tcx, Self::QueryResponse>> { + ) -> Result<CanonicalQueryResponse<'tcx, Self::QueryResponse>, NoSolution> { T::type_op_method(tcx, canonicalized) } + + fn perform_locally_in_new_solver( + ocx: &ObligationCtxt<'_, 'tcx>, + key: ParamEnvAnd<'tcx, Self>, + ) -> Result<Self::QueryResponse, NoSolution> { + // FIXME(-Ztrait-solver=next): shouldn't be using old normalizer + Ok(ocx.normalize(&ObligationCause::dummy(), key.param_env, key.value.value)) + } } pub trait Normalizable<'tcx>: fmt::Debug + TypeFoldable<TyCtxt<'tcx>> + Lift<'tcx> + Copy { fn type_op_method( tcx: TyCtxt<'tcx>, canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Normalize<Self>>>, - ) -> Fallible<CanonicalQueryResponse<'tcx, Self>>; + ) -> Result<CanonicalQueryResponse<'tcx, Self>, NoSolution>; } impl<'tcx> Normalizable<'tcx> for Ty<'tcx> { fn type_op_method( tcx: TyCtxt<'tcx>, canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Normalize<Self>>>, - ) -> Fallible<CanonicalQueryResponse<'tcx, Self>> { + ) -> Result<CanonicalQueryResponse<'tcx, Self>, NoSolution> { tcx.type_op_normalize_ty(canonicalized) } } @@ -44,7 +54,7 @@ impl<'tcx> Normalizable<'tcx> for ty::Predicate<'tcx> { fn type_op_method( tcx: TyCtxt<'tcx>, canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Normalize<Self>>>, - ) -> Fallible<CanonicalQueryResponse<'tcx, Self>> { + ) -> Result<CanonicalQueryResponse<'tcx, Self>, NoSolution> { tcx.type_op_normalize_predicate(canonicalized) } } @@ -53,7 +63,7 @@ impl<'tcx> Normalizable<'tcx> for ty::PolyFnSig<'tcx> { fn type_op_method( tcx: TyCtxt<'tcx>, canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Normalize<Self>>>, - ) -> Fallible<CanonicalQueryResponse<'tcx, Self>> { + ) -> Result<CanonicalQueryResponse<'tcx, Self>, NoSolution> { tcx.type_op_normalize_poly_fn_sig(canonicalized) } } @@ -62,7 +72,7 @@ impl<'tcx> Normalizable<'tcx> for ty::FnSig<'tcx> { fn type_op_method( tcx: TyCtxt<'tcx>, canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Normalize<Self>>>, - ) -> Fallible<CanonicalQueryResponse<'tcx, Self>> { + ) -> Result<CanonicalQueryResponse<'tcx, Self>, NoSolution> { tcx.type_op_normalize_fn_sig(canonicalized) } } diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs index 21ef4e24fdb..98894263374 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs @@ -1,6 +1,9 @@ use crate::infer::canonical::{Canonical, CanonicalQueryResponse}; -use crate::traits::query::dropck_outlives::{trivial_dropck_outlives, DropckOutlivesResult}; -use crate::traits::query::Fallible; +use crate::traits::query::dropck_outlives::{ + compute_dropck_outlives_inner, trivial_dropck_outlives, +}; +use crate::traits::ObligationCtxt; +use rustc_middle::traits::query::{DropckOutlivesResult, NoSolution}; use rustc_middle::ty::{ParamEnvAnd, Ty, TyCtxt}; #[derive(Copy, Clone, Debug, HashStable, TypeFoldable, TypeVisitable, Lift)] @@ -27,7 +30,7 @@ impl<'tcx> super::QueryTypeOp<'tcx> for DropckOutlives<'tcx> { fn perform_query( tcx: TyCtxt<'tcx>, canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Self>>, - ) -> Fallible<CanonicalQueryResponse<'tcx, Self::QueryResponse>> { + ) -> Result<CanonicalQueryResponse<'tcx, Self::QueryResponse>, NoSolution> { // Subtle: note that we are not invoking // `infcx.at(...).dropck_outlives(...)` here, but rather the // underlying `dropck_outlives` query. This same underlying @@ -48,4 +51,11 @@ impl<'tcx> super::QueryTypeOp<'tcx> for DropckOutlives<'tcx> { tcx.dropck_outlives(canonicalized) } + + fn perform_locally_in_new_solver( + ocx: &ObligationCtxt<'_, 'tcx>, + key: ParamEnvAnd<'tcx, Self>, + ) -> Result<Self::QueryResponse, NoSolution> { + compute_dropck_outlives_inner(ocx, key.param_env.and(key.value.dropped_ty)) + } } 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 baa2fbb6751..47850bc330d 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,5 +1,8 @@ use crate::infer::canonical::{Canonical, CanonicalQueryResponse}; -use crate::traits::query::Fallible; +use crate::traits::ObligationCtxt; +use rustc_infer::traits::Obligation; +use rustc_middle::traits::query::NoSolution; +use rustc_middle::traits::ObligationCause; use rustc_middle::ty::{self, ParamEnvAnd, TyCtxt}; pub use rustc_middle::traits::query::type_op::ProvePredicate; @@ -33,7 +36,20 @@ impl<'tcx> super::QueryTypeOp<'tcx> for ProvePredicate<'tcx> { fn perform_query( tcx: TyCtxt<'tcx>, canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Self>>, - ) -> Fallible<CanonicalQueryResponse<'tcx, ()>> { + ) -> Result<CanonicalQueryResponse<'tcx, ()>, NoSolution> { tcx.type_op_prove_predicate(canonicalized) } + + fn perform_locally_in_new_solver( + ocx: &ObligationCtxt<'_, 'tcx>, + key: ParamEnvAnd<'tcx, Self>, + ) -> Result<Self::QueryResponse, NoSolution> { + ocx.register_obligation(Obligation::new( + ocx.infcx.tcx, + ObligationCause::dummy(), + key.param_env, + key.value.predicate, + )); + Ok(()) + } } diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/subtype.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/subtype.rs index c51292eba14..10976d5cd71 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/subtype.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/subtype.rs @@ -1,5 +1,7 @@ use crate::infer::canonical::{Canonical, CanonicalQueryResponse}; -use crate::traits::query::Fallible; +use crate::traits::ObligationCtxt; +use rustc_middle::traits::query::NoSolution; +use rustc_middle::traits::ObligationCause; use rustc_middle::ty::{ParamEnvAnd, TyCtxt}; pub use rustc_middle::traits::query::type_op::Subtype; @@ -14,7 +16,15 @@ impl<'tcx> super::QueryTypeOp<'tcx> for Subtype<'tcx> { fn perform_query( tcx: TyCtxt<'tcx>, canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Self>>, - ) -> Fallible<CanonicalQueryResponse<'tcx, ()>> { + ) -> Result<CanonicalQueryResponse<'tcx, ()>, NoSolution> { tcx.type_op_subtype(canonicalized) } + + fn perform_locally_in_new_solver( + ocx: &ObligationCtxt<'_, 'tcx>, + key: ParamEnvAnd<'tcx, Self>, + ) -> Result<Self::QueryResponse, NoSolution> { + ocx.sub(&ObligationCause::dummy(), key.param_env, key.value.sub, key.value.sup)?; + Ok(()) + } } diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 8bc82b9f549..3c223db5a0b 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -360,7 +360,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // consider a "quick reject". This avoids creating more types // and so forth that we need to. let impl_trait_ref = self.tcx().impl_trait_ref(impl_def_id).unwrap(); - if !drcx.substs_refs_may_unify(obligation_substs, impl_trait_ref.0.substs) { + if !drcx + .substs_refs_may_unify(obligation_substs, impl_trait_ref.skip_binder().substs) + { return; } if self.reject_fn_ptr_impls( diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 0d9f55d4c2e..4e961c3ee73 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -527,9 +527,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { substs.extend(trait_predicate.trait_ref.substs.iter()); let mut bound_vars: smallvec::SmallVec<[ty::BoundVariableKind; 8]> = smallvec::SmallVec::with_capacity( - bound.0.kind().bound_vars().len() + defs.count(), + bound.skip_binder().kind().bound_vars().len() + defs.count(), ); - bound_vars.extend(bound.0.kind().bound_vars().into_iter()); + bound_vars.extend(bound.skip_binder().kind().bound_vars().into_iter()); InternalSubsts::fill_single(&mut substs, defs, &mut |param, _| match param .kind { @@ -550,7 +550,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let kind = ty::BoundRegionKind::BrNamed(param.def_id, param.name); let bound_var = ty::BoundVariableKind::Region(kind); bound_vars.push(bound_var); - tcx.mk_re_late_bound( + ty::Region::new_late_bound( + tcx, ty::INNERMOST, ty::BoundRegion { var: ty::BoundVar::from_usize(bound_vars.len() - 1), diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 3baf1c97c9f..42c1b629ac2 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -561,9 +561,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { op: impl FnOnce(&mut Self) -> Result<EvaluationResult, OverflowError>, ) -> Result<EvaluationResult, OverflowError> { self.infcx.probe(|snapshot| -> Result<EvaluationResult, OverflowError> { + let outer_universe = self.infcx.universe(); let result = op(self)?; - match self.infcx.leak_check(true, snapshot) { + match self.infcx.leak_check(outer_universe, Some(snapshot)) { Ok(()) => {} Err(_) => return Ok(EvaluatedToErr), } @@ -572,9 +573,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { return Ok(result.max(EvaluatedToOkModuloOpaqueTypes)); } - match self.infcx.region_constraints_added_in_snapshot(snapshot) { - None => Ok(result), - Some(_) => Ok(result.max(EvaluatedToOkModuloRegions)), + if self.infcx.region_constraints_added_in_snapshot(snapshot) { + Ok(result.max(EvaluatedToOkModuloRegions)) + } else { + Ok(result) } }) } @@ -2149,13 +2151,11 @@ impl<'tcx> SelectionContext<'_, 'tcx> { ty::Adt(def, substs) => { let sized_crit = def.sized_constraint(self.tcx()); // (*) binder moved here - Where(obligation.predicate.rebind({ - sized_crit - .0 - .iter() - .map(|ty| sized_crit.rebind(*ty).subst(self.tcx(), substs)) - .collect() - })) + Where( + obligation + .predicate + .rebind(sized_crit.subst_iter_copied(self.tcx(), substs).collect()), + ) } ty::Alias(..) | ty::Param(_) | ty::Placeholder(..) => None, @@ -3029,7 +3029,7 @@ fn bind_generator_hidden_types_above<'tcx>( kind: ty::BrAnon(None), }; counter += 1; - tcx.mk_re_late_bound(current_depth, br) + ty::Region::new_late_bound(tcx, current_depth, br) } r => bug!("unexpected region: {r:?}"), }) diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index 82f3df40198..e2c9c62512e 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -41,7 +41,12 @@ impl<'tcx> TraitAliasExpansionInfo<'tcx> { /// Adds diagnostic labels to `diag` for the expansion path of a trait through all intermediate /// trait aliases. - pub fn label_with_exp_info(&self, diag: &mut Diagnostic, top_label: &str, use_desc: &str) { + pub fn label_with_exp_info( + &self, + diag: &mut Diagnostic, + top_label: &'static str, + use_desc: &str, + ) { diag.span_label(self.top().1, top_label); if self.path.len() > 1 { for (_, sp) in self.path.iter().rev().skip(1).take(self.path.len() - 2) { diff --git a/compiler/rustc_traits/src/chalk/db.rs b/compiler/rustc_traits/src/chalk/db.rs index c319b2e31c7..38f94c38861 100644 --- a/compiler/rustc_traits/src/chalk/db.rs +++ b/compiler/rustc_traits/src/chalk/db.rs @@ -294,7 +294,7 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t }; Arc::new(chalk_solve::rust_ir::FnDefDatum { id: fn_def_id, - sig: sig.0.lower_into(self.interner), + sig: sig.skip_binder().lower_into(self.interner), binders: chalk_ir::Binders::new(binders, bound), }) } @@ -727,7 +727,7 @@ fn bound_vars_for_item(tcx: TyCtxt<'_>, def_id: DefId) -> SubstsRef<'_> { var: ty::BoundVar::from_usize(substs.len()), kind: ty::BrAnon(None), }; - tcx.mk_re_late_bound(ty::INNERMOST, br).into() + ty::Region::new_late_bound(tcx, ty::INNERMOST, br).into() } ty::GenericParamDefKind::Const { .. } => tcx diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs index e447ab94f64..e6c6e0f13df 100644 --- a/compiler/rustc_traits/src/chalk/lowering.rs +++ b/compiler/rustc_traits/src/chalk/lowering.rs @@ -542,7 +542,8 @@ impl<'tcx> LowerInto<'tcx, Region<'tcx>> for &chalk_ir::Lifetime<RustInterner<'t fn lower_into(self, interner: RustInterner<'tcx>) -> Region<'tcx> { let tcx = interner.tcx; match self.data(interner) { - chalk_ir::LifetimeData::BoundVar(var) => tcx.mk_re_late_bound( + chalk_ir::LifetimeData::BoundVar(var) => ty::Region::new_late_bound( + tcx, ty::DebruijnIndex::from_u32(var.debruijn.depth()), ty::BoundRegion { var: ty::BoundVar::from_usize(var.index), @@ -550,13 +551,16 @@ impl<'tcx> LowerInto<'tcx, Region<'tcx>> for &chalk_ir::Lifetime<RustInterner<'t }, ), chalk_ir::LifetimeData::InferenceVar(_var) => unimplemented!(), - chalk_ir::LifetimeData::Placeholder(p) => tcx.mk_re_placeholder(ty::Placeholder { - universe: ty::UniverseIndex::from_usize(p.ui.counter), - bound: ty::BoundRegion { - var: ty::BoundVar::from_usize(p.idx), - kind: ty::BoundRegionKind::BrAnon(None), + chalk_ir::LifetimeData::Placeholder(p) => ty::Region::new_placeholder( + tcx, + ty::Placeholder { + universe: ty::UniverseIndex::from_usize(p.ui.counter), + bound: ty::BoundRegion { + var: ty::BoundVar::from_usize(p.idx), + kind: ty::BoundRegionKind::BrAnon(None), + }, }, - }), + ), chalk_ir::LifetimeData::Static => tcx.lifetimes.re_static, chalk_ir::LifetimeData::Erased => tcx.lifetimes.re_erased, chalk_ir::LifetimeData::Phantom(void, _) => match *void {}, @@ -1051,7 +1055,7 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for NamedBoundVarSubstitutor<'a, 'tcx> { ty::BrNamed(def_id, _name) => match self.named_parameters.get(&def_id) { Some(_) => { let new_br = ty::BoundRegion { var: br.var, kind: ty::BrAnon(None) }; - return self.tcx.mk_re_late_bound(index, new_br); + return ty::Region::new_late_bound(self.tcx, index, new_br); } None => panic!("Missing `BrNamed`."), }, @@ -1142,7 +1146,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ParamsSubstitutor<'tcx> { var: ty::BoundVar::from_u32(*idx), kind: ty::BrAnon(None), }; - self.tcx.mk_re_late_bound(self.binder_index, br) + ty::Region::new_late_bound(self.tcx, self.binder_index, br) } None => { let idx = self.named_regions.len() as u32; @@ -1151,7 +1155,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ParamsSubstitutor<'tcx> { kind: ty::BrAnon(None), }; self.named_regions.insert(_re.def_id, idx); - self.tcx.mk_re_late_bound(self.binder_index, br) + ty::Region::new_late_bound(self.tcx, self.binder_index, br) } }, diff --git a/compiler/rustc_traits/src/dropck_outlives.rs b/compiler/rustc_traits/src/dropck_outlives.rs index 83f6c7d07fe..f35c14eeac8 100644 --- a/compiler/rustc_traits/src/dropck_outlives.rs +++ b/compiler/rustc_traits/src/dropck_outlives.rs @@ -3,17 +3,14 @@ use rustc_hir::def_id::DefId; use rustc_infer::infer::canonical::{Canonical, QueryResponse}; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::query::Providers; +use rustc_middle::traits::query::{DropckConstraint, DropckOutlivesResult}; use rustc_middle::ty::InternalSubsts; -use rustc_middle::ty::{self, EarlyBinder, ParamEnvAnd, Ty, TyCtxt}; -use rustc_span::source_map::{Span, DUMMY_SP}; +use rustc_middle::ty::TyCtxt; use rustc_trait_selection::infer::InferCtxtBuilderExt; -use rustc_trait_selection::traits::query::dropck_outlives::trivial_dropck_outlives; use rustc_trait_selection::traits::query::dropck_outlives::{ - DropckConstraint, DropckOutlivesResult, + compute_dropck_outlives_inner, dtorck_constraint_for_ty_inner, }; -use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt; use rustc_trait_selection::traits::query::{CanonicalTyGoal, NoSolution}; -use rustc_trait_selection::traits::{Normalized, ObligationCause}; pub(crate) fn provide(p: &mut Providers) { *p = Providers { dropck_outlives, adt_dtorck_constraint, ..*p }; @@ -26,263 +23,10 @@ fn dropck_outlives<'tcx>( debug!("dropck_outlives(goal={:#?})", canonical_goal); tcx.infer_ctxt().enter_canonical_trait_query(&canonical_goal, |ocx, goal| { - let tcx = ocx.infcx.tcx; - let ParamEnvAnd { param_env, value: for_ty } = goal; - - let mut result = DropckOutlivesResult { kinds: vec![], overflows: vec![] }; - - // A stack of types left to process. Each round, we pop - // something from the stack and invoke - // `dtorck_constraint_for_ty`. This may produce new types that - // have to be pushed on the stack. This continues until we have explored - // all the reachable types from the type `for_ty`. - // - // Example: Imagine that we have the following code: - // - // ```rust - // struct A { - // value: B, - // children: Vec<A>, - // } - // - // struct B { - // value: u32 - // } - // - // fn f() { - // let a: A = ...; - // .. - // } // here, `a` is dropped - // ``` - // - // at the point where `a` is dropped, we need to figure out - // which types inside of `a` contain region data that may be - // accessed by any destructors in `a`. We begin by pushing `A` - // onto the stack, as that is the type of `a`. We will then - // invoke `dtorck_constraint_for_ty` which will expand `A` - // into the types of its fields `(B, Vec<A>)`. These will get - // pushed onto the stack. Eventually, expanding `Vec<A>` will - // lead to us trying to push `A` a second time -- to prevent - // infinite recursion, we notice that `A` was already pushed - // once and stop. - let mut ty_stack = vec![(for_ty, 0)]; - - // Set used to detect infinite recursion. - let mut ty_set = FxHashSet::default(); - - let cause = ObligationCause::dummy(); - let mut constraints = DropckConstraint::empty(); - while let Some((ty, depth)) = ty_stack.pop() { - debug!( - "{} kinds, {} overflows, {} ty_stack", - result.kinds.len(), - result.overflows.len(), - ty_stack.len() - ); - dtorck_constraint_for_ty(tcx, DUMMY_SP, for_ty, depth, ty, &mut constraints)?; - - // "outlives" represent types/regions that may be touched - // by a destructor. - result.kinds.append(&mut constraints.outlives); - result.overflows.append(&mut constraints.overflows); - - // If we have even one overflow, we should stop trying to evaluate further -- - // chances are, the subsequent overflows for this evaluation won't provide useful - // information and will just decrease the speed at which we can emit these errors - // (since we'll be printing for just that much longer for the often enormous types - // that result here). - if !result.overflows.is_empty() { - break; - } - - // dtorck types are "types that will get dropped but which - // do not themselves define a destructor", more or less. We have - // to push them onto the stack to be expanded. - for ty in constraints.dtorck_types.drain(..) { - let Normalized { value: ty, obligations } = - ocx.infcx.at(&cause, param_env).query_normalize(ty)?; - ocx.register_obligations(obligations); - - debug!("dropck_outlives: ty from dtorck_types = {:?}", ty); - - match ty.kind() { - // All parameters live for the duration of the - // function. - ty::Param(..) => {} - - // A projection that we couldn't resolve - it - // might have a destructor. - ty::Alias(..) => { - result.kinds.push(ty.into()); - } - - _ => { - if ty_set.insert(ty) { - ty_stack.push((ty, depth + 1)); - } - } - } - } - } - - debug!("dropck_outlives: result = {:#?}", result); - Ok(result) + compute_dropck_outlives_inner(ocx, goal) }) } -/// Returns a set of constraints that needs to be satisfied in -/// order for `ty` to be valid for destruction. -fn dtorck_constraint_for_ty<'tcx>( - tcx: TyCtxt<'tcx>, - span: Span, - for_ty: Ty<'tcx>, - depth: usize, - ty: Ty<'tcx>, - constraints: &mut DropckConstraint<'tcx>, -) -> Result<(), NoSolution> { - debug!("dtorck_constraint_for_ty({:?}, {:?}, {:?}, {:?})", span, for_ty, depth, ty); - - if !tcx.recursion_limit().value_within_limit(depth) { - constraints.overflows.push(ty); - return Ok(()); - } - - if trivial_dropck_outlives(tcx, ty) { - return Ok(()); - } - - match ty.kind() { - ty::Bool - | ty::Char - | ty::Int(_) - | ty::Uint(_) - | ty::Float(_) - | ty::Str - | ty::Never - | ty::Foreign(..) - | ty::RawPtr(..) - | ty::Ref(..) - | ty::FnDef(..) - | ty::FnPtr(_) - | ty::GeneratorWitness(..) - | ty::GeneratorWitnessMIR(..) => { - // these types never have a destructor - } - - ty::Array(ety, _) | ty::Slice(ety) => { - // single-element containers, behave like their element - rustc_data_structures::stack::ensure_sufficient_stack(|| { - dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, *ety, constraints) - })?; - } - - ty::Tuple(tys) => rustc_data_structures::stack::ensure_sufficient_stack(|| { - for ty in tys.iter() { - dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ty, constraints)?; - } - Ok::<_, NoSolution>(()) - })?, - - ty::Closure(_, substs) => { - if !substs.as_closure().is_valid() { - // By the time this code runs, all type variables ought to - // be fully resolved. - - tcx.sess.delay_span_bug( - span, - format!("upvar_tys for closure not found. Expected capture information for closure {ty}",), - ); - return Err(NoSolution); - } - - rustc_data_structures::stack::ensure_sufficient_stack(|| { - for ty in substs.as_closure().upvar_tys() { - dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ty, constraints)?; - } - Ok::<_, NoSolution>(()) - })? - } - - ty::Generator(_, substs, _movability) => { - // rust-lang/rust#49918: types can be constructed, stored - // in the interior, and sit idle when generator yields - // (and is subsequently dropped). - // - // It would be nice to descend into interior of a - // generator to determine what effects dropping it might - // have (by looking at any drop effects associated with - // its interior). - // - // However, the interior's representation uses things like - // GeneratorWitness that explicitly assume they are not - // traversed in such a manner. So instead, we will - // simplify things for now by treating all generators as - // if they were like trait objects, where its upvars must - // all be alive for the generator's (potential) - // destructor. - // - // In particular, skipping over `_interior` is safe - // because any side-effects from dropping `_interior` can - // only take place through references with lifetimes - // derived from lifetimes attached to the upvars and resume - // argument, and we *do* incorporate those here. - - if !substs.as_generator().is_valid() { - // By the time this code runs, all type variables ought to - // be fully resolved. - tcx.sess.delay_span_bug( - span, - format!("upvar_tys for generator not found. Expected capture information for generator {ty}",), - ); - return Err(NoSolution); - } - - constraints.outlives.extend( - substs - .as_generator() - .upvar_tys() - .map(|t| -> ty::subst::GenericArg<'tcx> { t.into() }), - ); - constraints.outlives.push(substs.as_generator().resume_ty().into()); - } - - ty::Adt(def, substs) => { - let DropckConstraint { dtorck_types, outlives, overflows } = - tcx.at(span).adt_dtorck_constraint(def.did())?; - // FIXME: we can try to recursively `dtorck_constraint_on_ty` - // there, but that needs some way to handle cycles. - constraints - .dtorck_types - .extend(dtorck_types.iter().map(|t| EarlyBinder(*t).subst(tcx, substs))); - constraints - .outlives - .extend(outlives.iter().map(|t| EarlyBinder(*t).subst(tcx, substs))); - constraints - .overflows - .extend(overflows.iter().map(|t| EarlyBinder(*t).subst(tcx, substs))); - } - - // Objects must be alive in order for their destructor - // to be called. - ty::Dynamic(..) => { - constraints.outlives.push(ty.into()); - } - - // Types that can't be resolved. Pass them forward. - ty::Alias(..) | ty::Param(..) => { - constraints.dtorck_types.push(ty); - } - - ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error(_) => { - // By the time this code runs, all type variables ought to - // be fully resolved. - return Err(NoSolution); - } - } - - Ok(()) -} - /// Calculates the dtorck constraint for a type. pub(crate) fn adt_dtorck_constraint( tcx: TyCtxt<'_>, @@ -311,7 +55,7 @@ pub(crate) fn adt_dtorck_constraint( let mut result = DropckConstraint::empty(); for field in def.all_fields() { let fty = tcx.type_of(field.did).subst_identity(); - dtorck_constraint_for_ty(tcx, span, fty, 0, fty, &mut result)?; + dtorck_constraint_for_ty_inner(tcx, span, fty, 0, fty, &mut result)?; } result.outlives.extend(tcx.destructor_constraints(def)); dedup_dtorck_constraint(&mut result); diff --git a/compiler/rustc_traits/src/implied_outlives_bounds.rs b/compiler/rustc_traits/src/implied_outlives_bounds.rs index 0c2bb863e1f..959838ab348 100644 --- a/compiler/rustc_traits/src/implied_outlives_bounds.rs +++ b/compiler/rustc_traits/src/implied_outlives_bounds.rs @@ -3,18 +3,13 @@ //! [`rustc_trait_selection::traits::query::type_op::implied_outlives_bounds`]. use rustc_infer::infer::canonical::{self, Canonical}; -use rustc_infer::infer::outlives::components::{push_outlives_components, Component}; use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::traits::query::OutlivesBound; use rustc_middle::query::Providers; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; -use rustc_span::def_id::CRATE_DEF_ID; -use rustc_span::source_map::DUMMY_SP; +use rustc_middle::ty::TyCtxt; use rustc_trait_selection::infer::InferCtxtBuilderExt; -use rustc_trait_selection::traits::query::{CanonicalTyGoal, Fallible, NoSolution}; -use rustc_trait_selection::traits::wf; -use rustc_trait_selection::traits::ObligationCtxt; -use smallvec::{smallvec, SmallVec}; +use rustc_trait_selection::traits::query::type_op::implied_outlives_bounds::compute_implied_outlives_bounds_inner; +use rustc_trait_selection::traits::query::{CanonicalTyGoal, NoSolution}; pub(crate) fn provide(p: &mut Providers) { *p = Providers { implied_outlives_bounds, ..*p }; @@ -29,164 +24,6 @@ fn implied_outlives_bounds<'tcx>( > { tcx.infer_ctxt().enter_canonical_trait_query(&goal, |ocx, key| { let (param_env, ty) = key.into_parts(); - compute_implied_outlives_bounds(ocx, param_env, ty) + compute_implied_outlives_bounds_inner(ocx, param_env, ty) }) } - -fn compute_implied_outlives_bounds<'tcx>( - ocx: &ObligationCtxt<'_, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - ty: Ty<'tcx>, -) -> Fallible<Vec<OutlivesBound<'tcx>>> { - let tcx = ocx.infcx.tcx; - - // Sometimes when we ask what it takes for T: WF, we get back that - // U: WF is required; in that case, we push U onto this stack and - // process it next. Because the resulting predicates aren't always - // guaranteed to be a subset of the original type, so we need to store the - // WF args we've computed in a set. - let mut checked_wf_args = rustc_data_structures::fx::FxHashSet::default(); - let mut wf_args = vec![ty.into()]; - - let mut outlives_bounds: Vec<ty::OutlivesPredicate<ty::GenericArg<'tcx>, ty::Region<'tcx>>> = - vec![]; - - while let Some(arg) = wf_args.pop() { - if !checked_wf_args.insert(arg) { - continue; - } - - // Compute the obligations for `arg` to be well-formed. If `arg` is - // an unresolved inference variable, just substituted an empty set - // -- because the return type here is going to be things we *add* - // to the environment, it's always ok for this set to be smaller - // than the ultimate set. (Note: normally there won't be - // unresolved inference variables here anyway, but there might be - // during typeck under some circumstances.) - // - // FIXME(@lcnr): It's not really "always fine", having fewer implied - // bounds can be backward incompatible, e.g. #101951 was caused by - // us not dealing with inference vars in `TypeOutlives` predicates. - let obligations = wf::obligations(ocx.infcx, param_env, CRATE_DEF_ID, 0, arg, DUMMY_SP) - .unwrap_or_default(); - - for obligation in obligations { - debug!(?obligation); - assert!(!obligation.has_escaping_bound_vars()); - - // While these predicates should all be implied by other parts of - // the program, they are still relevant as they may constrain - // inference variables, which is necessary to add the correct - // implied bounds in some cases, mostly when dealing with projections. - // - // Another important point here: we only register `Projection` - // predicates, since otherwise we might register outlives - // predicates containing inference variables, and we don't - // learn anything new from those. - if obligation.predicate.has_non_region_infer() { - match obligation.predicate.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Projection(..)) - | ty::PredicateKind::AliasRelate(..) => { - ocx.register_obligation(obligation.clone()); - } - _ => {} - } - } - - let pred = match obligation.predicate.kind().no_bound_vars() { - None => continue, - Some(pred) => pred, - }; - match pred { - ty::PredicateKind::Clause(ty::Clause::Trait(..)) - // FIXME(const_generics): Make sure that `<'a, 'b, const N: &'a &'b u32>` is sound - // if we ever support that - | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) - | ty::PredicateKind::Subtype(..) - | ty::PredicateKind::Coerce(..) - | ty::PredicateKind::Clause(ty::Clause::Projection(..)) - | ty::PredicateKind::ClosureKind(..) - | ty::PredicateKind::ObjectSafe(..) - | ty::PredicateKind::ConstEvaluatable(..) - | ty::PredicateKind::ConstEquate(..) - | ty::PredicateKind::Ambiguous - | ty::PredicateKind::AliasRelate(..) - | ty::PredicateKind::TypeWellFormedFromEnv(..) => {} - - // We need to search through *all* WellFormed predicates - ty::PredicateKind::WellFormed(arg) => { - wf_args.push(arg); - } - - // We need to register region relationships - ty::PredicateKind::Clause(ty::Clause::RegionOutlives(ty::OutlivesPredicate( - r_a, - r_b, - ))) => outlives_bounds.push(ty::OutlivesPredicate(r_a.into(), r_b)), - - ty::PredicateKind::Clause(ty::Clause::TypeOutlives(ty::OutlivesPredicate( - ty_a, - r_b, - ))) => outlives_bounds.push(ty::OutlivesPredicate(ty_a.into(), r_b)), - } - } - } - - // This call to `select_all_or_error` is necessary to constrain inference variables, which we - // use further down when computing the implied bounds. - match ocx.select_all_or_error().as_slice() { - [] => (), - _ => return Err(NoSolution), - } - - // We lazily compute the outlives components as - // `select_all_or_error` constrains inference variables. - let implied_bounds = outlives_bounds - .into_iter() - .flat_map(|ty::OutlivesPredicate(a, r_b)| match a.unpack() { - ty::GenericArgKind::Lifetime(r_a) => vec![OutlivesBound::RegionSubRegion(r_b, r_a)], - ty::GenericArgKind::Type(ty_a) => { - let ty_a = ocx.infcx.resolve_vars_if_possible(ty_a); - let mut components = smallvec![]; - push_outlives_components(tcx, ty_a, &mut components); - implied_bounds_from_components(r_b, components) - } - ty::GenericArgKind::Const(_) => unreachable!(), - }) - .collect(); - - Ok(implied_bounds) -} - -/// When we have an implied bound that `T: 'a`, we can further break -/// this down to determine what relationships would have to hold for -/// `T: 'a` to hold. We get to assume that the caller has validated -/// those relationships. -fn implied_bounds_from_components<'tcx>( - sub_region: ty::Region<'tcx>, - sup_components: SmallVec<[Component<'tcx>; 4]>, -) -> Vec<OutlivesBound<'tcx>> { - sup_components - .into_iter() - .filter_map(|component| { - match component { - Component::Region(r) => Some(OutlivesBound::RegionSubRegion(sub_region, r)), - Component::Param(p) => Some(OutlivesBound::RegionSubParam(sub_region, p)), - Component::Alias(p) => Some(OutlivesBound::RegionSubAlias(sub_region, p)), - Component::EscapingAlias(_) => - // If the projection has escaping regions, don't - // try to infer any implied bounds even for its - // free components. This is conservative, because - // the caller will still have to prove that those - // free components outlive `sub_region`. But the - // idea is that the WAY that the caller proves - // that may change in the future and we want to - // give ourselves room to get smarter here. - { - None - } - Component::UnresolvedInferenceVariable(..) => None, - } - }) - .collect() -} diff --git a/compiler/rustc_traits/src/lib.rs b/compiler/rustc_traits/src/lib.rs index b0f9c57154f..907e2d39c51 100644 --- a/compiler/rustc_traits/src/lib.rs +++ b/compiler/rustc_traits/src/lib.rs @@ -21,7 +21,8 @@ mod normalize_erasing_regions; mod normalize_projection_ty; mod type_op; -pub use type_op::{type_op_ascribe_user_type_with_span, type_op_prove_predicate_with_cause}; +pub use rustc_trait_selection::traits::query::type_op::ascribe_user_type::type_op_ascribe_user_type_with_span; +pub use type_op::type_op_prove_predicate_with_cause; use rustc_middle::query::Providers; diff --git a/compiler/rustc_traits/src/type_op.rs b/compiler/rustc_traits/src/type_op.rs index b1cbd88ce27..9904acb1c0d 100644 --- a/compiler/rustc_traits/src/type_op.rs +++ b/compiler/rustc_traits/src/type_op.rs @@ -1,21 +1,19 @@ -use rustc_hir as hir; use rustc_infer::infer::canonical::{Canonical, QueryResponse}; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::query::Providers; -use rustc_middle::traits::{DefiningAnchor, ObligationCauseCode}; -use rustc_middle::ty::{self, FnSig, Lift, PolyFnSig, Ty, TyCtxt, TypeFoldable}; +use rustc_middle::traits::query::NoSolution; +use rustc_middle::traits::DefiningAnchor; +use rustc_middle::ty::{FnSig, Lift, PolyFnSig, Ty, TyCtxt, TypeFoldable}; use rustc_middle::ty::{ParamEnvAnd, Predicate}; -use rustc_middle::ty::{UserSelfTy, UserSubsts, UserType}; -use rustc_span::def_id::CRATE_DEF_ID; -use rustc_span::{Span, DUMMY_SP}; use rustc_trait_selection::infer::InferCtxtBuilderExt; use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt; -use rustc_trait_selection::traits::query::type_op::ascribe_user_type::AscribeUserType; +use rustc_trait_selection::traits::query::type_op::ascribe_user_type::{ + type_op_ascribe_user_type_with_span, AscribeUserType, +}; use rustc_trait_selection::traits::query::type_op::eq::Eq; use rustc_trait_selection::traits::query::type_op::normalize::Normalize; use rustc_trait_selection::traits::query::type_op::prove_predicate::ProvePredicate; use rustc_trait_selection::traits::query::type_op::subtype::Subtype; -use rustc_trait_selection::traits::query::{Fallible, NoSolution}; use rustc_trait_selection::traits::{Normalized, Obligation, ObligationCause, ObligationCtxt}; use std::fmt; @@ -42,111 +40,6 @@ fn type_op_ascribe_user_type<'tcx>( }) } -/// The core of the `type_op_ascribe_user_type` query: for diagnostics purposes in NLL HRTB errors, -/// this query can be re-run to better track the span of the obligation cause, and improve the error -/// message. Do not call directly unless you're in that very specific context. -pub fn type_op_ascribe_user_type_with_span<'tcx>( - ocx: &ObligationCtxt<'_, 'tcx>, - key: ParamEnvAnd<'tcx, AscribeUserType<'tcx>>, - span: Option<Span>, -) -> Result<(), NoSolution> { - let (param_env, AscribeUserType { mir_ty, user_ty }) = key.into_parts(); - debug!("type_op_ascribe_user_type: mir_ty={:?} user_ty={:?}", mir_ty, user_ty); - let span = span.unwrap_or(DUMMY_SP); - match user_ty { - UserType::Ty(user_ty) => relate_mir_and_user_ty(ocx, param_env, span, mir_ty, user_ty)?, - UserType::TypeOf(def_id, user_substs) => { - relate_mir_and_user_substs(ocx, param_env, span, mir_ty, def_id, user_substs)? - } - }; - Ok(()) -} - -#[instrument(level = "debug", skip(ocx, param_env, span))] -fn relate_mir_and_user_ty<'tcx>( - ocx: &ObligationCtxt<'_, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - span: Span, - mir_ty: Ty<'tcx>, - user_ty: Ty<'tcx>, -) -> Result<(), NoSolution> { - let cause = ObligationCause::dummy_with_span(span); - let user_ty = ocx.normalize(&cause, param_env, user_ty); - ocx.eq(&cause, param_env, mir_ty, user_ty)?; - - // FIXME(#104764): We should check well-formedness before normalization. - let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(user_ty.into())); - ocx.register_obligation(Obligation::new(ocx.infcx.tcx, cause, param_env, predicate)); - Ok(()) -} - -#[instrument(level = "debug", skip(ocx, param_env, span))] -fn relate_mir_and_user_substs<'tcx>( - ocx: &ObligationCtxt<'_, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - span: Span, - mir_ty: Ty<'tcx>, - def_id: hir::def_id::DefId, - user_substs: UserSubsts<'tcx>, -) -> Result<(), NoSolution> { - let param_env = param_env.without_const(); - let UserSubsts { user_self_ty, substs } = user_substs; - let tcx = ocx.infcx.tcx; - let cause = ObligationCause::dummy_with_span(span); - - let ty = tcx.type_of(def_id).subst(tcx, substs); - let ty = ocx.normalize(&cause, param_env, ty); - debug!("relate_type_and_user_type: ty of def-id is {:?}", ty); - - ocx.eq(&cause, param_env, mir_ty, ty)?; - - // Prove the predicates coming along with `def_id`. - // - // Also, normalize the `instantiated_predicates` - // because otherwise we wind up with duplicate "type - // outlives" error messages. - let instantiated_predicates = tcx.predicates_of(def_id).instantiate(tcx, substs); - - debug!(?instantiated_predicates); - for (instantiated_predicate, predicate_span) in instantiated_predicates { - let span = if span == DUMMY_SP { predicate_span } else { span }; - let cause = ObligationCause::new( - span, - CRATE_DEF_ID, - ObligationCauseCode::AscribeUserTypeProvePredicate(predicate_span), - ); - let instantiated_predicate = - ocx.normalize(&cause.clone(), param_env, instantiated_predicate); - - ocx.register_obligation(Obligation::new(tcx, cause, param_env, instantiated_predicate)); - } - - if let Some(UserSelfTy { impl_def_id, self_ty }) = user_self_ty { - let self_ty = ocx.normalize(&cause, param_env, self_ty); - let impl_self_ty = tcx.type_of(impl_def_id).subst(tcx, substs); - let impl_self_ty = ocx.normalize(&cause, param_env, impl_self_ty); - - ocx.eq(&cause, param_env, self_ty, impl_self_ty)?; - let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(impl_self_ty.into())); - ocx.register_obligation(Obligation::new(tcx, cause.clone(), param_env, predicate)); - } - - // In addition to proving the predicates, we have to - // prove that `ty` is well-formed -- this is because - // the WF of `ty` is predicated on the substs being - // well-formed, and we haven't proven *that*. We don't - // want to prove the WF of types from `substs` directly because they - // haven't been normalized. - // - // FIXME(nmatsakis): Well, perhaps we should normalize - // them? This would only be relevant if some input - // type were ill-formed but did not appear in `ty`, - // which...could happen with normalization... - let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(ty.into())); - ocx.register_obligation(Obligation::new(tcx, cause, param_env, predicate)); - Ok(()) -} - fn type_op_eq<'tcx>( tcx: TyCtxt<'tcx>, canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Eq<'tcx>>>, @@ -160,7 +53,7 @@ fn type_op_eq<'tcx>( fn type_op_normalize<'tcx, T>( ocx: &ObligationCtxt<'_, 'tcx>, key: ParamEnvAnd<'tcx, Normalize<T>>, -) -> Fallible<T> +) -> Result<T, NoSolution> where T: fmt::Debug + TypeFoldable<TyCtxt<'tcx>> + Lift<'tcx>, { diff --git a/compiler/rustc_ty_utils/messages.ftl b/compiler/rustc_ty_utils/messages.ftl index 5bc3e3c00c9..c416aa52a24 100644 --- a/compiler/rustc_ty_utils/messages.ftl +++ b/compiler/rustc_ty_utils/messages.ftl @@ -1,65 +1,65 @@ -ty_utils_needs_drop_overflow = overflow while checking whether `{$query_ty}` requires drop +ty_utils_address_and_deref_not_supported = dereferencing or taking the address is not supported in generic constants -ty_utils_generic_constant_too_complex = overly complex generic constant - .help = consider moving this anonymous constant into a `const` function - .maybe_supported = this operation may be supported in the future +ty_utils_adt_not_supported = struct/enum construction is not supported in generic constants -ty_utils_borrow_not_supported = borrowing is not supported in generic constants +ty_utils_array_not_supported = array construction is not supported in generic constants -ty_utils_address_and_deref_not_supported = dereferencing or taking the address is not supported in generic constants +ty_utils_assign_not_supported = assignment is not supported in generic constants -ty_utils_array_not_supported = array construction is not supported in generic constants +ty_utils_binary_not_supported = unsupported binary operation in generic constants ty_utils_block_not_supported = blocks are not supported in generic constants -ty_utils_never_to_any_not_supported = coercing the `never` type is not supported in generic constants - -ty_utils_tuple_not_supported = tuple construction is not supported in generic constants +ty_utils_borrow_not_supported = borrowing is not supported in generic constants -ty_utils_index_not_supported = indexing is not supported in generic constants +ty_utils_box_not_supported = allocations are not allowed in generic constants -ty_utils_field_not_supported = field access is not supported in generic constants +ty_utils_closure_and_return_not_supported = closures and function keywords are not supported in generic constants ty_utils_const_block_not_supported = const blocks are not supported in generic constants -ty_utils_adt_not_supported = struct/enum construction is not supported in generic constants +ty_utils_control_flow_not_supported = control flow is not supported in generic constants -ty_utils_pointer_not_supported = pointer casts are not allowed in generic constants +ty_utils_field_not_supported = field access is not supported in generic constants -ty_utils_yield_not_supported = generator control flow is not allowed in generic constants +ty_utils_generic_constant_too_complex = overly complex generic constant + .help = consider moving this anonymous constant into a `const` function + .maybe_supported = this operation may be supported in the future -ty_utils_loop_not_supported = loops and loop control flow are not supported in generic constants +ty_utils_impl_trait_duplicate_arg = non-defining opaque type use in defining scope + .label = generic argument `{$arg}` used twice + .note = for this opaque type -ty_utils_box_not_supported = allocations are not allowed in generic constants +ty_utils_impl_trait_not_param = non-defining opaque type use in defining scope + .label = argument `{$arg}` is not a generic parameter + .note = for this opaque type -ty_utils_binary_not_supported = unsupported binary operation in generic constants +ty_utils_index_not_supported = indexing is not supported in generic constants + +ty_utils_inline_asm_not_supported = assembly is not supported in generic constants ty_utils_logical_op_not_supported = unsupported operation in generic constants, short-circuiting operations would imply control flow -ty_utils_assign_not_supported = assignment is not supported in generic constants +ty_utils_loop_not_supported = loops and loop control flow are not supported in generic constants -ty_utils_closure_and_return_not_supported = closures and function keywords are not supported in generic constants +ty_utils_multiple_array_fields_simd_type = monomorphising SIMD type `{$ty}` with more than one array field -ty_utils_control_flow_not_supported = control flow is not supported in generic constants +ty_utils_needs_drop_overflow = overflow while checking whether `{$query_ty}` requires drop -ty_utils_inline_asm_not_supported = assembly is not supported in generic constants +ty_utils_never_to_any_not_supported = coercing the `never` type is not supported in generic constants -ty_utils_operation_not_supported = unsupported operation in generic constants +ty_utils_non_primitive_simd_type = monomorphising SIMD type `{$ty}` with a non-primitive-scalar (integer/float/pointer) element type `{$e_ty}` -ty_utils_unexpected_fnptr_associated_item = `FnPtr` trait with unexpected associated item +ty_utils_operation_not_supported = unsupported operation in generic constants -ty_utils_zero_length_simd_type = monomorphising SIMD type `{$ty}` of zero length +ty_utils_oversized_simd_type = monomorphising SIMD type `{$ty}` of length greater than {$max_lanes} -ty_utils_multiple_array_fields_simd_type = monomorphising SIMD type `{$ty}` with more than one array field +ty_utils_pointer_not_supported = pointer casts are not allowed in generic constants -ty_utils_oversized_simd_type = monomorphising SIMD type `{$ty}` of length greater than {$max_lanes} +ty_utils_tuple_not_supported = tuple construction is not supported in generic constants -ty_utils_non_primitive_simd_type = monomorphising SIMD type `{$ty}` with a non-primitive-scalar (integer/float/pointer) element type `{$e_ty}` +ty_utils_unexpected_fnptr_associated_item = `FnPtr` trait with unexpected associated item -ty_utils_impl_trait_duplicate_arg = non-defining opaque type use in defining scope - .label = generic argument `{$arg}` used twice - .note = for this opaque type +ty_utils_yield_not_supported = generator control flow is not allowed in generic constants -ty_utils_impl_trait_not_param = non-defining opaque type use in defining scope - .label = argument `{$arg}` is not a generic parameter - .note = for this opaque type +ty_utils_zero_length_simd_type = monomorphising SIMD type `{$ty}` of zero length diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index 15c19104616..5b3ffc9fc36 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -81,7 +81,7 @@ fn fn_sig_for_fn_abi<'tcx>( var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind: ty::BoundRegionKind::BrEnv, }; - let env_region = tcx.mk_re_late_bound(ty::INNERMOST, br); + let env_region = ty::Region::new_late_bound(tcx, ty::INNERMOST, br); let env_ty = tcx.closure_env_ty(def_id, substs, env_region).unwrap(); let sig = sig.skip_binder(); @@ -106,7 +106,7 @@ fn fn_sig_for_fn_abi<'tcx>( var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind: ty::BoundRegionKind::BrEnv, }; - let env_ty = tcx.mk_mut_ref(tcx.mk_re_late_bound(ty::INNERMOST, br), ty); + let env_ty = tcx.mk_mut_ref(ty::Region::new_late_bound(tcx, ty::INNERMOST, br), ty); let pin_did = tcx.require_lang_item(LangItem::Pin, None); let pin_adt_ref = tcx.adt_def(pin_did); diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs index ed574f22e61..57b4183d336 100644 --- a/compiler/rustc_ty_utils/src/assoc.rs +++ b/compiler/rustc_ty_utils/src/assoc.rs @@ -301,7 +301,7 @@ fn associated_type_for_impl_trait_in_trait( trait_assoc_ty.impl_defaultness(tcx.impl_defaultness(fn_def_id)); // Copy type_of of the opaque. - trait_assoc_ty.type_of(ty::EarlyBinder(tcx.mk_opaque( + trait_assoc_ty.type_of(ty::EarlyBinder::bind(tcx.mk_opaque( opaque_ty_def_id.to_def_id(), InternalSubsts::identity_for_item(tcx, opaque_ty_def_id), ))); diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs index 1219bb40098..ce77df0df5d 100644 --- a/compiler/rustc_ty_utils/src/consts.rs +++ b/compiler/rustc_ty_utils/src/consts.rs @@ -419,7 +419,7 @@ pub fn thir_abstract_const( let root_span = body.exprs[body_id].span; - Ok(Some(ty::EarlyBinder(recurse_build(tcx, body, body_id, root_span)?))) + Ok(Some(ty::EarlyBinder::bind(recurse_build(tcx, body, body_id, root_span)?))) } pub fn provide(providers: &mut Providers) { diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index 16cd8bc8e69..7015778e24b 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -610,7 +610,7 @@ fn generator_layout<'tcx>( ) -> Result<Layout<'tcx>, LayoutError<'tcx>> { use SavedLocalEligibility::*; let tcx = cx.tcx; - let subst_field = |ty: Ty<'tcx>| EarlyBinder(ty).subst(tcx, substs); + let subst_field = |ty: Ty<'tcx>| EarlyBinder::bind(ty).subst(tcx, substs); let Some(info) = tcx.generator_layout(def_id) else { return Err(LayoutError::Unknown(ty)); diff --git a/compiler/rustc_ty_utils/src/needs_drop.rs b/compiler/rustc_ty_utils/src/needs_drop.rs index 1f9701b9322..9d593dc5e04 100644 --- a/compiler/rustc_ty_utils/src/needs_drop.rs +++ b/compiler/rustc_ty_utils/src/needs_drop.rs @@ -210,7 +210,7 @@ fn drop_tys_helper<'tcx>( match subty.kind() { ty::Adt(adt_id, subst) => { for subty in tcx.adt_drop_tys(adt_id.did())? { - vec.push(EarlyBinder(subty).subst(tcx, subst)); + vec.push(EarlyBinder::bind(subty).subst(tcx, subst)); } } _ => vec.push(subty), diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index 65dc3c39c6a..12ad8b0842f 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -44,9 +44,7 @@ fn sized_constraint_for_ty<'tcx>( let adt_tys = adt.sized_constraint(tcx); debug!("sized_constraint_for_ty({:?}) intermediate = {:?}", ty, adt_tys); adt_tys - .0 - .iter() - .map(|ty| adt_tys.rebind(*ty).subst(tcx, substs)) + .subst_iter_copied(tcx, substs) .flat_map(|ty| sized_constraint_for_ty(tcx, adtdef, ty)) .collect() } @@ -289,12 +287,13 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ImplTraitInTraitFinder<'_, 'tcx> { let shifted_alias_ty = self.tcx.fold_regions(unshifted_alias_ty, |re, depth| { if let ty::ReLateBound(index, bv) = re.kind() { if depth != ty::INNERMOST { - return self.tcx.mk_re_error_with_message( + return ty::Region::new_error_with_message( + self.tcx, DUMMY_SP, "we shouldn't walk non-predicate binders with `impl Trait`...", ); } - self.tcx.mk_re_late_bound(index.shifted_out_to_binder(self.depth), bv) + ty::Region::new_late_bound(self.tcx, index.shifted_out_to_binder(self.depth), bv) } else { re } @@ -508,7 +507,7 @@ fn issue33140_self_ty(tcx: TyCtxt<'_>, def_id: DefId) -> Option<EarlyBinder<Ty<' if self_ty_matches { debug!("issue33140_self_ty - MATCHES!"); - Some(EarlyBinder(self_ty)) + Some(EarlyBinder::bind(self_ty)) } else { debug!("issue33140_self_ty - non-matching self type"); None diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index f6b44bdf27e..ae16fbb162e 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -52,7 +52,7 @@ pub trait Interner: Sized { type PolyFnSig: Clone + Debug + Hash + Ord; type ListBinderExistentialPredicate: Clone + Debug + Hash + Ord; type BinderListTy: Clone + Debug + Hash + Ord; - type ListTy: Clone + Debug + Hash + Ord; + type ListTy: Clone + Debug + Hash + Ord + IntoIterator<Item = Self::Ty>; type AliasTy: Clone + Debug + Hash + Ord; type ParamTy: Clone + Debug + Hash + Ord; type BoundTy: Clone + Debug + Hash + Ord; @@ -67,6 +67,9 @@ pub trait Interner: Sized { type FreeRegion: Clone + Debug + Hash + Ord; type RegionVid: Clone + Debug + Hash + Ord; type PlaceholderRegion: Clone + Debug + Hash + Ord; + + fn ty_and_mut_to_parts(ty_and_mut: Self::TypeAndMut) -> (Self::Ty, Self::Mutability); + fn mutability_is_mut(mutbl: Self::Mutability) -> bool; } /// Imagine you have a function `F: FnOnce(&[T]) -> R`, plus an iterator `iter` @@ -390,7 +393,19 @@ impl DebruijnIndex { } } -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +pub fn debug_bound_var<T: std::fmt::Write>( + fmt: &mut T, + debruijn: DebruijnIndex, + var: impl std::fmt::Debug, +) -> Result<(), std::fmt::Error> { + if debruijn == INNERMOST { + write!(fmt, "^{:?}", var) + } else { + write!(fmt, "^{}_{:?}", debruijn.index(), var) + } +} + +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Encodable, Decodable, HashStable_Generic)] pub enum IntTy { Isize, @@ -448,7 +463,7 @@ impl IntTy { } } -#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, Debug)] +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy)] #[derive(Encodable, Decodable, HashStable_Generic)] pub enum UintTy { Usize, @@ -506,7 +521,7 @@ impl UintTy { } } -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Encodable, Decodable, HashStable_Generic)] pub enum FloatTy { F32, diff --git a/compiler/rustc_type_ir/src/structural_impls.rs b/compiler/rustc_type_ir/src/structural_impls.rs index 45a2e9023c9..553d7f31b2d 100644 --- a/compiler/rustc_type_ir/src/structural_impls.rs +++ b/compiler/rustc_type_ir/src/structural_impls.rs @@ -4,11 +4,12 @@ use crate::fold::{FallibleTypeFolder, TypeFoldable}; use crate::visit::{TypeVisitable, TypeVisitor}; -use crate::Interner; +use crate::{FloatTy, IntTy, Interner, UintTy}; use rustc_data_structures::functor::IdFunctor; use rustc_data_structures::sync::Lrc; use rustc_index::{Idx, IndexVec}; +use core::fmt; use std::ops::ControlFlow; /////////////////////////////////////////////////////////////////////////// @@ -163,3 +164,21 @@ impl<I: Interner, T: TypeVisitable<I>, Ix: Idx> TypeVisitable<I> for IndexVec<Ix self.iter().try_for_each(|t| t.visit_with(visitor)) } } + +impl fmt::Debug for IntTy { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.name_str()) + } +} + +impl fmt::Debug for UintTy { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.name_str()) + } +} + +impl fmt::Debug for FloatTy { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.name_str()) + } +} diff --git a/compiler/rustc_type_ir/src/sty.rs b/compiler/rustc_type_ir/src/sty.rs index f7344bacc02..fa18f921ee4 100644 --- a/compiler/rustc_type_ir/src/sty.rs +++ b/compiler/rustc_type_ir/src/sty.rs @@ -294,7 +294,7 @@ impl<I: Interner> Clone for TyKind<I> { Str => Str, Array(t, c) => Array(t.clone(), c.clone()), Slice(t) => Slice(t.clone()), - RawPtr(t) => RawPtr(t.clone()), + RawPtr(p) => RawPtr(p.clone()), Ref(r, t, m) => Ref(r.clone(), t.clone(), m.clone()), FnDef(d, s) => FnDef(d.clone(), s.clone()), FnPtr(s) => FnPtr(s.clone()), @@ -499,33 +499,65 @@ impl<I: Interner> hash::Hash for TyKind<I> { impl<I: Interner> fmt::Debug for TyKind<I> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - Bool => f.write_str("Bool"), - Char => f.write_str("Char"), - Int(i) => f.debug_tuple_field1_finish("Int", i), - Uint(u) => f.debug_tuple_field1_finish("Uint", u), - Float(float) => f.debug_tuple_field1_finish("Float", float), + Bool => write!(f, "bool"), + Char => write!(f, "char"), + Int(i) => write!(f, "{i:?}"), + Uint(u) => write!(f, "{u:?}"), + Float(float) => write!(f, "{float:?}"), Adt(d, s) => f.debug_tuple_field2_finish("Adt", d, s), Foreign(d) => f.debug_tuple_field1_finish("Foreign", d), - Str => f.write_str("Str"), - Array(t, c) => f.debug_tuple_field2_finish("Array", t, c), - Slice(t) => f.debug_tuple_field1_finish("Slice", t), - RawPtr(t) => f.debug_tuple_field1_finish("RawPtr", t), - Ref(r, t, m) => f.debug_tuple_field3_finish("Ref", r, t, m), + Str => write!(f, "str"), + Array(t, c) => write!(f, "[{t:?}; {c:?}]"), + Slice(t) => write!(f, "[{t:?}]"), + RawPtr(p) => { + let (ty, mutbl) = I::ty_and_mut_to_parts(p.clone()); + match I::mutability_is_mut(mutbl) { + true => write!(f, "*mut "), + false => write!(f, "*const "), + }?; + write!(f, "{ty:?}") + } + Ref(r, t, m) => match I::mutability_is_mut(m.clone()) { + true => write!(f, "&{r:?} mut {t:?}"), + false => write!(f, "&{r:?} {t:?}"), + }, FnDef(d, s) => f.debug_tuple_field2_finish("FnDef", d, s), - FnPtr(s) => f.debug_tuple_field1_finish("FnPtr", s), - Dynamic(p, r, repr) => f.debug_tuple_field3_finish("Dynamic", p, r, repr), + FnPtr(s) => write!(f, "{s:?}"), + Dynamic(p, r, repr) => match repr { + DynKind::Dyn => write!(f, "dyn {p:?} + {r:?}"), + DynKind::DynStar => write!(f, "dyn* {p:?} + {r:?}"), + }, Closure(d, s) => f.debug_tuple_field2_finish("Closure", d, s), Generator(d, s, m) => f.debug_tuple_field3_finish("Generator", d, s, m), GeneratorWitness(g) => f.debug_tuple_field1_finish("GeneratorWitness", g), GeneratorWitnessMIR(d, s) => f.debug_tuple_field2_finish("GeneratorWitnessMIR", d, s), - Never => f.write_str("Never"), - Tuple(t) => f.debug_tuple_field1_finish("Tuple", t), + Never => write!(f, "!"), + Tuple(t) => { + let mut iter = t.clone().into_iter(); + + write!(f, "(")?; + + match iter.next() { + None => return write!(f, ")"), + Some(ty) => write!(f, "{ty:?}")?, + }; + + match iter.next() { + None => return write!(f, ",)"), + Some(ty) => write!(f, "{ty:?})")?, + } + + for ty in iter { + write!(f, ", {ty:?}")?; + } + write!(f, ")") + } Alias(i, a) => f.debug_tuple_field2_finish("Alias", i, a), - Param(p) => f.debug_tuple_field1_finish("Param", p), - Bound(d, b) => f.debug_tuple_field2_finish("Bound", d, b), - Placeholder(p) => f.debug_tuple_field1_finish("Placeholder", p), - Infer(t) => f.debug_tuple_field1_finish("Infer", t), - TyKind::Error(e) => f.debug_tuple_field1_finish("Error", e), + Param(p) => write!(f, "{p:?}"), + Bound(d, b) => crate::debug_bound_var(f, *d, b), + Placeholder(p) => write!(f, "{p:?}"), + Infer(t) => write!(f, "{t:?}"), + TyKind::Error(_) => write!(f, "{{type error}}"), } } } diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 498fbd93288..c524d4c0367 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -1851,7 +1851,7 @@ impl String { } /// Consumes and leaks the `String`, returning a mutable reference to the contents, - /// `&'static mut str`. + /// `&'a mut str`. /// /// This is mainly useful for data that lives for the remainder of /// the program's life. Dropping the returned reference will cause a memory @@ -1874,7 +1874,7 @@ impl String { /// ``` #[unstable(feature = "string_leak", issue = "102929")] #[inline] - pub fn leak(self) -> &'static mut str { + pub fn leak<'a>(self) -> &'a mut str { let slice = self.vec.leak(); unsafe { from_utf8_unchecked_mut(slice) } } diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 82f30a26d41..47661a3d384 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -2662,7 +2662,6 @@ impl<T: Clone, A: Allocator + Clone> Clone for Vec<T, A> { /// as required by the `core::borrow::Borrow` implementation. /// /// ``` -/// #![feature(build_hasher_simple_hash_one)] /// use std::hash::BuildHasher; /// /// let b = std::collections::hash_map::RandomState::new(); diff --git a/library/alloc/tests/str.rs b/library/alloc/tests/str.rs index c1dbbde08b6..0ba5d088f61 100644 --- a/library/alloc/tests/str.rs +++ b/library/alloc/tests/str.rs @@ -1,3 +1,5 @@ +#![cfg_attr(not(bootstrap), allow(invalid_from_utf8))] + use std::assert_matches::assert_matches; use std::borrow::Cow; use std::cmp::Ordering::{Equal, Greater, Less}; diff --git a/library/core/src/alloc/global.rs b/library/core/src/alloc/global.rs index 18da70451f2..c582111701a 100644 --- a/library/core/src/alloc/global.rs +++ b/library/core/src/alloc/global.rs @@ -235,7 +235,8 @@ pub unsafe trait GlobalAlloc { /// * `new_size` must be greater than zero. /// /// * `new_size`, when rounded up to the nearest multiple of `layout.align()`, - /// must not overflow (i.e., the rounded value must be less than `usize::MAX`). + /// must not overflow isize (i.e., the rounded value must be less than or + /// equal to `isize::MAX`). /// /// (Extension subtraits might provide more specific bounds on /// behavior, e.g., guarantee a sentinel address or a null pointer diff --git a/library/core/src/alloc/mod.rs b/library/core/src/alloc/mod.rs index d6ae2b8213f..78091c01729 100644 --- a/library/core/src/alloc/mod.rs +++ b/library/core/src/alloc/mod.rs @@ -94,8 +94,9 @@ impl fmt::Display for AllocError { /// /// # Safety /// -/// * Memory blocks returned from an allocator must point to valid memory and retain their validity -/// until the instance and all of its copies and clones are dropped, +/// * Memory blocks returned from an allocator that are [*currently allocated*] must point to +/// valid memory and retain their validity while they are [*currently allocated*] and at +/// least one of the instance and all of its clones has not been dropped. /// /// * copying, cloning, or moving the allocator must not invalidate memory blocks returned from this /// allocator. A copied or cloned allocator must behave like the same allocator, and diff --git a/library/core/src/any.rs b/library/core/src/any.rs index d1c1ae6526b..7969f4055dd 100644 --- a/library/core/src/any.rs +++ b/library/core/src/any.rs @@ -662,12 +662,20 @@ impl dyn Any + Send + Sync { /// While `TypeId` implements `Hash`, `PartialOrd`, and `Ord`, it is worth /// noting that the hashes and ordering will vary between Rust releases. Beware /// of relying on them inside of your code! -#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Clone, Copy, Debug, Hash, Eq, PartialOrd, Ord)] #[stable(feature = "rust1", since = "1.0.0")] pub struct TypeId { t: u64, } +#[stable(feature = "rust1", since = "1.0.0")] +impl PartialEq for TypeId { + #[inline] + fn eq(&self, other: &Self) -> bool { + self.t == other.t + } +} + impl TypeId { /// Returns the `TypeId` of the type this generic function has been /// instantiated with. diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index bdb4c975909..76b3589b9e4 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -204,6 +204,7 @@ where { type Error = TryFromSliceError; + #[inline] fn try_from(slice: &[T]) -> Result<[T; N], TryFromSliceError> { <&Self>::try_from(slice).map(|r| *r) } @@ -228,6 +229,7 @@ where { type Error = TryFromSliceError; + #[inline] fn try_from(slice: &mut [T]) -> Result<[T; N], TryFromSliceError> { <Self>::try_from(&*slice) } @@ -249,6 +251,7 @@ where impl<'a, T, const N: usize> TryFrom<&'a [T]> for &'a [T; N] { type Error = TryFromSliceError; + #[inline] fn try_from(slice: &'a [T]) -> Result<&'a [T; N], TryFromSliceError> { if slice.len() == N { let ptr = slice.as_ptr() as *const [T; N]; @@ -276,6 +279,7 @@ impl<'a, T, const N: usize> TryFrom<&'a [T]> for &'a [T; N] { impl<'a, T, const N: usize> TryFrom<&'a mut [T]> for &'a mut [T; N] { type Error = TryFromSliceError; + #[inline] fn try_from(slice: &'a mut [T]) -> Result<&'a mut [T; N], TryFromSliceError> { if slice.len() == N { let ptr = slice.as_mut_ptr() as *mut [T; N]; @@ -291,7 +295,6 @@ impl<'a, T, const N: usize> TryFrom<&'a mut [T]> for &'a mut [T; N] { /// as required by the `Borrow` implementation. /// /// ``` -/// #![feature(build_hasher_simple_hash_one)] /// use std::hash::BuildHasher; /// /// let b = std::collections::hash_map::RandomState::new(); @@ -535,29 +538,6 @@ impl<T, const N: usize> [T; N] { drain_array_with(self, |iter| try_from_trusted_iterator(iter.map(f))) } - /// 'Zips up' two arrays into a single array of pairs. - /// - /// `zip()` returns a new array where every element is a tuple where the - /// first element comes from the first array, and the second element comes - /// from the second array. In other words, it zips two arrays together, - /// into a single one. - /// - /// # Examples - /// - /// ``` - /// #![feature(array_zip)] - /// let x = [1, 2, 3]; - /// let y = [4, 5, 6]; - /// let z = x.zip(y); - /// assert_eq!(z, [(1, 4), (2, 5), (3, 6)]); - /// ``` - #[unstable(feature = "array_zip", issue = "80094")] - pub fn zip<U>(self, rhs: [U; N]) -> [(T, U); N] { - drain_array_with(self, |lhs| { - drain_array_with(rhs, |rhs| from_trusted_iterator(crate::iter::zip(lhs, rhs))) - }) - } - /// Returns a slice containing the entire array. Equivalent to `&s[..]`. #[stable(feature = "array_as_slice", since = "1.57.0")] #[rustc_const_stable(feature = "array_as_slice", since = "1.57.0")] diff --git a/library/core/src/hash/mod.rs b/library/core/src/hash/mod.rs index a73b5b610a4..ca7c0772de8 100644 --- a/library/core/src/hash/mod.rs +++ b/library/core/src/hash/mod.rs @@ -674,8 +674,6 @@ pub trait BuildHasher { /// # Example /// /// ``` - /// #![feature(build_hasher_simple_hash_one)] - /// /// use std::cmp::{max, min}; /// use std::hash::{BuildHasher, Hash, Hasher}; /// struct OrderAmbivalentPair<T: Ord>(T, T); @@ -697,7 +695,7 @@ pub trait BuildHasher { /// bh.hash_one(&OrderAmbivalentPair(2, 10)) /// ); /// ``` - #[unstable(feature = "build_hasher_simple_hash_one", issue = "86161")] + #[stable(feature = "build_hasher_simple_hash_one", since = "CURRENT_RUSTC_VERSION")] fn hash_one<T: Hash>(&self, x: T) -> u64 where Self: Sized, diff --git a/library/core/src/iter/range.rs b/library/core/src/iter/range.rs index 0171d89812f..462f7170a55 100644 --- a/library/core/src/iter/range.rs +++ b/library/core/src/iter/range.rs @@ -619,9 +619,10 @@ impl<T: TrustedStep> RangeIteratorImpl for ops::Range<T> { #[inline] fn spec_next(&mut self) -> Option<T> { if self.start < self.end { + let old = self.start; // SAFETY: just checked precondition - let n = unsafe { Step::forward_unchecked(self.start.clone(), 1) }; - Some(mem::replace(&mut self.start, n)) + self.start = unsafe { Step::forward_unchecked(old, 1) }; + Some(old) } else { None } @@ -629,15 +630,15 @@ impl<T: TrustedStep> RangeIteratorImpl for ops::Range<T> { #[inline] fn spec_nth(&mut self, n: usize) -> Option<T> { - if let Some(plus_n) = Step::forward_checked(self.start.clone(), n) { + if let Some(plus_n) = Step::forward_checked(self.start, n) { if plus_n < self.end { // SAFETY: just checked precondition - self.start = unsafe { Step::forward_unchecked(plus_n.clone(), 1) }; + self.start = unsafe { Step::forward_unchecked(plus_n, 1) }; return Some(plus_n); } } - self.start = self.end.clone(); + self.start = self.end; None } @@ -655,7 +656,7 @@ impl<T: TrustedStep> RangeIteratorImpl for ops::Range<T> { // then steps_between either returns a bound to which we clamp or returns None which // together with the initial inequality implies more than usize::MAX steps. // Otherwise 0 is returned which always safe to use. - self.start = unsafe { Step::forward_unchecked(self.start.clone(), taken) }; + self.start = unsafe { Step::forward_unchecked(self.start, taken) }; NonZeroUsize::new(n - taken).map_or(Ok(()), Err) } @@ -664,8 +665,8 @@ impl<T: TrustedStep> RangeIteratorImpl for ops::Range<T> { fn spec_next_back(&mut self) -> Option<T> { if self.start < self.end { // SAFETY: just checked precondition - self.end = unsafe { Step::backward_unchecked(self.end.clone(), 1) }; - Some(self.end.clone()) + self.end = unsafe { Step::backward_unchecked(self.end, 1) }; + Some(self.end) } else { None } @@ -673,15 +674,15 @@ impl<T: TrustedStep> RangeIteratorImpl for ops::Range<T> { #[inline] fn spec_nth_back(&mut self, n: usize) -> Option<T> { - if let Some(minus_n) = Step::backward_checked(self.end.clone(), n) { + if let Some(minus_n) = Step::backward_checked(self.end, n) { if minus_n > self.start { // SAFETY: just checked precondition self.end = unsafe { Step::backward_unchecked(minus_n, 1) }; - return Some(self.end.clone()); + return Some(self.end); } } - self.end = self.start.clone(); + self.end = self.start; None } @@ -696,7 +697,7 @@ impl<T: TrustedStep> RangeIteratorImpl for ops::Range<T> { let taken = available.min(n); // SAFETY: same as the spec_advance_by() implementation - self.end = unsafe { Step::backward_unchecked(self.end.clone(), taken) }; + self.end = unsafe { Step::backward_unchecked(self.end, taken) }; NonZeroUsize::new(n - taken).map_or(Ok(()), Err) } diff --git a/library/core/src/iter/traits/marker.rs b/library/core/src/iter/traits/marker.rs index af02848233d..c21a2aac1c9 100644 --- a/library/core/src/iter/traits/marker.rs +++ b/library/core/src/iter/traits/marker.rs @@ -86,4 +86,4 @@ pub unsafe trait InPlaceIterable: Iterator {} /// for details. Consumers are free to rely on the invariants in unsafe code. #[unstable(feature = "trusted_step", issue = "85731")] #[rustc_specialization_trait] -pub unsafe trait TrustedStep: Step {} +pub unsafe trait TrustedStep: Step + Copy {} diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index b24882ddb17..c4134dbcd25 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -1427,7 +1427,7 @@ pub(crate) mod builtin { #[rustc_builtin_macro] #[macro_export] #[rustc_diagnostic_item = "assert_macro"] - #[allow_internal_unstable(core_panic, edition_panic)] + #[allow_internal_unstable(core_panic, edition_panic, generic_assert_internals)] macro_rules! assert { ($cond:expr $(,)?) => {{ /* compiler built-in */ }}; ($cond:expr, $($arg:tt)+) => {{ /* compiler built-in */ }}; diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index bd1b16e8d73..62003ddf515 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -3005,8 +3005,9 @@ impl<T> [T] { /// /// # Current implementation /// - /// The current algorithm is based on the quickselect portion of the same quicksort algorithm - /// used for [`sort_unstable`]. + /// The current algorithm is an introselect implementation based on Pattern Defeating Quicksort, which is also + /// the basis for [`sort_unstable`]. The fallback algorithm is Median of Medians using Tukey's Ninther for + /// pivot selection, which guarantees linear runtime for all inputs. /// /// [`sort_unstable`]: slice::sort_unstable /// @@ -3056,8 +3057,9 @@ impl<T> [T] { /// /// # Current implementation /// - /// The current algorithm is based on the quickselect portion of the same quicksort algorithm - /// used for [`sort_unstable`]. + /// The current algorithm is an introselect implementation based on Pattern Defeating Quicksort, which is also + /// the basis for [`sort_unstable`]. The fallback algorithm is Median of Medians using Tukey's Ninther for + /// pivot selection, which guarantees linear runtime for all inputs. /// /// [`sort_unstable`]: slice::sort_unstable /// @@ -3111,8 +3113,9 @@ impl<T> [T] { /// /// # Current implementation /// - /// The current algorithm is based on the quickselect portion of the same quicksort algorithm - /// used for [`sort_unstable`]. + /// The current algorithm is an introselect implementation based on Pattern Defeating Quicksort, which is also + /// the basis for [`sort_unstable`]. The fallback algorithm is Median of Medians using Tukey's Ninther for + /// pivot selection, which guarantees linear runtime for all inputs. /// /// [`sort_unstable`]: slice::sort_unstable /// diff --git a/library/core/src/str/converts.rs b/library/core/src/str/converts.rs index 5f8748206d7..0f23cf7ae23 100644 --- a/library/core/src/str/converts.rs +++ b/library/core/src/str/converts.rs @@ -84,6 +84,7 @@ use super::Utf8Error; #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_str_from_utf8_shared", since = "1.63.0")] #[rustc_allow_const_fn_unstable(str_internals)] +#[rustc_diagnostic_item = "str_from_utf8"] pub const fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error> { // FIXME: This should use `?` again, once it's `const` match run_utf8_validation(v) { @@ -127,6 +128,7 @@ pub const fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error> { /// errors that can be returned. #[stable(feature = "str_mut_extras", since = "1.20.0")] #[rustc_const_unstable(feature = "const_str_from_utf8", issue = "91006")] +#[rustc_diagnostic_item = "str_from_utf8_mut"] pub const fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> { // This should use `?` again, once it's `const` match run_utf8_validation(v) { @@ -167,6 +169,7 @@ pub const fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> { #[must_use] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_str_from_utf8_unchecked", since = "1.55.0")] +#[rustc_diagnostic_item = "str_from_utf8_unchecked"] pub const unsafe fn from_utf8_unchecked(v: &[u8]) -> &str { // SAFETY: the caller must guarantee that the bytes `v` are valid UTF-8. // Also relies on `&str` and `&[u8]` having the same layout. @@ -194,6 +197,7 @@ pub const unsafe fn from_utf8_unchecked(v: &[u8]) -> &str { #[must_use] #[stable(feature = "str_mut_extras", since = "1.20.0")] #[rustc_const_unstable(feature = "const_str_from_utf8_unchecked_mut", issue = "91005")] +#[rustc_diagnostic_item = "str_from_utf8_unchecked_mut"] pub const unsafe fn from_utf8_unchecked_mut(v: &mut [u8]) -> &mut str { // SAFETY: the caller must guarantee that the bytes `v` // are valid UTF-8, thus the cast to `*mut str` is safe. diff --git a/library/portable-simd/Cargo.toml b/library/portable-simd/Cargo.toml index 9802386e456..d1732aaec2f 100644 --- a/library/portable-simd/Cargo.toml +++ b/library/portable-simd/Cargo.toml @@ -1,5 +1,5 @@ [workspace] - +resolver = "1" members = [ "crates/core_simd", "crates/std_float", diff --git a/library/std/src/ffi/mod.rs b/library/std/src/ffi/mod.rs index d987bf69b25..3ddb8748753 100644 --- a/library/std/src/ffi/mod.rs +++ b/library/std/src/ffi/mod.rs @@ -127,6 +127,14 @@ //! trait, which provides a [`from_wide`] method to convert a native Windows //! string (without the terminating nul character) to an [`OsString`]. //! +//! ## On all platforms +//! +//! On all platforms, [`OsStr`] consists of a sequence of bytes that is encoded as a superset of +//! UTF-8; see [`OsString`] for more details on its encoding on different platforms. +//! +//! For limited, inexpensive conversions from and to bytes, see [`OsStr::as_os_str_bytes`] and +//! [`OsStr::from_os_str_bytes_unchecked`]. +//! //! [Unicode scalar value]: https://www.unicode.org/glossary/#unicode_scalar_value //! [Unicode code point]: https://www.unicode.org/glossary/#code_point //! [`env::set_var()`]: crate::env::set_var "env::set_var" diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index 5c0541d3caf..bb577acf769 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -667,6 +667,51 @@ impl OsStr { s.as_ref() } + /// Converts a slice of bytes to an OS string slice without checking that the string contains + /// valid `OsStr`-encoded data. + /// + /// The byte encoding is an unspecified, platform-specific, self-synchronizing superset of UTF-8. + /// By being a self-synchronizing superset of UTF-8, this encoding is also a superset of 7-bit + /// ASCII. + /// + /// See the [module's toplevel documentation about conversions][conversions] for safe, + /// cross-platform [conversions] from/to native representations. + /// + /// # Safety + /// + /// As the encoding is unspecified, callers must pass in bytes that originated as a mixture of + /// validated UTF-8 and bytes from [`OsStr::as_os_str_bytes`] from within the same rust version + /// built for the same target platform. For example, reconstructing an `OsStr` from bytes sent + /// over the network or stored in a file will likely violate these safety rules. + /// + /// Due to the encoding being self-synchronizing, the bytes from [`OsStr::as_os_str_bytes`] can be + /// split either immediately before or immediately after any valid non-empty UTF-8 substring. + /// + /// # Example + /// + /// ``` + /// #![feature(os_str_bytes)] + /// + /// use std::ffi::OsStr; + /// + /// let os_str = OsStr::new("Mary had a little lamb"); + /// let bytes = os_str.as_os_str_bytes(); + /// let words = bytes.split(|b| *b == b' '); + /// let words: Vec<&OsStr> = words.map(|word| { + /// // SAFETY: + /// // - Each `word` only contains content that originated from `OsStr::as_os_str_bytes` + /// // - Only split with ASCII whitespace which is a non-empty UTF-8 substring + /// unsafe { OsStr::from_os_str_bytes_unchecked(word) } + /// }).collect(); + /// ``` + /// + /// [conversions]: super#conversions + #[inline] + #[unstable(feature = "os_str_bytes", issue = "111544")] + pub unsafe fn from_os_str_bytes_unchecked(bytes: &[u8]) -> &Self { + Self::from_inner(Slice::from_os_str_bytes_unchecked(bytes)) + } + #[inline] fn from_inner(inner: &Slice) -> &OsStr { // SAFETY: OsStr is just a wrapper of Slice, @@ -837,13 +882,24 @@ impl OsStr { OsString { inner: Buf::from_box(boxed) } } - /// Gets the underlying byte representation. + /// Converts an OS string slice to a byte slice. To convert the byte slice back into an OS + /// string slice, use the [`OsStr::from_os_str_bytes_unchecked`] function. + /// + /// The byte encoding is an unspecified, platform-specific, self-synchronizing superset of UTF-8. + /// By being a self-synchronizing superset of UTF-8, this encoding is also a superset of 7-bit + /// ASCII. + /// + /// Note: As the encoding is unspecified, any sub-slice of bytes that is not valid UTF-8 should + /// be treated as opaque and only comparable within the same rust version built for the same + /// target platform. For example, sending the slice over the network or storing it in a file + /// will likely result in incompatible byte slices. See [`OsString`] for more encoding details + /// and [`std::ffi`] for platform-specific, specified conversions. /// - /// Note: it is *crucial* that this API is not externally public, to avoid - /// revealing the internal, platform-specific encodings. + /// [`std::ffi`]: crate::ffi #[inline] - pub(crate) fn bytes(&self) -> &[u8] { - unsafe { &*(&self.inner as *const _ as *const [u8]) } + #[unstable(feature = "os_str_bytes", issue = "111544")] + pub fn as_os_str_bytes(&self) -> &[u8] { + self.inner.as_os_str_bytes() } /// Converts this string to its ASCII lower case equivalent in-place. @@ -1131,7 +1187,7 @@ impl Default for &OsStr { impl PartialEq for OsStr { #[inline] fn eq(&self, other: &OsStr) -> bool { - self.bytes().eq(other.bytes()) + self.as_os_str_bytes().eq(other.as_os_str_bytes()) } } @@ -1158,23 +1214,23 @@ impl Eq for OsStr {} impl PartialOrd for OsStr { #[inline] fn partial_cmp(&self, other: &OsStr) -> Option<cmp::Ordering> { - self.bytes().partial_cmp(other.bytes()) + self.as_os_str_bytes().partial_cmp(other.as_os_str_bytes()) } #[inline] fn lt(&self, other: &OsStr) -> bool { - self.bytes().lt(other.bytes()) + self.as_os_str_bytes().lt(other.as_os_str_bytes()) } #[inline] fn le(&self, other: &OsStr) -> bool { - self.bytes().le(other.bytes()) + self.as_os_str_bytes().le(other.as_os_str_bytes()) } #[inline] fn gt(&self, other: &OsStr) -> bool { - self.bytes().gt(other.bytes()) + self.as_os_str_bytes().gt(other.as_os_str_bytes()) } #[inline] fn ge(&self, other: &OsStr) -> bool { - self.bytes().ge(other.bytes()) + self.as_os_str_bytes().ge(other.as_os_str_bytes()) } } @@ -1193,7 +1249,7 @@ impl PartialOrd<str> for OsStr { impl Ord for OsStr { #[inline] fn cmp(&self, other: &OsStr) -> cmp::Ordering { - self.bytes().cmp(other.bytes()) + self.as_os_str_bytes().cmp(other.as_os_str_bytes()) } } @@ -1243,7 +1299,7 @@ impl_cmp!(Cow<'a, OsStr>, OsString); impl Hash for OsStr { #[inline] fn hash<H: Hasher>(&self, state: &mut H) { - self.bytes().hash(state) + self.as_os_str_bytes().hash(state) } } diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 9e09ce337bc..8a007d095d5 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -593,7 +593,8 @@ pub trait Read { /// This may happen for example because fewer bytes are actually available right now /// (e. g. being close to end-of-file) or because read() was interrupted by a signal. /// - /// As this trait is safe to implement, callers cannot rely on `n <= buf.len()` for safety. + /// As this trait is safe to implement, callers in unsafe code cannot rely on + /// `n <= buf.len()` for safety. /// Extra care needs to be taken when `unsafe` functions are used to access the read bytes. /// Callers have to ensure that no unchecked out-of-bounds accesses are possible even if /// `n > buf.len()`. @@ -603,8 +604,8 @@ pub trait Read { /// contents of `buf` being true. It is recommended that *implementations* /// only write data to `buf` instead of reading its contents. /// - /// Correspondingly, however, *callers* of this method must not assume any guarantees - /// about how the implementation uses `buf`. The trait is safe to implement, + /// Correspondingly, however, *callers* of this method in unsafe code must not assume + /// any guarantees about how the implementation uses `buf`. The trait is safe to implement, /// so it is possible that the code that's supposed to write to the buffer might also read /// from it. It is your responsibility to make sure that `buf` is initialized /// before calling `read`. Calling `read` with an uninitialized `buf` (of the kind one diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs index 6d59266b6f8..a6a370409c0 100644 --- a/library/std/src/panicking.rs +++ b/library/std/src/panicking.rs @@ -298,8 +298,18 @@ pub mod panic_count { pub const ALWAYS_ABORT_FLAG: usize = 1 << (usize::BITS - 1); - // Panic count for the current thread. - thread_local! { static LOCAL_PANIC_COUNT: Cell<usize> = const { Cell::new(0) } } + /// A reason for forcing an immediate abort on panic. + #[derive(Debug)] + pub enum MustAbort { + AlwaysAbort, + PanicInHook, + } + + // Panic count for the current thread and whether a panic hook is currently + // being executed.. + thread_local! { + static LOCAL_PANIC_COUNT: Cell<(usize, bool)> = const { Cell::new((0, false)) } + } // Sum of panic counts from all threads. The purpose of this is to have // a fast path in `count_is_zero` (which is used by `panicking`). In any particular @@ -328,34 +338,39 @@ pub mod panic_count { // panicking thread consumes at least 2 bytes of address space. static GLOBAL_PANIC_COUNT: AtomicUsize = AtomicUsize::new(0); - // Return the state of the ALWAYS_ABORT_FLAG and number of panics. + // Increases the global and local panic count, and returns whether an + // immediate abort is required. // - // If ALWAYS_ABORT_FLAG is not set, the number is determined on a per-thread - // base (stored in LOCAL_PANIC_COUNT), i.e. it is the amount of recursive calls - // of the calling thread. - // If ALWAYS_ABORT_FLAG is set, the number equals the *global* number of panic - // calls. See above why LOCAL_PANIC_COUNT is not used. - pub fn increase() -> (bool, usize) { + // This also updates thread-local state to keep track of whether a panic + // hook is currently executing. + pub fn increase(run_panic_hook: bool) -> Option<MustAbort> { let global_count = GLOBAL_PANIC_COUNT.fetch_add(1, Ordering::Relaxed); - let must_abort = global_count & ALWAYS_ABORT_FLAG != 0; - let panics = if must_abort { - global_count & !ALWAYS_ABORT_FLAG - } else { - LOCAL_PANIC_COUNT.with(|c| { - let next = c.get() + 1; - c.set(next); - next - }) - }; - (must_abort, panics) + if global_count & ALWAYS_ABORT_FLAG != 0 { + return Some(MustAbort::AlwaysAbort); + } + + LOCAL_PANIC_COUNT.with(|c| { + let (count, in_panic_hook) = c.get(); + if in_panic_hook { + return Some(MustAbort::PanicInHook); + } + c.set((count + 1, run_panic_hook)); + None + }) + } + + pub fn finished_panic_hook() { + LOCAL_PANIC_COUNT.with(|c| { + let (count, _) = c.get(); + c.set((count, false)); + }); } pub fn decrease() { GLOBAL_PANIC_COUNT.fetch_sub(1, Ordering::Relaxed); LOCAL_PANIC_COUNT.with(|c| { - let next = c.get() - 1; - c.set(next); - next + let (count, _) = c.get(); + c.set((count - 1, false)); }); } @@ -366,7 +381,7 @@ pub mod panic_count { // Disregards ALWAYS_ABORT_FLAG #[must_use] pub fn get_count() -> usize { - LOCAL_PANIC_COUNT.with(|c| c.get()) + LOCAL_PANIC_COUNT.with(|c| c.get().0) } // Disregards ALWAYS_ABORT_FLAG @@ -394,7 +409,7 @@ pub mod panic_count { #[inline(never)] #[cold] fn is_zero_slow_path() -> bool { - LOCAL_PANIC_COUNT.with(|c| c.get() == 0) + LOCAL_PANIC_COUNT.with(|c| c.get().0 == 0) } } @@ -655,23 +670,22 @@ fn rust_panic_with_hook( location: &Location<'_>, can_unwind: bool, ) -> ! { - let (must_abort, panics) = panic_count::increase(); - - // If this is the third nested call (e.g., panics == 2, this is 0-indexed), - // the panic hook probably triggered the last panic, otherwise the - // double-panic check would have aborted the process. In this case abort the - // process real quickly as we don't want to try calling it again as it'll - // probably just panic again. - if must_abort || panics > 2 { - if panics > 2 { - // Don't try to print the message in this case - // - perhaps that is causing the recursive panics. - rtprintpanic!("thread panicked while processing panic. aborting.\n"); - } else { - // Unfortunately, this does not print a backtrace, because creating - // a `Backtrace` will allocate, which we must to avoid here. - let panicinfo = PanicInfo::internal_constructor(message, location, can_unwind); - rtprintpanic!("{panicinfo}\npanicked after panic::always_abort(), aborting.\n"); + let must_abort = panic_count::increase(true); + + // Check if we need to abort immediately. + if let Some(must_abort) = must_abort { + match must_abort { + panic_count::MustAbort::PanicInHook => { + // Don't try to print the message in this case + // - perhaps that is causing the recursive panics. + rtprintpanic!("thread panicked while processing panic. aborting.\n"); + } + panic_count::MustAbort::AlwaysAbort => { + // Unfortunately, this does not print a backtrace, because creating + // a `Backtrace` will allocate, which we must to avoid here. + let panicinfo = PanicInfo::internal_constructor(message, location, can_unwind); + rtprintpanic!("{panicinfo}\npanicked after panic::always_abort(), aborting.\n"); + } } crate::sys::abort_internal(); } @@ -697,16 +711,16 @@ fn rust_panic_with_hook( }; drop(hook); - if panics > 1 || !can_unwind { - // If a thread panics while it's already unwinding then we - // have limited options. Currently our preference is to - // just abort. In the future we may consider resuming - // unwinding or otherwise exiting the thread cleanly. - if !can_unwind { - rtprintpanic!("thread caused non-unwinding panic. aborting.\n"); - } else { - rtprintpanic!("thread panicked while panicking. aborting.\n"); - } + // Indicate that we have finished executing the panic hook. After this point + // it is fine if there is a panic while executing destructors, as long as it + // it contained within a `catch_unwind`. + panic_count::finished_panic_hook(); + + if !can_unwind { + // If a thread panics while running destructors or tries to unwind + // through a nounwind function (e.g. extern "C") then we cannot continue + // unwinding and have to abort immediately. + rtprintpanic!("thread caused non-unwinding panic. aborting.\n"); crate::sys::abort_internal(); } @@ -716,7 +730,7 @@ fn rust_panic_with_hook( /// This is the entry point for `resume_unwind`. /// It just forwards the payload to the panic runtime. pub fn rust_panic_without_hook(payload: Box<dyn Any + Send>) -> ! { - panic_count::increase(); + panic_count::increase(false); struct RewrapBox(Box<dyn Any + Send>); diff --git a/library/std/src/path.rs b/library/std/src/path.rs index febdeb51463..28cd3c4e4db 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -193,7 +193,7 @@ impl<'a> Prefix<'a> { fn len(&self) -> usize { use self::Prefix::*; fn os_str_len(s: &OsStr) -> usize { - s.bytes().len() + s.as_os_str_bytes().len() } match *self { Verbatim(x) => 4 + os_str_len(x), @@ -299,20 +299,6 @@ where } } -unsafe fn u8_slice_as_os_str(s: &[u8]) -> &OsStr { - // SAFETY: See note at the top of this module to understand why this and - // `OsStr::bytes` are used: - // - // This casts are safe as OsStr is internally a wrapper around [u8] on all - // platforms. - // - // Note that currently this relies on the special knowledge that std has; - // these types are single-element structs but are not marked - // repr(transparent) or repr(C) which would make these casts not allowable - // outside std. - unsafe { &*(s as *const [u8] as *const OsStr) } -} - // Detect scheme on Redox fn has_redox_scheme(s: &[u8]) -> bool { cfg!(target_os = "redox") && s.contains(&b':') @@ -330,7 +316,7 @@ fn has_physical_root(s: &[u8], prefix: Option<Prefix<'_>>) -> bool { // basic workhorse for splitting stem and extension fn rsplit_file_at_dot(file: &OsStr) -> (Option<&OsStr>, Option<&OsStr>) { - if file.bytes() == b".." { + if file.as_os_str_bytes() == b".." { return (Some(file), None); } @@ -338,18 +324,23 @@ fn rsplit_file_at_dot(file: &OsStr) -> (Option<&OsStr>, Option<&OsStr>) { // and back. This is safe to do because (1) we only look at ASCII // contents of the encoding and (2) new &OsStr values are produced // only from ASCII-bounded slices of existing &OsStr values. - let mut iter = file.bytes().rsplitn(2, |b| *b == b'.'); + let mut iter = file.as_os_str_bytes().rsplitn(2, |b| *b == b'.'); let after = iter.next(); let before = iter.next(); if before == Some(b"") { (Some(file), None) } else { - unsafe { (before.map(|s| u8_slice_as_os_str(s)), after.map(|s| u8_slice_as_os_str(s))) } + unsafe { + ( + before.map(|s| OsStr::from_os_str_bytes_unchecked(s)), + after.map(|s| OsStr::from_os_str_bytes_unchecked(s)), + ) + } } } fn split_file_at_dot(file: &OsStr) -> (&OsStr, Option<&OsStr>) { - let slice = file.bytes(); + let slice = file.as_os_str_bytes(); if slice == b".." { return (file, None); } @@ -364,7 +355,12 @@ fn split_file_at_dot(file: &OsStr) -> (&OsStr, Option<&OsStr>) { }; let before = &slice[..i]; let after = &slice[i + 1..]; - unsafe { (u8_slice_as_os_str(before), Some(u8_slice_as_os_str(after))) } + unsafe { + ( + OsStr::from_os_str_bytes_unchecked(before), + Some(OsStr::from_os_str_bytes_unchecked(after)), + ) + } } //////////////////////////////////////////////////////////////////////////////// @@ -743,7 +739,7 @@ impl<'a> Components<'a> { // separately via `include_cur_dir` b".." => Some(Component::ParentDir), b"" => None, - _ => Some(Component::Normal(unsafe { u8_slice_as_os_str(comp) })), + _ => Some(Component::Normal(unsafe { OsStr::from_os_str_bytes_unchecked(comp) })), } } @@ -900,7 +896,7 @@ impl<'a> Iterator for Components<'a> { let raw = &self.path[..self.prefix_len()]; self.path = &self.path[self.prefix_len()..]; return Some(Component::Prefix(PrefixComponent { - raw: unsafe { u8_slice_as_os_str(raw) }, + raw: unsafe { OsStr::from_os_str_bytes_unchecked(raw) }, parsed: self.prefix.unwrap(), })); } @@ -972,7 +968,7 @@ impl<'a> DoubleEndedIterator for Components<'a> { State::Prefix if self.prefix_len() > 0 => { self.back = State::Done; return Some(Component::Prefix(PrefixComponent { - raw: unsafe { u8_slice_as_os_str(self.path) }, + raw: unsafe { OsStr::from_os_str_bytes_unchecked(self.path) }, parsed: self.prefix.unwrap(), })); } @@ -1481,17 +1477,17 @@ impl PathBuf { fn _set_extension(&mut self, extension: &OsStr) -> bool { let file_stem = match self.file_stem() { None => return false, - Some(f) => f.bytes(), + Some(f) => f.as_os_str_bytes(), }; // truncate until right after the file stem let end_file_stem = file_stem[file_stem.len()..].as_ptr().addr(); - let start = self.inner.bytes().as_ptr().addr(); + let start = self.inner.as_os_str_bytes().as_ptr().addr(); let v = self.as_mut_vec(); v.truncate(end_file_stem.wrapping_sub(start)); // add the new extension, if any - let new = extension.bytes(); + let new = extension.as_os_str_bytes(); if !new.is_empty() { v.reserve_exact(new.len() + 1); v.push(b'.'); @@ -2011,11 +2007,11 @@ impl Path { // The following (private!) function allows construction of a path from a u8 // slice, which is only safe when it is known to follow the OsStr encoding. unsafe fn from_u8_slice(s: &[u8]) -> &Path { - unsafe { Path::new(u8_slice_as_os_str(s)) } + unsafe { Path::new(OsStr::from_os_str_bytes_unchecked(s)) } } // The following (private!) function reveals the byte encoding used for OsStr. fn as_u8_slice(&self) -> &[u8] { - self.inner.bytes() + self.inner.as_os_str_bytes() } /// Directly wraps a string slice as a `Path` slice. diff --git a/library/std/src/sys/common/small_c_string.rs b/library/std/src/sys/common/small_c_string.rs index 01acd519135..963d17a47e4 100644 --- a/library/std/src/sys/common/small_c_string.rs +++ b/library/std/src/sys/common/small_c_string.rs @@ -19,7 +19,7 @@ pub fn run_path_with_cstr<T, F>(path: &Path, f: F) -> io::Result<T> where F: FnOnce(&CStr) -> io::Result<T>, { - run_with_cstr(path.as_os_str().bytes(), f) + run_with_cstr(path.as_os_str().as_os_str_bytes(), f) } #[inline] diff --git a/library/std/src/sys/common/tests.rs b/library/std/src/sys/common/tests.rs index fb6f5d6af83..0a1cbcbe8ef 100644 --- a/library/std/src/sys/common/tests.rs +++ b/library/std/src/sys/common/tests.rs @@ -8,7 +8,7 @@ use core::iter::repeat; fn stack_allocation_works() { let path = Path::new("abc"); let result = run_path_with_cstr(path, |p| { - assert_eq!(p, &*CString::new(path.as_os_str().bytes()).unwrap()); + assert_eq!(p, &*CString::new(path.as_os_str().as_os_str_bytes()).unwrap()); Ok(42) }); assert_eq!(result.unwrap(), 42); @@ -25,7 +25,7 @@ fn heap_allocation_works() { let path = repeat("a").take(384).collect::<String>(); let path = Path::new(&path); let result = run_path_with_cstr(path, |p| { - assert_eq!(p, &*CString::new(path.as_os_str().bytes()).unwrap()); + assert_eq!(p, &*CString::new(path.as_os_str().as_os_str_bytes()).unwrap()); Ok(42) }); assert_eq!(result.unwrap(), 42); diff --git a/library/std/src/sys/unix/os_str.rs b/library/std/src/sys/unix/os_str.rs index 488217f3941..142fcb9ed0b 100644 --- a/library/std/src/sys/unix/os_str.rs +++ b/library/std/src/sys/unix/os_str.rs @@ -193,13 +193,18 @@ impl Buf { impl Slice { #[inline] - fn from_u8_slice(s: &[u8]) -> &Slice { + pub fn as_os_str_bytes(&self) -> &[u8] { + &self.inner + } + + #[inline] + pub unsafe fn from_os_str_bytes_unchecked(s: &[u8]) -> &Slice { unsafe { mem::transmute(s) } } #[inline] pub fn from_str(s: &str) -> &Slice { - Slice::from_u8_slice(s.as_bytes()) + unsafe { Slice::from_os_str_bytes_unchecked(s.as_bytes()) } } pub fn to_str(&self) -> Option<&str> { diff --git a/library/std/src/sys/unix/os_str/tests.rs b/library/std/src/sys/unix/os_str/tests.rs index 22ba0c92350..91bc0e61a4a 100644 --- a/library/std/src/sys/unix/os_str/tests.rs +++ b/library/std/src/sys/unix/os_str/tests.rs @@ -2,7 +2,7 @@ use super::*; #[test] fn slice_debug_output() { - let input = Slice::from_u8_slice(b"\xF0hello,\tworld"); + let input = unsafe { Slice::from_os_str_bytes_unchecked(b"\xF0hello,\tworld") }; let expected = r#""\xF0hello,\tworld""#; let output = format!("{input:?}"); @@ -11,8 +11,7 @@ fn slice_debug_output() { #[test] fn display() { - assert_eq!( - "Hello\u{FFFD}\u{FFFD} There\u{FFFD} Goodbye", - Slice::from_u8_slice(b"Hello\xC0\x80 There\xE6\x83 Goodbye").to_string(), - ); + assert_eq!("Hello\u{FFFD}\u{FFFD} There\u{FFFD} Goodbye", unsafe { + Slice::from_os_str_bytes_unchecked(b"Hello\xC0\x80 There\xE6\x83 Goodbye").to_string() + },); } diff --git a/library/std/src/sys/unix/path.rs b/library/std/src/sys/unix/path.rs index a98a69e2db8..935245f637b 100644 --- a/library/std/src/sys/unix/path.rs +++ b/library/std/src/sys/unix/path.rs @@ -30,7 +30,7 @@ pub(crate) fn absolute(path: &Path) -> io::Result<PathBuf> { // Get the components, skipping the redundant leading "." component if it exists. let mut components = path.strip_prefix(".").unwrap_or(path).components(); - let path_os = path.as_os_str().bytes(); + let path_os = path.as_os_str().as_os_str_bytes(); let mut normalized = if path.is_absolute() { // "If a pathname begins with two successive <slash> characters, the diff --git a/library/std/src/sys/unix/process/process_common.rs b/library/std/src/sys/unix/process/process_common.rs index afd03d79c0b..640648e8707 100644 --- a/library/std/src/sys/unix/process/process_common.rs +++ b/library/std/src/sys/unix/process/process_common.rs @@ -164,9 +164,9 @@ pub enum ProgramKind { impl ProgramKind { fn new(program: &OsStr) -> Self { - if program.bytes().starts_with(b"/") { + if program.as_os_str_bytes().starts_with(b"/") { Self::Absolute - } else if program.bytes().contains(&b'/') { + } else if program.as_os_str_bytes().contains(&b'/') { // If the program has more than one component in it, it is a relative path. Self::Relative } else { diff --git a/library/std/src/sys/windows/args.rs b/library/std/src/sys/windows/args.rs index 5bfd8b52ed0..6b597f499bc 100644 --- a/library/std/src/sys/windows/args.rs +++ b/library/std/src/sys/windows/args.rs @@ -226,7 +226,7 @@ pub(crate) fn append_arg(cmd: &mut Vec<u16>, arg: &Arg, force_quotes: bool) -> i // that it actually gets passed through on the command line or otherwise // it will be dropped entirely when parsed on the other end. ensure_no_nuls(arg)?; - let arg_bytes = arg.bytes(); + let arg_bytes = arg.as_os_str_bytes(); let (quote, escape) = match quote { Quote::Always => (true, true), Quote::Auto => { @@ -297,7 +297,9 @@ pub(crate) fn make_bat_command_line( // * `|<>` pipe/redirect characters. const SPECIAL: &[u8] = b"\t &()[]{}^=;!'+,`~%|<>"; let force_quotes = match arg { - Arg::Regular(arg) if !force_quotes => arg.bytes().iter().any(|c| SPECIAL.contains(c)), + Arg::Regular(arg) if !force_quotes => { + arg.as_os_str_bytes().iter().any(|c| SPECIAL.contains(c)) + } _ => force_quotes, }; append_arg(&mut cmd, arg, force_quotes)?; diff --git a/library/std/src/sys/windows/os_str.rs b/library/std/src/sys/windows/os_str.rs index 2f2b0e56e08..611f0d040f0 100644 --- a/library/std/src/sys/windows/os_str.rs +++ b/library/std/src/sys/windows/os_str.rs @@ -152,6 +152,16 @@ impl Buf { impl Slice { #[inline] + pub fn as_os_str_bytes(&self) -> &[u8] { + self.inner.as_bytes() + } + + #[inline] + pub unsafe fn from_os_str_bytes_unchecked(s: &[u8]) -> &Slice { + mem::transmute(Wtf8::from_bytes_unchecked(s)) + } + + #[inline] pub fn from_str(s: &str) -> &Slice { unsafe { mem::transmute(Wtf8::from_str(s)) } } diff --git a/library/std/src/sys/windows/path.rs b/library/std/src/sys/windows/path.rs index c3573d14c7f..c9c2d10e6c4 100644 --- a/library/std/src/sys/windows/path.rs +++ b/library/std/src/sys/windows/path.rs @@ -1,7 +1,6 @@ use super::{c, fill_utf16_buf, to_u16s}; use crate::ffi::{OsStr, OsString}; use crate::io; -use crate::mem; use crate::path::{Path, PathBuf, Prefix}; use crate::ptr; @@ -11,16 +10,6 @@ mod tests; pub const MAIN_SEP_STR: &str = "\\"; pub const MAIN_SEP: char = '\\'; -/// # Safety -/// -/// `bytes` must be a valid wtf8 encoded slice -#[inline] -unsafe fn bytes_as_os_str(bytes: &[u8]) -> &OsStr { - // &OsStr is layout compatible with &Slice, which is compatible with &Wtf8, - // which is compatible with &[u8]. - mem::transmute(bytes) -} - #[inline] pub fn is_sep_byte(b: u8) -> bool { b == b'/' || b == b'\\' @@ -33,12 +22,12 @@ pub fn is_verbatim_sep(b: u8) -> bool { /// Returns true if `path` looks like a lone filename. pub(crate) fn is_file_name(path: &OsStr) -> bool { - !path.bytes().iter().copied().any(is_sep_byte) + !path.as_os_str_bytes().iter().copied().any(is_sep_byte) } pub(crate) fn has_trailing_slash(path: &OsStr) -> bool { - let is_verbatim = path.bytes().starts_with(br"\\?\"); + let is_verbatim = path.as_os_str_bytes().starts_with(br"\\?\"); let is_separator = if is_verbatim { is_verbatim_sep } else { is_sep_byte }; - if let Some(&c) = path.bytes().last() { is_separator(c) } else { false } + if let Some(&c) = path.as_os_str_bytes().last() { is_separator(c) } else { false } } /// Appends a suffix to a path. @@ -60,7 +49,7 @@ impl<'a, const LEN: usize> PrefixParser<'a, LEN> { fn get_prefix(path: &OsStr) -> [u8; LEN] { let mut prefix = [0; LEN]; // SAFETY: Only ASCII characters are modified. - for (i, &ch) in path.bytes().iter().take(LEN).enumerate() { + for (i, &ch) in path.as_os_str_bytes().iter().take(LEN).enumerate() { prefix[i] = if ch == b'/' { b'\\' } else { ch }; } prefix @@ -93,7 +82,7 @@ impl<'a> PrefixParserSlice<'a, '_> { } fn prefix_bytes(&self) -> &'a [u8] { - &self.path.bytes()[..self.index] + &self.path.as_os_str_bytes()[..self.index] } fn finish(self) -> &'a OsStr { @@ -101,7 +90,7 @@ impl<'a> PrefixParserSlice<'a, '_> { // &[u8] and back. This is safe to do because (1) we only look at ASCII // contents of the encoding and (2) new &OsStr values are produced only // from ASCII-bounded slices of existing &OsStr values. - unsafe { bytes_as_os_str(&self.path.bytes()[self.index..]) } + unsafe { OsStr::from_os_str_bytes_unchecked(&self.path.as_os_str_bytes()[self.index..]) } } } @@ -173,7 +162,7 @@ fn parse_drive(path: &OsStr) -> Option<u8> { drive.is_ascii_alphabetic() } - match path.bytes() { + match path.as_os_str_bytes() { [drive, b':', ..] if is_valid_drive_letter(drive) => Some(drive.to_ascii_uppercase()), _ => None, } @@ -182,7 +171,7 @@ fn parse_drive(path: &OsStr) -> Option<u8> { // Parses a drive prefix exactly, e.g. "C:" fn parse_drive_exact(path: &OsStr) -> Option<u8> { // only parse two bytes: the drive letter and the drive separator - if path.bytes().get(2).map(|&x| is_sep_byte(x)).unwrap_or(true) { + if path.as_os_str_bytes().get(2).map(|&x| is_sep_byte(x)).unwrap_or(true) { parse_drive(path) } else { None @@ -196,21 +185,26 @@ fn parse_drive_exact(path: &OsStr) -> Option<u8> { fn parse_next_component(path: &OsStr, verbatim: bool) -> (&OsStr, &OsStr) { let separator = if verbatim { is_verbatim_sep } else { is_sep_byte }; - match path.bytes().iter().position(|&x| separator(x)) { + match path.as_os_str_bytes().iter().position(|&x| separator(x)) { Some(separator_start) => { let separator_end = separator_start + 1; - let component = &path.bytes()[..separator_start]; + let component = &path.as_os_str_bytes()[..separator_start]; // Panic safe // The max `separator_end` is `bytes.len()` and `bytes[bytes.len()..]` is a valid index. - let path = &path.bytes()[separator_end..]; + let path = &path.as_os_str_bytes()[separator_end..]; // SAFETY: `path` is a valid wtf8 encoded slice and each of the separators ('/', '\') // is encoded in a single byte, therefore `bytes[separator_start]` and // `bytes[separator_end]` must be code point boundaries and thus // `bytes[..separator_start]` and `bytes[separator_end..]` are valid wtf8 slices. - unsafe { (bytes_as_os_str(component), bytes_as_os_str(path)) } + unsafe { + ( + OsStr::from_os_str_bytes_unchecked(component), + OsStr::from_os_str_bytes_unchecked(path), + ) + } } None => (path, OsStr::new("")), } @@ -329,7 +323,7 @@ pub(crate) fn absolute(path: &Path) -> io::Result<PathBuf> { // Verbatim paths should not be modified. if prefix.map(|x| x.is_verbatim()).unwrap_or(false) { // NULs in verbatim paths are rejected for consistency. - if path.bytes().contains(&0) { + if path.as_os_str_bytes().contains(&0) { return Err(io::const_io_error!( io::ErrorKind::InvalidInput, "strings passed to WinAPI cannot contain NULs", diff --git a/library/std/src/sys/windows/process.rs b/library/std/src/sys/windows/process.rs index df3667c0fd7..a573a05c39c 100644 --- a/library/std/src/sys/windows/process.rs +++ b/library/std/src/sys/windows/process.rs @@ -395,7 +395,7 @@ fn resolve_exe<'a>( // Test if the file name has the `exe` extension. // This does a case-insensitive `ends_with`. let has_exe_suffix = if exe_path.len() >= EXE_SUFFIX.len() { - exe_path.bytes()[exe_path.len() - EXE_SUFFIX.len()..] + exe_path.as_os_str_bytes()[exe_path.len() - EXE_SUFFIX.len()..] .eq_ignore_ascii_case(EXE_SUFFIX.as_bytes()) } else { false @@ -425,7 +425,7 @@ fn resolve_exe<'a>( // From the `CreateProcessW` docs: // > If the file name does not contain an extension, .exe is appended. // Note that this rule only applies when searching paths. - let has_extension = exe_path.bytes().contains(&b'.'); + let has_extension = exe_path.as_os_str_bytes().contains(&b'.'); // Search the directories given by `search_paths`. let result = search_paths(parent_paths, child_paths, |mut path| { diff --git a/library/std/src/sys_common/wtf8.rs b/library/std/src/sys_common/wtf8.rs index ff96c35fb0b..31bb0ad25a6 100644 --- a/library/std/src/sys_common/wtf8.rs +++ b/library/std/src/sys_common/wtf8.rs @@ -570,7 +570,7 @@ impl Wtf8 { /// Since the byte slice is not checked for valid WTF-8, this functions is /// marked unsafe. #[inline] - unsafe fn from_bytes_unchecked(value: &[u8]) -> &Wtf8 { + pub unsafe fn from_bytes_unchecked(value: &[u8]) -> &Wtf8 { mem::transmute(value) } @@ -614,6 +614,12 @@ impl Wtf8 { Wtf8CodePoints { bytes: self.bytes.iter() } } + /// Access raw bytes of WTF-8 data + #[inline] + pub fn as_bytes(&self) -> &[u8] { + &self.bytes + } + /// Tries to convert the string to UTF-8 and return a `&str` slice. /// /// Returns `None` if the string contains surrogates. diff --git a/library/test/src/options.rs b/library/test/src/options.rs index 75ec0b616e1..3eaad59474a 100644 --- a/library/test/src/options.rs +++ b/library/test/src/options.rs @@ -16,19 +16,21 @@ pub enum ShouldPanic { } /// Whether should console output be colored or not -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Default, Debug)] pub enum ColorConfig { + #[default] AutoColor, AlwaysColor, NeverColor, } /// Format of the test results output -#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)] pub enum OutputFormat { /// Verbose output Pretty, /// Quiet output + #[default] Terse, /// JSON output Json, diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock index 8f8778efee7..311ac175160 100644 --- a/src/bootstrap/Cargo.lock +++ b/src/bootstrap/Cargo.lock @@ -58,7 +58,6 @@ dependencies = [ "once_cell", "opener", "pretty_assertions", - "semver", "serde", "serde_derive", "serde_json", @@ -647,12 +646,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] -name = "semver" -version = "1.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" - -[[package]] name = "serde" version = "1.0.160" source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index 367c6190967..70ade776d7d 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -57,7 +57,6 @@ walkdir = "2" sysinfo = { version = "0.26.0", optional = true } clap = { version = "4.2.4", default-features = false, features = ["std", "usage", "help", "derive", "error-context"] } clap_complete = "4.2.2" -semver = "1.0.17" # Solaris doesn't support flock() and thus fd-lock is not option now [target.'cfg(not(target_os = "solaris"))'.dependencies] diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index d75ffd4ac22..75df5345169 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -226,16 +226,13 @@ def format_build_time(duration): def default_build_triple(verbose): """Build triple as in LLVM""" - # If the user already has a host build triple with an existing `rustc` - # install, use their preference. This fixes most issues with Windows builds - # being detected as GNU instead of MSVC. + # If we're on Windows and have an existing `rustc` toolchain, use `rustc --version --verbose` + # to find our host target triple. This fixes an issue with Windows builds being detected + # as GNU instead of MSVC. + # Otherwise, detect it via `uname` default_encoding = sys.getdefaultencoding() - if sys.platform == 'darwin': - if verbose: - print("not using rustc detection as it is unreliable on macOS", file=sys.stderr) - print("falling back to auto-detect", file=sys.stderr) - else: + if platform_is_win32(): try: version = subprocess.check_output(["rustc", "--version", "--verbose"], stderr=subprocess.DEVNULL) @@ -253,19 +250,17 @@ def default_build_triple(verbose): print("falling back to auto-detect", file=sys.stderr) required = not platform_is_win32() - ostype = require(["uname", "-s"], exit=required) - cputype = require(['uname', '-m'], exit=required) + uname = require(["uname", "-smp"], exit=required) # If we do not have `uname`, assume Windows. - if ostype is None or cputype is None: + if uname is None: return 'x86_64-pc-windows-msvc' - ostype = ostype.decode(default_encoding) - cputype = cputype.decode(default_encoding) + kernel, cputype, processor = uname.decode(default_encoding).split() # The goal here is to come up with the same triple as LLVM would, # at least for the subset of platforms we're willing to target. - ostype_mapper = { + kerneltype_mapper = { 'Darwin': 'apple-darwin', 'DragonFly': 'unknown-dragonfly', 'FreeBSD': 'unknown-freebsd', @@ -275,17 +270,18 @@ def default_build_triple(verbose): } # Consider the direct transformation first and then the special cases - if ostype in ostype_mapper: - ostype = ostype_mapper[ostype] - elif ostype == 'Linux': - os_from_sp = subprocess.check_output( - ['uname', '-o']).strip().decode(default_encoding) - if os_from_sp == 'Android': - ostype = 'linux-android' + if kernel in kerneltype_mapper: + kernel = kerneltype_mapper[kernel] + elif kernel == 'Linux': + # Apple doesn't support `-o` so this can't be used in the combined + # uname invocation above + ostype = require(["uname", "-o"], exit=required).decode(default_encoding) + if ostype == 'Android': + kernel = 'linux-android' else: - ostype = 'unknown-linux-gnu' - elif ostype == 'SunOS': - ostype = 'pc-solaris' + kernel = 'unknown-linux-gnu' + elif kernel == 'SunOS': + kernel = 'pc-solaris' # On Solaris, uname -m will return a machine classification instead # of a cpu type, so uname -p is recommended instead. However, the # output from that option is too generic for our purposes (it will @@ -294,34 +290,34 @@ def default_build_triple(verbose): cputype = require(['isainfo', '-k']).decode(default_encoding) # sparc cpus have sun as a target vendor if 'sparc' in cputype: - ostype = 'sun-solaris' - elif ostype.startswith('MINGW'): + kernel = 'sun-solaris' + elif kernel.startswith('MINGW'): # msys' `uname` does not print gcc configuration, but prints msys # configuration. so we cannot believe `uname -m`: # msys1 is always i686 and msys2 is always x86_64. # instead, msys defines $MSYSTEM which is MINGW32 on i686 and # MINGW64 on x86_64. - ostype = 'pc-windows-gnu' + kernel = 'pc-windows-gnu' cputype = 'i686' if os.environ.get('MSYSTEM') == 'MINGW64': cputype = 'x86_64' - elif ostype.startswith('MSYS'): - ostype = 'pc-windows-gnu' - elif ostype.startswith('CYGWIN_NT'): + elif kernel.startswith('MSYS'): + kernel = 'pc-windows-gnu' + elif kernel.startswith('CYGWIN_NT'): cputype = 'i686' - if ostype.endswith('WOW64'): + if kernel.endswith('WOW64'): cputype = 'x86_64' - ostype = 'pc-windows-gnu' - elif sys.platform == 'win32': + kernel = 'pc-windows-gnu' + elif platform_is_win32(): # Some Windows platforms might have a `uname` command that returns a # non-standard string (e.g. gnuwin32 tools returns `windows32`). In # these cases, fall back to using sys.platform. return 'x86_64-pc-windows-msvc' else: - err = "unknown OS type: {}".format(ostype) + err = "unknown OS type: {}".format(kernel) sys.exit(err) - if cputype in ['powerpc', 'riscv'] and ostype == 'unknown-freebsd': + if cputype in ['powerpc', 'riscv'] and kernel == 'unknown-freebsd': cputype = subprocess.check_output( ['uname', '-p']).strip().decode(default_encoding) cputype_mapper = { @@ -354,24 +350,23 @@ def default_build_triple(verbose): cputype = cputype_mapper[cputype] elif cputype in {'xscale', 'arm'}: cputype = 'arm' - if ostype == 'linux-android': - ostype = 'linux-androideabi' - elif ostype == 'unknown-freebsd': - cputype = subprocess.check_output( - ['uname', '-p']).strip().decode(default_encoding) - ostype = 'unknown-freebsd' + if kernel == 'linux-android': + kernel = 'linux-androideabi' + elif kernel == 'unknown-freebsd': + cputype = processor + kernel = 'unknown-freebsd' elif cputype == 'armv6l': cputype = 'arm' - if ostype == 'linux-android': - ostype = 'linux-androideabi' + if kernel == 'linux-android': + kernel = 'linux-androideabi' else: - ostype += 'eabihf' + kernel += 'eabihf' elif cputype in {'armv7l', 'armv8l'}: cputype = 'armv7' - if ostype == 'linux-android': - ostype = 'linux-androideabi' + if kernel == 'linux-android': + kernel = 'linux-androideabi' else: - ostype += 'eabihf' + kernel += 'eabihf' elif cputype == 'mips': if sys.byteorder == 'big': cputype = 'mips' @@ -387,14 +382,14 @@ def default_build_triple(verbose): else: raise ValueError('unknown byteorder: {}'.format(sys.byteorder)) # only the n64 ABI is supported, indicate it - ostype += 'abi64' + kernel += 'abi64' elif cputype == 'sparc' or cputype == 'sparcv9' or cputype == 'sparc64': pass else: err = "unknown cpu type: {}".format(cputype) sys.exit(err) - return "{}-{}".format(cputype, ostype) + return "{}-{}".format(cputype, kernel) @contextlib.contextmanager @@ -882,6 +877,12 @@ class RustBuild(object): # preserve existing RUSTFLAGS env.setdefault("RUSTFLAGS", "") + # we need to explicitly add +xgot here so that we can successfully bootstrap + # a usable stage1 compiler + # FIXME: remove this if condition on the next bootstrap bump + # cfg(bootstrap) + if self.build_triple().startswith('mips'): + env["RUSTFLAGS"] += " -Ctarget-feature=+xgot" target_features = [] if self.get_toml("crt-static", build_section) == "true": target_features += ["+crt-static"] diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index cf7c6596c02..43c859b0063 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -103,11 +103,14 @@ impl RunConfig<'_> { } /// Return a list of crate names selected by `run.paths`. + #[track_caller] pub fn cargo_crates_in_set(&self) -> Interned<Vec<String>> { let mut crates = Vec::new(); for krate in &self.paths { let path = krate.assert_single_path(); - let crate_name = self.builder.crate_paths[&path.path]; + let Some(crate_name) = self.builder.crate_paths.get(&path.path) else { + panic!("missing crate for path {}", path.path.display()) + }; crates.push(crate_name.to_string()); } INTERNER.intern_list(crates) @@ -264,7 +267,7 @@ impl PathSet { /// A convenience wrapper for Steps which know they have no aliases and all their sets contain only a single path. /// - /// This can be used with [`ShouldRun::krate`], [`ShouldRun::path`], or [`ShouldRun::alias`]. + /// This can be used with [`ShouldRun::crate_or_deps`], [`ShouldRun::path`], or [`ShouldRun::alias`]. #[track_caller] pub fn assert_single_path(&self) -> &TaskPath { match self { @@ -378,7 +381,7 @@ impl StepDescription { eprintln!( "note: if you are adding a new Step to bootstrap itself, make sure you register it with `describe!`" ); - crate::detail_exit(1); + crate::detail_exit_macro!(1); } } } @@ -430,25 +433,6 @@ impl<'a> ShouldRun<'a> { /// Indicates it should run if the command-line selects the given crate or /// any of its (local) dependencies. /// - /// Compared to `krate`, this treats the dependencies as aliases for the - /// same job. Generally it is preferred to use `krate`, and treat each - /// individual path separately. For example `./x.py test src/liballoc` - /// (which uses `krate`) will test just `liballoc`. However, `./x.py check - /// src/liballoc` (which uses `all_krates`) will check all of `libtest`. - /// `all_krates` should probably be removed at some point. - pub fn all_krates(mut self, name: &str) -> Self { - let mut set = BTreeSet::new(); - for krate in self.builder.in_tree_crates(name, None) { - let path = krate.local_path(self.builder); - set.insert(TaskPath { path, kind: Some(self.kind) }); - } - self.paths.insert(PathSet::Set(set)); - self - } - - /// Indicates it should run if the command-line selects the given crate or - /// any of its (local) dependencies. - /// /// `make_run` will be called a single time with all matching command-line paths. pub fn crate_or_deps(self, name: &str) -> Self { let crates = self.builder.in_tree_crates(name, None); @@ -458,6 +442,8 @@ impl<'a> ShouldRun<'a> { /// Indicates it should run if the command-line selects any of the given crates. /// /// `make_run` will be called a single time with all matching command-line paths. + /// + /// Prefer [`ShouldRun::crate_or_deps`] to this function where possible. pub(crate) fn crates(mut self, crates: Vec<&Crate>) -> Self { for krate in crates { let path = krate.local_path(self.builder); @@ -487,7 +473,15 @@ impl<'a> ShouldRun<'a> { self.paths(&[path]) } - // multiple aliases for the same job + /// Multiple aliases for the same job. + /// + /// This differs from [`path`] in that multiple calls to path will end up calling `make_run` + /// multiple times, whereas a single call to `paths` will only ever generate a single call to + /// `paths`. + /// + /// This is analogous to `all_krates`, although `all_krates` is gone now. Prefer [`path`] where possible. + /// + /// [`path`]: ShouldRun::path pub fn paths(mut self, paths: &[&str]) -> Self { static SUBMODULES_PATHS: OnceCell<Vec<String>> = OnceCell::new(); @@ -641,12 +635,16 @@ impl Kind { } } - pub fn test_description(&self) -> &'static str { + pub fn description(&self) -> String { match self { Kind::Test => "Testing", Kind::Bench => "Benchmarking", - _ => panic!("not a test command: {}!", self.as_str()), + Kind::Doc => "Documenting", + Kind::Run => "Running", + Kind::Suggest => "Suggesting", + _ => return format!("{self:?}"), } + .to_owned() } } @@ -689,7 +687,8 @@ impl<'a> Builder<'a> { tool::Miri, tool::CargoMiri, llvm::Lld, - llvm::CrtBeginEnd + llvm::CrtBeginEnd, + tool::RustdocGUITest, ), Kind::Check | Kind::Clippy | Kind::Fix => describe!( check::Std, @@ -787,6 +786,7 @@ impl<'a> Builder<'a> { doc::EditionGuide, doc::StyleGuide, doc::Tidy, + doc::Bootstrap, ), Kind::Dist => describe!( dist::Docs, @@ -1355,7 +1355,7 @@ impl<'a> Builder<'a> { "error: `x.py clippy` requires a host `rustc` toolchain with the `clippy` component" ); eprintln!("help: try `rustup component add clippy`"); - crate::detail_exit(1); + crate::detail_exit_macro!(1); }); if !t!(std::str::from_utf8(&output.stdout)).contains("nightly") { rustflags.arg("--cfg=bootstrap"); @@ -1915,10 +1915,10 @@ impl<'a> Builder<'a> { } // For `cargo doc` invocations, make rustdoc print the Rust version into the docs - // This replaces spaces with newlines because RUSTDOCFLAGS does not + // This replaces spaces with tabs because RUSTDOCFLAGS does not // support arguments with regular spaces. Hopefully someday Cargo will // have space support. - let rust_version = self.rust_version().replace(' ', "\n"); + let rust_version = self.rust_version().replace(' ', "\t"); rustdocflags.arg("--crate-version").arg(&rust_version); // Environment variables *required* throughout the build diff --git a/src/bootstrap/builder/tests.rs b/src/bootstrap/builder/tests.rs index edca8fe9b13..d76b830b0e5 100644 --- a/src/bootstrap/builder/tests.rs +++ b/src/bootstrap/builder/tests.rs @@ -1,5 +1,6 @@ use super::*; use crate::config::{Config, DryRun, TargetSelection}; +use crate::doc::DocumentationFormat; use std::thread; fn configure(cmd: &str, host: &[&str], target: &[&str]) -> Config { @@ -66,6 +67,16 @@ macro_rules! std { }; } +macro_rules! doc_std { + ($host:ident => $target:ident, stage = $stage:literal) => { + doc::Std::new( + $stage, + TargetSelection::from_user(stringify!($target)), + DocumentationFormat::HTML, + ) + }; +} + macro_rules! rustc { ($host:ident => $target:ident, stage = $stage:literal) => { compile::Rustc::new( @@ -144,6 +155,9 @@ fn alias_and_path_for_library() { first(cache.all::<compile::Std>()), &[std!(A => A, stage = 0), std!(A => A, stage = 1)] ); + + let mut cache = run_build(&["library".into(), "core".into()], configure("doc", &["A"], &["A"])); + assert_eq!(first(cache.all::<doc::Std>()), &[doc_std!(A => A, stage = 0)]); } #[test] diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index b11be96cefe..f5a93854bf2 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -1,8 +1,10 @@ //! Implementation of compiling the compiler and standard library, in "check"-based modes. -use crate::builder::{Builder, Kind, RunConfig, ShouldRun, Step}; +use crate::builder::{crate_description, Builder, Kind, RunConfig, ShouldRun, Step}; use crate::cache::Interned; -use crate::compile::{add_to_sysroot, run_cargo, rustc_cargo, rustc_cargo_env, std_cargo}; +use crate::compile::{ + add_to_sysroot, make_run_crates, run_cargo, rustc_cargo, rustc_cargo_env, std_cargo, +}; use crate::config::TargetSelection; use crate::tool::{prepare_tool_cargo, SourceType}; use crate::INTERNER; @@ -12,6 +14,12 @@ use std::path::{Path, PathBuf}; #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct Std { pub target: TargetSelection, + /// Whether to build only a subset of crates. + /// + /// This shouldn't be used from other steps; see the comment on [`compile::Rustc`]. + /// + /// [`compile::Rustc`]: crate::compile::Rustc + crates: Interned<Vec<String>>, } /// Returns args for the subcommand itself (not for cargo) @@ -66,16 +74,23 @@ fn cargo_subcommand(kind: Kind) -> &'static str { } } +impl Std { + pub fn new(target: TargetSelection) -> Self { + Self { target, crates: INTERNER.intern_list(vec![]) } + } +} + impl Step for Std { type Output = (); const DEFAULT: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.all_krates("sysroot").path("library") + run.crate_or_deps("sysroot").path("library") } fn make_run(run: RunConfig<'_>) { - run.builder.ensure(Std { target: run.target }); + let crates = make_run_crates(&run, "library"); + run.builder.ensure(Std { target: run.target, crates }); } fn run(self, builder: &Builder<'_>) { @@ -97,7 +112,14 @@ impl Step for Std { cargo.arg("--lib"); } - let _guard = builder.msg_check("library artifacts", target); + for krate in &*self.crates { + cargo.arg("-p").arg(krate); + } + + let _guard = builder.msg_check( + format_args!("library artifacts{}", crate_description(&self.crates)), + target, + ); run_cargo( builder, cargo, @@ -117,7 +139,8 @@ impl Step for Std { } // don't run on std twice with x.py clippy - if builder.kind == Kind::Clippy { + // don't check test dependencies if we haven't built libtest + if builder.kind == Kind::Clippy || !self.crates.is_empty() { return; } @@ -147,8 +170,8 @@ impl Step for Std { // Explicitly pass -p for all dependencies krates -- this will force cargo // to also check the tests/benches/examples for these crates, rather // than just the leaf crate. - for krate in builder.in_tree_crates("test", Some(target)) { - cargo.arg("-p").arg(krate.name); + for krate in &*self.crates { + cargo.arg("-p").arg(krate); } let _guard = builder.msg_check("library test/bench/example targets", target); @@ -167,6 +190,22 @@ impl Step for Std { #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct Rustc { pub target: TargetSelection, + /// Whether to build only a subset of crates. + /// + /// This shouldn't be used from other steps; see the comment on [`compile::Rustc`]. + /// + /// [`compile::Rustc`]: crate::compile::Rustc + crates: Interned<Vec<String>>, +} + +impl Rustc { + pub fn new(target: TargetSelection, builder: &Builder<'_>) -> Self { + let mut crates = vec![]; + for krate in builder.in_tree_crates("rustc-main", None) { + crates.push(krate.name.to_string()); + } + Self { target, crates: INTERNER.intern_list(crates) } + } } impl Step for Rustc { @@ -175,11 +214,12 @@ impl Step for Rustc { const DEFAULT: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.all_krates("rustc-main").path("compiler") + run.crate_or_deps("rustc-main").path("compiler") } fn make_run(run: RunConfig<'_>) { - run.builder.ensure(Rustc { target: run.target }); + let crates = make_run_crates(&run, "compiler"); + run.builder.ensure(Rustc { target: run.target, crates }); } /// Builds the compiler. @@ -200,7 +240,7 @@ impl Step for Rustc { builder.ensure(crate::compile::Std::new(compiler, compiler.host)); builder.ensure(crate::compile::Std::new(compiler, target)); } else { - builder.ensure(Std { target }); + builder.ensure(Std::new(target)); } let mut cargo = builder.cargo( @@ -218,14 +258,17 @@ impl Step for Rustc { cargo.arg("--all-targets"); } - // Explicitly pass -p for all compiler krates -- this will force cargo + // Explicitly pass -p for all compiler crates -- this will force cargo // to also check the tests/benches/examples for these crates, rather // than just the leaf crate. - for krate in builder.in_tree_crates("rustc-main", Some(target)) { - cargo.arg("-p").arg(krate.name); + for krate in &*self.crates { + cargo.arg("-p").arg(krate); } - let _guard = builder.msg_check("compiler artifacts", target); + let _guard = builder.msg_check( + format_args!("compiler artifacts{}", crate_description(&self.crates)), + target, + ); run_cargo( builder, cargo, @@ -268,7 +311,7 @@ impl Step for CodegenBackend { let target = self.target; let backend = self.backend; - builder.ensure(Rustc { target }); + builder.ensure(Rustc::new(target, builder)); let mut cargo = builder.cargo( compiler, @@ -318,7 +361,7 @@ impl Step for RustAnalyzer { let compiler = builder.compiler(builder.top_stage, builder.config.build); let target = self.target; - builder.ensure(Std { target }); + builder.ensure(Std::new(target)); let mut cargo = prepare_tool_cargo( builder, @@ -386,7 +429,7 @@ macro_rules! tool_check_step { let compiler = builder.compiler(builder.top_stage, builder.config.build); let target = self.target; - builder.ensure(Rustc { target }); + builder.ensure(Rustc::new(target, builder)); let mut cargo = prepare_tool_cargo( builder, diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 33addb90da3..1c66c00eda7 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -48,6 +48,17 @@ impl Std { } } +/// Given an `alias` selected by the `Step` and the paths passed on the command line, +/// return a list of the crates that should be built. +/// +/// Normally, people will pass *just* `library` if they pass it. +/// But it's possible (although strange) to pass something like `library std core`. +/// Build all crates anyway, as if they hadn't passed the other args. +pub(crate) fn make_run_crates(run: &RunConfig<'_>, alias: &str) -> Interned<Vec<String>> { + let has_alias = run.paths.iter().any(|set| set.assert_single_path().path.ends_with(alias)); + if has_alias { Default::default() } else { run.cargo_crates_in_set() } +} + impl Step for Std { type Output = (); const DEFAULT: bool = true; @@ -62,16 +73,10 @@ impl Step for Std { } fn make_run(run: RunConfig<'_>) { - // Normally, people will pass *just* library if they pass it. - // But it's possible (although strange) to pass something like `library std core`. - // Build all crates anyway, as if they hadn't passed the other args. - let has_library = - run.paths.iter().any(|set| set.assert_single_path().path.ends_with("library")); - let crates = if has_library { Default::default() } else { run.cargo_crates_in_set() }; run.builder.ensure(Std { compiler: run.builder.compiler(run.builder.top_stage, run.build_triple()), target: run.target, - crates, + crates: make_run_crates(&run, "library"), }); } @@ -615,6 +620,8 @@ impl Step for Rustc { fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { let mut crates = run.builder.in_tree_crates("rustc-main", None); for (i, krate) in crates.iter().enumerate() { + // We can't allow `build rustc` as an alias for this Step, because that's reserved by `Assemble`. + // Ideally Assemble would use `build compiler` instead, but that seems too confusing to be worth the breaking change. if krate.name == "rustc-main" { crates.swap_remove(i); break; @@ -1679,7 +1686,7 @@ pub fn run_cargo( }); if !ok { - crate::detail_exit(1); + crate::detail_exit_macro!(1); } // Ok now we need to actually find all the files listed in `toplevel`. We've diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index e192cda9a9a..45ad1547eb7 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -23,8 +23,8 @@ use crate::channel::{self, GitInfo}; pub use crate::flags::Subcommand; use crate::flags::{Color, Flags, Warnings}; use crate::util::{exe, output, t}; +use build_helper::detail_exit_macro; use once_cell::sync::OnceCell; -use semver::Version; use serde::{Deserialize, Deserializer}; use serde_derive::Deserialize; @@ -580,7 +580,7 @@ macro_rules! define_config { panic!("overriding existing option") } else { eprintln!("overriding existing option: `{}`", stringify!($field)); - crate::detail_exit(2); + detail_exit_macro!(2); } } else { self.$field = other.$field; @@ -679,7 +679,7 @@ impl<T> Merge for Option<T> { panic!("overriding existing option") } else { eprintln!("overriding existing option"); - crate::detail_exit(2); + detail_exit_macro!(2); } } else { *self = other; @@ -945,7 +945,7 @@ impl Config { .and_then(|table: toml::Value| TomlConfig::deserialize(table)) .unwrap_or_else(|err| { eprintln!("failed to parse TOML configuration '{}': {err}", file.display()); - crate::detail_exit(2); + detail_exit_macro!(2); }) } Self::parse_inner(args, get_toml) @@ -979,7 +979,7 @@ impl Config { eprintln!( "Cannot use both `llvm_bolt_profile_generate` and `llvm_bolt_profile_use` at the same time" ); - crate::detail_exit(1); + detail_exit_macro!(1); } // Infer the rest of the configuration. @@ -1095,7 +1095,7 @@ impl Config { } } eprintln!("failed to parse override `{option}`: `{err}"); - crate::detail_exit(2) + detail_exit_macro!(2) } toml.merge(override_toml, ReplaceOpt::Override); @@ -1118,7 +1118,6 @@ impl Config { config.download_beta_toolchain(); config.out.join(config.build.triple).join("stage0/bin/rustc") }); - config.initial_cargo = build .cargo .map(|cargo| { @@ -1780,42 +1779,6 @@ impl Config { self.rust_codegen_backends.get(0).cloned() } - pub fn check_build_rustc_version(&self) { - if self.dry_run() { - return; - } - - // check rustc version is same or lower with 1 apart from the building one - let mut cmd = Command::new(&self.initial_rustc); - cmd.arg("--version"); - let rustc_output = output(&mut cmd) - .lines() - .next() - .unwrap() - .split(' ') - .nth(1) - .unwrap() - .split('-') - .next() - .unwrap() - .to_owned(); - let rustc_version = Version::parse(&rustc_output.trim()).unwrap(); - let source_version = - Version::parse(&fs::read_to_string(self.src.join("src/version")).unwrap().trim()) - .unwrap(); - if !(source_version == rustc_version - || (source_version.major == rustc_version.major - && source_version.minor == rustc_version.minor + 1)) - { - let prev_version = format!("{}.{}.x", source_version.major, source_version.minor - 1); - eprintln!( - "Unexpected rustc version: {}, we should use {}/{} to build source with {}", - rustc_version, prev_version, source_version, source_version - ); - crate::detail_exit(1); - } - } - /// Returns the commit to download, or `None` if we shouldn't download CI artifacts. fn download_ci_rustc_commit(&self, download_rustc: Option<StringOrBool>) -> Option<String> { // If `download-rustc` is not set, default to rebuilding. @@ -1848,7 +1811,7 @@ impl Config { println!("help: maybe your repository history is too shallow?"); println!("help: consider disabling `download-rustc`"); println!("help: or fetch enough history to include one upstream commit"); - crate::detail_exit(1); + crate::detail_exit_macro!(1); } // Warn if there were changes to the compiler or standard library since the ancestor commit. diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index b49845386da..46fc5b80e99 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -106,11 +106,7 @@ impl Step for JsonDocs { /// Builds the `rust-docs-json` installer component. fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> { let host = self.host; - builder.ensure(crate::doc::Std { - stage: builder.top_stage, - target: host, - format: DocumentationFormat::JSON, - }); + builder.ensure(crate::doc::Std::new(builder.top_stage, host, DocumentationFormat::JSON)); let dest = "share/doc/rust/json"; diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index 8f5d9bb66e1..3de85c91516 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -7,7 +7,6 @@ //! Everything here is basically just a shim around calling either `rustbook` or //! `rustdoc`. -use std::ffi::OsStr; use std::fs; use std::io; use std::path::{Path, PathBuf}; @@ -16,6 +15,7 @@ use crate::builder::crate_description; use crate::builder::{Builder, Compiler, Kind, RunConfig, ShouldRun, Step}; use crate::cache::{Interned, INTERNER}; use crate::compile; +use crate::compile::make_run_crates; use crate::config::{Config, TargetSelection}; use crate::tool::{self, prepare_tool_cargo, SourceType, Tool}; use crate::util::{symlink_dir, t, up_to_date}; @@ -87,15 +87,6 @@ book!( StyleGuide, "src/doc/style-guide", "style-guide"; ); -// "library/std" -> ["library", "std"] -// -// Used for deciding whether a particular step is one requested by the user on -// the `x.py doc` command line, which determines whether `--open` will open that -// page. -pub(crate) fn components_simplified(path: &PathBuf) -> Vec<&str> { - path.iter().map(|component| component.to_str().unwrap_or("???")).collect() -} - #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct UnstableBook { target: TargetSelection, @@ -425,11 +416,18 @@ impl Step for SharedAssets { } } -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Std { pub stage: u32, pub target: TargetSelection, pub format: DocumentationFormat, + crates: Interned<Vec<String>>, +} + +impl Std { + pub(crate) fn new(stage: u32, target: TargetSelection, format: DocumentationFormat) -> Self { + Std { stage, target, format, crates: INTERNER.intern_list(vec![]) } + } } impl Step for Std { @@ -438,7 +436,7 @@ impl Step for Std { fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { let builder = run.builder; - run.all_krates("sysroot").path("library").default_condition(builder.config.docs) + run.crate_or_deps("sysroot").path("library").default_condition(builder.config.docs) } fn make_run(run: RunConfig<'_>) { @@ -450,6 +448,7 @@ impl Step for Std { } else { DocumentationFormat::HTML }, + crates: make_run_crates(&run, "library"), }); } @@ -457,7 +456,7 @@ impl Step for Std { /// /// This will generate all documentation for the standard library and its /// dependencies. This is largely just a wrapper around `cargo doc`. - fn run(self, builder: &Builder<'_>) { + fn run(mut self, builder: &Builder<'_>) { let stage = self.stage; let target = self.target; let out = match self.format { @@ -471,41 +470,24 @@ impl Step for Std { builder.ensure(SharedAssets { target: self.target }); } - let index_page = builder.src.join("src/doc/index.md").into_os_string(); + let index_page = builder + .src + .join("src/doc/index.md") + .into_os_string() + .into_string() + .expect("non-utf8 paths are unsupported"); let mut extra_args = match self.format { - DocumentationFormat::HTML => vec![ - OsStr::new("--markdown-css"), - OsStr::new("rust.css"), - OsStr::new("--markdown-no-toc"), - OsStr::new("--index-page"), - &index_page, - ], - DocumentationFormat::JSON => vec![OsStr::new("--output-format"), OsStr::new("json")], + DocumentationFormat::HTML => { + vec!["--markdown-css", "rust.css", "--markdown-no-toc", "--index-page", &index_page] + } + DocumentationFormat::JSON => vec!["--output-format", "json"], }; if !builder.config.docs_minification { - extra_args.push(OsStr::new("--disable-minification")); + extra_args.push("--disable-minification"); } - let requested_crates = builder - .paths - .iter() - .map(components_simplified) - .filter_map(|path| { - if path.len() >= 2 && path.get(0) == Some(&"library") { - // single crate - Some(path[1].to_owned()) - } else if !path.is_empty() { - // ?? - Some(path[0].to_owned()) - } else { - // all library crates - None - } - }) - .collect::<Vec<_>>(); - - doc_std(builder, self.format, stage, target, &out, &extra_args, &requested_crates); + doc_std(builder, self.format, stage, target, &out, &extra_args, &self.crates); // Don't open if the format is json if let DocumentationFormat::JSON = self.format { @@ -514,7 +496,11 @@ impl Step for Std { // Look for library/std, library/core etc in the `x.py doc` arguments and // open the corresponding rendered docs. - for requested_crate in requested_crates { + if self.crates.is_empty() { + self.crates = INTERNER.intern_list(vec!["library".to_owned()]); + }; + + for requested_crate in &*self.crates { if requested_crate == "library" { // For `x.py doc library --open`, open `std` by default. let index = out.join("std").join("index.html"); @@ -538,7 +524,7 @@ impl Step for Std { /// or remote link. const STD_PUBLIC_CRATES: [&str; 5] = ["core", "alloc", "std", "proc_macro", "test"]; -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub enum DocumentationFormat { HTML, JSON, @@ -563,24 +549,22 @@ fn doc_std( stage: u32, target: TargetSelection, out: &Path, - extra_args: &[&OsStr], + extra_args: &[&str], requested_crates: &[String], ) { - builder.info(&format!( - "Documenting{} stage{} library ({}) in {} format", - crate_description(requested_crates), - stage, - target, - format.as_str() - )); if builder.no_std(target) == Some(true) { panic!( "building std documentation for no_std target {target} is not supported\n\ - Set `docs = false` in the config to disable documentation." + Set `docs = false` in the config to disable documentation, or pass `--exclude doc::library`." ); } + let compiler = builder.compiler(stage, builder.config.build); + let description = + format!("library{} in {} format", crate_description(&requested_crates), format.as_str()); + let _guard = builder.msg(Kind::Doc, stage, &description, compiler.host, target); + let target_doc_dir_name = if format == DocumentationFormat::JSON { "json-doc" } else { "doc" }; let target_dir = builder.stage_out(compiler, Mode::Std).join(target.triple).join(target_doc_dir_name); @@ -590,35 +574,42 @@ fn doc_std( // as a function parameter. let out_dir = target_dir.join(target.triple).join("doc"); - let run_cargo_rustdoc_for = |package: &str| { - let mut cargo = builder.cargo(compiler, Mode::Std, SourceType::InTree, target, "rustdoc"); - compile::std_cargo(builder, target, compiler.stage, &mut cargo); - cargo - .arg("--target-dir") - .arg(&*target_dir.to_string_lossy()) - .arg("-p") - .arg(package) - .arg("-Zskip-rustdoc-fingerprint") - .arg("--") - .arg("-Z") - .arg("unstable-options") - .arg("--resource-suffix") - .arg(&builder.version) - .args(extra_args); - if builder.config.library_docs_private_items { - cargo.arg("--document-private-items").arg("--document-hidden-items"); - } - builder.run(&mut cargo.into()); + let mut cargo = builder.cargo(compiler, Mode::Std, SourceType::InTree, target, "doc"); + compile::std_cargo(builder, target, compiler.stage, &mut cargo); + cargo + .arg("--no-deps") + .arg("--target-dir") + .arg(&*target_dir.to_string_lossy()) + .arg("-Zskip-rustdoc-fingerprint") + .rustdocflag("-Z") + .rustdocflag("unstable-options") + .rustdocflag("--resource-suffix") + .rustdocflag(&builder.version); + for arg in extra_args { + cargo.rustdocflag(arg); + } + + if builder.config.library_docs_private_items { + cargo.rustdocflag("--document-private-items").rustdocflag("--document-hidden-items"); + } + + // HACK: because we use `--manifest-path library/sysroot/Cargo.toml`, cargo thinks we only want to document that specific crate, not its dependencies. + // Override its default. + let built_crates = if requested_crates.is_empty() { + builder + .in_tree_crates("sysroot", None) + .into_iter() + .map(|krate| krate.name.to_string()) + .collect() + } else { + requested_crates.to_vec() }; - for krate in STD_PUBLIC_CRATES { - run_cargo_rustdoc_for(krate); - if requested_crates.iter().any(|p| p == krate) { - // No need to document more of the libraries if we have the one we want. - break; - } + for krate in built_crates { + cargo.arg("-p").arg(krate); } + builder.run(&mut cargo.into()); builder.cp_r(&out_dir, &out); } @@ -626,6 +617,28 @@ fn doc_std( pub struct Rustc { pub stage: u32, pub target: TargetSelection, + crates: Interned<Vec<String>>, +} + +impl Rustc { + pub(crate) fn new(stage: u32, target: TargetSelection, builder: &Builder<'_>) -> Self { + // Find dependencies for top level crates. + let root_crates = vec![ + INTERNER.intern_str("rustc_driver"), + INTERNER.intern_str("rustc_codegen_llvm"), + INTERNER.intern_str("rustc_codegen_ssa"), + ]; + let crates: Vec<_> = root_crates + .iter() + .flat_map(|krate| { + builder + .in_tree_crates(krate, Some(target)) + .into_iter() + .map(|krate| krate.name.to_string()) + }) + .collect(); + Self { stage, target, crates: INTERNER.intern_list(crates) } + } } impl Step for Rustc { @@ -641,7 +654,11 @@ impl Step for Rustc { } fn make_run(run: RunConfig<'_>) { - run.builder.ensure(Rustc { stage: run.builder.top_stage, target: run.target }); + run.builder.ensure(Rustc { + stage: run.builder.top_stage, + target: run.target, + crates: make_run_crates(&run, "compiler"), + }); } /// Generates compiler documentation. @@ -654,15 +671,6 @@ impl Step for Rustc { let stage = self.stage; let target = self.target; - let paths = builder - .paths - .iter() - .filter(|path| { - let components = components_simplified(path); - components.len() >= 2 && components[0] == "compiler" - }) - .collect::<Vec<_>>(); - // This is the intended out directory for compiler documentation. let out = builder.compiler_doc_out(target); t!(fs::create_dir_all(&out)); @@ -672,7 +680,13 @@ impl Step for Rustc { let compiler = builder.compiler(stage, builder.config.build); builder.ensure(compile::Std::new(compiler, builder.config.build)); - builder.info(&format!("Documenting stage{} compiler ({})", stage, target)); + let _guard = builder.msg( + Kind::Doc, + stage, + &format!("compiler{}", crate_description(&self.crates)), + compiler.host, + target, + ); // This uses a shared directory so that librustdoc documentation gets // correctly built and merged with the rustc documentation. This is @@ -710,22 +724,8 @@ impl Step for Rustc { cargo.rustdocflag("--extern-html-root-url"); cargo.rustdocflag("ena=https://docs.rs/ena/latest/"); - let root_crates = if paths.is_empty() { - vec![ - INTERNER.intern_str("rustc_driver"), - INTERNER.intern_str("rustc_codegen_llvm"), - INTERNER.intern_str("rustc_codegen_ssa"), - ] - } else { - paths.into_iter().map(|p| builder.crate_paths[p]).collect() - }; - // Find dependencies for top level crates. - let compiler_crates = root_crates.iter().flat_map(|krate| { - builder.in_tree_crates(krate, Some(target)).into_iter().map(|krate| krate.name) - }); - let mut to_open = None; - for krate in compiler_crates { + for krate in &*self.crates { // Create all crate output directories first to make sure rustdoc uses // relative links. // FIXME: Cargo should probably do this itself. @@ -785,7 +785,7 @@ macro_rules! tool_doc { if true $(&& $rustc_tool)? { // Build rustc docs so that we generate relative links. - builder.ensure(Rustc { stage, target }); + builder.ensure(Rustc::new(stage, target, builder)); // Rustdoc needs the rustc sysroot available to build. // FIXME: is there a way to only ensure `check::Rustc` here? Last time I tried it failed @@ -839,6 +839,8 @@ macro_rules! tool_doc { )+ cargo.rustdocflag("--document-private-items"); + // Since we always pass --document-private-items, there's no need to warn about linking to private items. + cargo.rustdocflag("-Arustdoc::private-intra-doc-links"); cargo.rustdocflag("--enable-index-page"); cargo.rustdocflag("--show-type-layout"); cargo.rustdocflag("--generate-link-to-definition"); @@ -882,7 +884,8 @@ tool_doc!( // "cargo-credential-wincred", ] ); -tool_doc!(Tidy, "tidy", "src/tools/tidy", ["tidy"]); +tool_doc!(Tidy, "tidy", "src/tools/tidy", rustc_tool = false, ["tidy"]); +tool_doc!(Bootstrap, "bootstrap", "src/bootstrap", rustc_tool = false, ["bootstrap"]); #[derive(Ord, PartialOrd, Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct ErrorIndex { diff --git a/src/bootstrap/download.rs b/src/bootstrap/download.rs index 25df5b2573b..12780df2175 100644 --- a/src/bootstrap/download.rs +++ b/src/bootstrap/download.rs @@ -7,6 +7,7 @@ use std::{ process::{Command, Stdio}, }; +use build_helper::util::try_run; use once_cell::sync::OnceCell; use xz2::bufread::XzDecoder; @@ -14,7 +15,7 @@ use crate::{ config::RustfmtMetadata, llvm::detect_llvm_sha, t, - util::{check_run, exe, program_out_of_date, try_run}, + util::{check_run, exe, program_out_of_date}, Config, }; @@ -123,7 +124,7 @@ impl Config { /// This is only required on NixOS and uses the PatchELF utility to /// change the interpreter/RPATH of ELF executables. /// - /// Please see https://nixos.org/patchelf.html for more information + /// Please see <https://nixos.org/patchelf.html> for more information fn fix_bin_or_dylib(&self, fname: &Path) { assert_eq!(SHOULD_FIX_BINS_AND_DYLIBS.get(), Some(&true)); println!("attempting to patch {}", fname.display()); @@ -245,7 +246,7 @@ impl Config { if !help_on_error.is_empty() { eprintln!("{}", help_on_error); } - crate::detail_exit(1); + crate::detail_exit_macro!(1); } } diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index 80e71577798..dc05f47ee9c 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -193,7 +193,7 @@ impl Flags { } else { panic!("No paths available for subcommand `{}`", subcommand.as_str()); } - crate::detail_exit(0); + crate::detail_exit_macro!(0); } Flags::parse_from(it) @@ -538,7 +538,7 @@ pub fn get_completion<G: clap_complete::Generator>(shell: G, path: &Path) -> Opt } else { std::fs::read_to_string(path).unwrap_or_else(|_| { eprintln!("couldn't read {}", path.display()); - crate::detail_exit(1) + crate::detail_exit_macro!(1) }) }; let mut buf = Vec::new(); diff --git a/src/bootstrap/format.rs b/src/bootstrap/format.rs index d8d3f300a35..ebf068b2cb1 100644 --- a/src/bootstrap/format.rs +++ b/src/bootstrap/format.rs @@ -40,7 +40,7 @@ fn rustfmt(src: &Path, rustfmt: &Path, paths: &[PathBuf], check: bool) -> impl F code, run `./x.py fmt` instead.", cmd_debug, ); - crate::detail_exit(1); + crate::detail_exit_macro!(1); } true } @@ -196,7 +196,7 @@ pub fn format(build: &Builder<'_>, check: bool, paths: &[PathBuf]) { let rustfmt_path = build.initial_rustfmt().unwrap_or_else(|| { eprintln!("./x.py fmt is not supported on this channel"); - crate::detail_exit(1); + crate::detail_exit_macro!(1); }); assert!(rustfmt_path.exists(), "{}", rustfmt_path.display()); let src = build.src.clone(); diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 6ee50ee6573..a1aaee68c62 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -27,6 +27,7 @@ use std::process::{Command, Stdio}; use std::str; use build_helper::ci::{gha, CiEnv}; +use build_helper::detail_exit_macro; use channel::GitInfo; use config::{DryRun, Target}; use filetime::FileTime; @@ -414,7 +415,6 @@ impl Build { bootstrap_out.display() ) } - config.check_build_rustc_version(); if rust_info.is_from_tarball() && config.description.is_none() { config.description = Some("built from a source tarball".to_owned()); @@ -700,7 +700,7 @@ impl Build { for failure in failures.iter() { eprintln!(" - {}\n", failure); } - detail_exit(1); + detail_exit_macro!(1); } #[cfg(feature = "build-metrics")] @@ -1011,6 +1011,8 @@ impl Build { } /// Return a `Group` guard for a [`Step`] that is built for each `--stage`. + /// + /// [`Step`]: crate::builder::Step fn msg( &self, action: impl Into<Kind>, @@ -1019,8 +1021,8 @@ impl Build { host: impl Into<Option<TargetSelection>>, target: impl Into<Option<TargetSelection>>, ) -> Option<gha::Group> { - let action = action.into(); - let msg = |fmt| format!("{action:?}ing stage{stage} {what}{fmt}"); + let action = action.into().description(); + let msg = |fmt| format!("{action} stage{stage} {what}{fmt}"); let msg = if let Some(target) = target.into() { let host = host.into().unwrap(); if host == target { @@ -1035,6 +1037,8 @@ impl Build { } /// Return a `Group` guard for a [`Step`] that is only built once and isn't affected by `--stage`. + /// + /// [`Step`]: crate::builder::Step fn msg_unstaged( &self, action: impl Into<Kind>, @@ -1479,7 +1483,7 @@ impl Build { "Error: Unable to find the stamp file {}, did you try to keep a nonexistent build stage?", stamp.display() ); - crate::detail_exit(1); + crate::detail_exit_macro!(1); } let mut paths = Vec::new(); @@ -1671,7 +1675,7 @@ Alternatively, set `download-ci-llvm = true` in that `[llvm]` section to download LLVM rather than building it. " ); - detail_exit(1); + detail_exit_macro!(1); } } @@ -1736,18 +1740,6 @@ fn chmod(path: &Path, perms: u32) { #[cfg(windows)] fn chmod(_path: &Path, _perms: u32) {} -/// If code is not 0 (successful exit status), exit status is 101 (rust's default error code.) -/// If the test is running and code is an error code, it will cause a panic. -fn detail_exit(code: i32) -> ! { - // if in test and code is an error code, panic with status code provided - if cfg!(test) { - panic!("status code: {}", code); - } else { - // otherwise,exit with provided status code - std::process::exit(code); - } -} - impl Compiler { pub fn with_stage(mut self, stage: u32) -> Compiler { self.stage = stage; diff --git a/src/bootstrap/llvm.rs b/src/bootstrap/llvm.rs index 040a12f5d10..3fd0cca40e5 100644 --- a/src/bootstrap/llvm.rs +++ b/src/bootstrap/llvm.rs @@ -1017,7 +1017,7 @@ fn supported_sanitizers( "x86_64-unknown-illumos" => common_libs("illumos", "x86_64", &["asan"]), "x86_64-pc-solaris" => common_libs("solaris", "x86_64", &["asan"]), "x86_64-unknown-linux-gnu" => { - common_libs("linux", "x86_64", &["asan", "lsan", "msan", "tsan"]) + common_libs("linux", "x86_64", &["asan", "lsan", "msan", "safestack", "tsan"]) } "x86_64-unknown-linux-musl" => { common_libs("linux", "x86_64", &["asan", "lsan", "msan", "tsan"]) diff --git a/src/bootstrap/metrics.rs b/src/bootstrap/metrics.rs index e19d56ccd6a..5990f33b9bc 100644 --- a/src/bootstrap/metrics.rs +++ b/src/bootstrap/metrics.rs @@ -14,6 +14,25 @@ use std::io::BufWriter; use std::time::{Duration, Instant, SystemTime}; use sysinfo::{CpuExt, System, SystemExt}; +// Update this number whenever a breaking change is made to the build metrics. +// +// The output format is versioned for two reasons: +// +// - The metadata is intended to be consumed by external tooling, and exposing a format version +// helps the tools determine whether they're compatible with a metrics file. +// +// - If a developer enables build metrics in their local checkout, making a breaking change to the +// metrics format would result in a hard-to-diagnose error message when an existing metrics file +// is not compatible with the new changes. With a format version number, bootstrap can discard +// incompatible metrics files instead of appending metrics to them. +// +// Version changelog: +// +// - v0: initial version +// - v1: replaced JsonNode::Test with JsonNode::TestSuite +// +const CURRENT_FORMAT_VERSION: usize = 1; + pub(crate) struct BuildMetrics { state: RefCell<MetricsState>, } @@ -57,7 +76,7 @@ impl BuildMetrics { duration_excluding_children_sec: Duration::ZERO, children: Vec::new(), - tests: Vec::new(), + test_suites: Vec::new(), }); } @@ -84,6 +103,17 @@ impl BuildMetrics { } } + pub(crate) fn begin_test_suite(&self, metadata: TestSuiteMetadata, builder: &Builder<'_>) { + // Do not record dry runs, as they'd be duplicates of the actual steps. + if builder.config.dry_run() { + return; + } + + let mut state = self.state.borrow_mut(); + let step = state.running_steps.last_mut().unwrap(); + step.test_suites.push(TestSuite { metadata, tests: Vec::new() }); + } + pub(crate) fn record_test(&self, name: &str, outcome: TestOutcome, builder: &Builder<'_>) { // Do not record dry runs, as they'd be duplicates of the actual steps. if builder.config.dry_run() { @@ -91,12 +121,13 @@ impl BuildMetrics { } let mut state = self.state.borrow_mut(); - state - .running_steps - .last_mut() - .unwrap() - .tests - .push(Test { name: name.to_string(), outcome }); + let step = state.running_steps.last_mut().unwrap(); + + if let Some(test_suite) = step.test_suites.last_mut() { + test_suite.tests.push(Test { name: name.to_string(), outcome }); + } else { + panic!("metrics.record_test() called without calling metrics.begin_test_suite() first"); + } } fn collect_stats(&self, state: &mut MetricsState) { @@ -131,7 +162,20 @@ impl BuildMetrics { // Some of our CI builds consist of multiple independent CI invocations. Ensure all the // previous invocations are still present in the resulting file. let mut invocations = match std::fs::read(&dest) { - Ok(contents) => t!(serde_json::from_slice::<JsonRoot>(&contents)).invocations, + Ok(contents) => { + // We first parse just the format_version field to have the check succeed even if + // the rest of the contents are not valid anymore. + let version: OnlyFormatVersion = t!(serde_json::from_slice(&contents)); + if version.format_version == CURRENT_FORMAT_VERSION { + t!(serde_json::from_slice::<JsonRoot>(&contents)).invocations + } else { + println!( + "warning: overriding existing build/metrics.json, as it's not \ + compatible with build metrics format version {CURRENT_FORMAT_VERSION}." + ); + Vec::new() + } + } Err(err) => { if err.kind() != std::io::ErrorKind::NotFound { panic!("failed to open existing metrics file at {}: {err}", dest.display()); @@ -149,7 +193,7 @@ impl BuildMetrics { children: steps.into_iter().map(|step| self.prepare_json_step(step)).collect(), }); - let json = JsonRoot { system_stats, invocations }; + let json = JsonRoot { format_version: CURRENT_FORMAT_VERSION, system_stats, invocations }; t!(std::fs::create_dir_all(dest.parent().unwrap())); let mut file = BufWriter::new(t!(File::create(&dest))); @@ -159,11 +203,7 @@ impl BuildMetrics { fn prepare_json_step(&self, step: StepMetrics) -> JsonNode { let mut children = Vec::new(); children.extend(step.children.into_iter().map(|child| self.prepare_json_step(child))); - children.extend( - step.tests - .into_iter() - .map(|test| JsonNode::Test { name: test.name, outcome: test.outcome }), - ); + children.extend(step.test_suites.into_iter().map(JsonNode::TestSuite)); JsonNode::RustbuildStep { type_: step.type_, @@ -198,17 +238,14 @@ struct StepMetrics { duration_excluding_children_sec: Duration, children: Vec<StepMetrics>, - tests: Vec<Test>, -} - -struct Test { - name: String, - outcome: TestOutcome, + test_suites: Vec<TestSuite>, } #[derive(Serialize, Deserialize)] #[serde(rename_all = "snake_case")] struct JsonRoot { + #[serde(default)] // For version 0 the field was not present. + format_version: usize, system_stats: JsonInvocationSystemStats, invocations: Vec<JsonInvocation>, } @@ -237,14 +274,42 @@ enum JsonNode { children: Vec<JsonNode>, }, - Test { - name: String, - #[serde(flatten)] - outcome: TestOutcome, + TestSuite(TestSuite), +} + +#[derive(Serialize, Deserialize)] +struct TestSuite { + metadata: TestSuiteMetadata, + tests: Vec<Test>, +} + +#[derive(Serialize, Deserialize)] +#[serde(tag = "kind", rename_all = "snake_case")] +pub(crate) enum TestSuiteMetadata { + CargoPackage { + crates: Vec<String>, + target: String, + host: String, + stage: u32, + }, + Compiletest { + suite: String, + mode: String, + compare_mode: Option<String>, + target: String, + host: String, + stage: u32, }, } #[derive(Serialize, Deserialize)] +pub(crate) struct Test { + name: String, + #[serde(flatten)] + outcome: TestOutcome, +} + +#[derive(Serialize, Deserialize)] #[serde(tag = "outcome", rename_all = "snake_case")] pub(crate) enum TestOutcome { Passed, @@ -266,3 +331,9 @@ struct JsonInvocationSystemStats { struct JsonStepSystemStats { cpu_utilization_percent: f64, } + +#[derive(Deserialize)] +struct OnlyFormatVersion { + #[serde(default)] // For version 0 the field was not present. + format_version: usize, +} diff --git a/src/bootstrap/render_tests.rs b/src/bootstrap/render_tests.rs index fa0a4806618..872b75f6c15 100644 --- a/src/bootstrap/render_tests.rs +++ b/src/bootstrap/render_tests.rs @@ -30,7 +30,7 @@ pub(crate) fn try_run_tests(builder: &Builder<'_>, cmd: &mut Command) -> bool { if !run_tests(builder, cmd) { if builder.fail_fast { - crate::detail_exit(1); + crate::detail_exit_macro!(1); } else { let mut failures = builder.delayed_failures.borrow_mut(); failures.push(format!("{cmd:?}")); diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs index 140259b0213..8f5ba42736b 100644 --- a/src/bootstrap/sanity.rs +++ b/src/bootstrap/sanity.rs @@ -104,7 +104,7 @@ You should install cmake, or set `download-ci-llvm = true` in the than building it. " ); - crate::detail_exit(1); + crate::detail_exit_macro!(1); } } diff --git a/src/bootstrap/setup.rs b/src/bootstrap/setup.rs index 09f26862b4a..40038df8332 100644 --- a/src/bootstrap/setup.rs +++ b/src/bootstrap/setup.rs @@ -194,7 +194,7 @@ fn setup_config_toml(path: &PathBuf, profile: Profile, config: &Config) { "note: this will use the configuration in {}", profile.include_path(&config.src).display() ); - crate::detail_exit(1); + crate::detail_exit_macro!(1); } let settings = format!( @@ -380,7 +380,7 @@ pub fn interactive_path() -> io::Result<Profile> { io::stdin().read_line(&mut input)?; if input.is_empty() { eprintln!("EOF on stdin, when expecting answer to question. Giving up."); - crate::detail_exit(1); + crate::detail_exit_macro!(1); } break match parse_with_abbrev(&input) { Ok(profile) => profile, diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 2b72d6c48eb..3290e6e0309 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -101,7 +101,7 @@ impl Step for CrateBootstrap { ); builder.info(&format!( "{} {} stage0 ({})", - builder.kind.test_description(), + builder.kind.description(), path, bootstrap_host, )); @@ -220,7 +220,7 @@ impl Step for HtmlCheck { } // Ensure that a few different kinds of documentation are available. builder.default_doc(&[]); - builder.ensure(crate::doc::Rustc { target: self.target, stage: builder.top_stage }); + builder.ensure(crate::doc::Rustc::new(builder.top_stage, self.target, builder)); try_run(builder, builder.tool_cmd(Tool::HtmlChecker).arg(builder.doc_out(self.target))); } @@ -317,6 +317,17 @@ impl Step for Cargo { cargo.env("CARGO_TEST_DISABLE_NIGHTLY", "1"); cargo.env("PATH", &path_for_cargo(builder, compiler)); + #[cfg(feature = "build-metrics")] + builder.metrics.begin_test_suite( + crate::metrics::TestSuiteMetadata::CargoPackage { + crates: vec!["cargo".into()], + target: self.host.triple.to_string(), + host: self.host.triple.to_string(), + stage: self.stage, + }, + builder, + ); + let _time = util::timeit(&builder); add_flags_and_try_run_tests(builder, &mut cargo); } @@ -762,7 +773,7 @@ impl Step for Clippy { } if !builder.config.cmd.bless() { - crate::detail_exit(1); + crate::detail_exit_macro!(1); } let mut cargo = builder.cargo(compiler, Mode::ToolRustc, SourceType::InTree, host, "run"); @@ -875,11 +886,11 @@ impl Step for RustdocJSStd { command.arg("--test-file").arg(path); } } - builder.ensure(crate::doc::Std { - target: self.target, - stage: builder.top_stage, - format: DocumentationFormat::HTML, - }); + builder.ensure(crate::doc::Std::new( + builder.top_stage, + self.target, + DocumentationFormat::HTML, + )); builder.run(&mut command); } else { builder.info("No nodejs found, skipping \"tests/rustdoc-js-std\" tests"); @@ -944,28 +955,6 @@ fn get_browser_ui_test_version(npm: &Path) -> Option<String> { .or_else(|| get_browser_ui_test_version_inner(npm, true)) } -fn compare_browser_ui_test_version(installed_version: &str, src: &Path) { - match fs::read_to_string( - src.join("src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version"), - ) { - Ok(v) => { - if v.trim() != installed_version { - eprintln!( - "⚠️ Installed version of browser-ui-test (`{}`) is different than the \ - one used in the CI (`{}`)", - installed_version, v - ); - eprintln!( - "You can install this version using `npm update browser-ui-test` or by using \ - `npm install browser-ui-test@{}`", - v, - ); - } - } - Err(e) => eprintln!("Couldn't find the CI browser-ui-test version: {:?}", e), - } -} - #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct RustdocGUI { pub target: TargetSelection, @@ -997,79 +986,30 @@ impl Step for RustdocGUI { } fn run(self, builder: &Builder<'_>) { - let nodejs = builder.config.nodejs.as_ref().expect("nodejs isn't available"); - let npm = builder.config.npm.as_ref().expect("npm isn't available"); - builder.ensure(compile::Std::new(self.compiler, self.target)); - // The goal here is to check if the necessary packages are installed, and if not, we - // panic. - match get_browser_ui_test_version(&npm) { - Some(version) => { - // We also check the version currently used in CI and emit a warning if it's not the - // same one. - compare_browser_ui_test_version(&version, &builder.build.src); - } - None => { - eprintln!( - "error: rustdoc-gui test suite cannot be run because npm `browser-ui-test` \ - dependency is missing", - ); - eprintln!( - "If you want to install the `{0}` dependency, run `npm install {0}`", - "browser-ui-test", - ); - panic!("Cannot run rustdoc-gui tests"); - } - } + let mut cmd = builder.tool_cmd(Tool::RustdocGUITest); let out_dir = builder.test_out(self.target).join("rustdoc-gui"); - - // We remove existing folder to be sure there won't be artifacts remaining. builder.clear_if_dirty(&out_dir, &builder.rustdoc(self.compiler)); - let src_path = builder.build.src.join("tests/rustdoc-gui/src"); - // We generate docs for the libraries present in the rustdoc-gui's src folder. - for entry in src_path.read_dir().expect("read_dir call failed") { - if let Ok(entry) = entry { - let path = entry.path(); + if let Some(src) = builder.config.src.to_str() { + cmd.arg("--rust-src").arg(src); + } - if !path.is_dir() { - continue; - } + if let Some(out_dir) = out_dir.to_str() { + cmd.arg("--out-dir").arg(out_dir); + } - let mut cargo = Command::new(&builder.initial_cargo); - cargo - .arg("doc") - .arg("--target-dir") - .arg(&out_dir) - .env("RUSTC_BOOTSTRAP", "1") - .env("RUSTDOC", builder.rustdoc(self.compiler)) - .env("RUSTC", builder.rustc(self.compiler)) - .current_dir(path); - // FIXME: implement a `// compile-flags` command or similar - // instead of hard-coding this test - if entry.file_name() == "link_to_definition" { - cargo.env("RUSTDOCFLAGS", "-Zunstable-options --generate-link-to-definition"); - } else if entry.file_name() == "scrape_examples" { - cargo.arg("-Zrustdoc-scrape-examples"); - } else if entry.file_name() == "extend_css" { - cargo.env("RUSTDOCFLAGS", &format!("--extend-css extra.css")); - } - builder.run(&mut cargo); - } + if let Some(initial_cargo) = builder.config.initial_cargo.to_str() { + cmd.arg("--initial-cargo").arg(initial_cargo); } - // We now run GUI tests. - let mut command = Command::new(&nodejs); - command - .arg(builder.build.src.join("src/tools/rustdoc-gui/tester.js")) - .arg("--jobs") - .arg(&builder.jobs().to_string()) - .arg("--doc-folder") - .arg(out_dir.join("doc")) - .arg("--tests-folder") - .arg(builder.build.src.join("tests/rustdoc-gui")); + cmd.arg("--jobs").arg(builder.jobs().to_string()); + + cmd.env("RUSTDOC", builder.rustdoc(self.compiler)) + .env("RUSTC", builder.rustc(self.compiler)); + for path in &builder.paths { if let Some(p) = util::is_valid_test_suite_arg(path, "tests/rustdoc-gui", builder) { if !p.ends_with(".goml") { @@ -1077,14 +1017,25 @@ impl Step for RustdocGUI { panic!("Cannot run rustdoc-gui tests"); } if let Some(name) = path.file_name().and_then(|f| f.to_str()) { - command.arg("--file").arg(name); + cmd.arg("--goml-file").arg(name); } } } + for test_arg in builder.config.test_args() { - command.arg(test_arg); + cmd.arg("--test-arg").arg(test_arg); + } + + if let Some(ref nodejs) = builder.config.nodejs { + cmd.arg("--nodejs").arg(nodejs); + } + + if let Some(ref npm) = builder.config.npm { + cmd.arg("--npm").arg(npm); } - builder.run(&mut command); + + let _time = util::timeit(&builder); + crate::render_tests::try_run_tests(builder, &mut cmd); } } @@ -1134,7 +1085,7 @@ help: to skip test's attempt to check tidiness, pass `--exclude src/tools/tidy` PATH = inferred_rustfmt_dir.display(), CHAN = builder.config.channel, ); - crate::detail_exit(1); + crate::detail_exit_macro!(1); } crate::format::format(&builder, !builder.config.cmd.bless(), &[]); } @@ -1157,7 +1108,7 @@ help: to skip test's attempt to check tidiness, pass `--exclude src/tools/tidy` eprintln!( "x.py completions were changed; run `x.py run generate-completions` to update them" ); - crate::detail_exit(1); + crate::detail_exit_macro!(1); } } } @@ -1378,7 +1329,7 @@ help: to test the compiler, use `--stage 1` instead help: to test the standard library, use `--stage 0 library/std` instead note: if you're sure you want to do this, please open an issue as to why. In the meantime, you can override this with `COMPILETEST_FORCE_STAGE0=1`." ); - crate::detail_exit(1); + crate::detail_exit_macro!(1); } let mut compiler = self.compiler; @@ -1753,12 +1704,21 @@ note: if you're sure you want to do this, please open an issue as to why. In the cmd.arg("--git-hash"); } - if let Some(commit) = builder.config.download_rustc_commit() { - cmd.env("FAKE_DOWNLOAD_RUSTC_PREFIX", format!("/rustc/{commit}")); - } - builder.ci_env.force_coloring_in_ci(&mut cmd); + #[cfg(feature = "build-metrics")] + builder.metrics.begin_test_suite( + crate::metrics::TestSuiteMetadata::Compiletest { + suite: suite.into(), + mode: mode.into(), + compare_mode: None, + target: self.target.triple.to_string(), + host: self.compiler.host.triple.to_string(), + stage: self.compiler.stage, + }, + builder, + ); + builder.info(&format!( "Check compiletest suite={} mode={} ({} -> {})", suite, mode, &compiler.host, target @@ -1768,6 +1728,20 @@ note: if you're sure you want to do this, please open an issue as to why. In the if let Some(compare_mode) = compare_mode { cmd.arg("--compare-mode").arg(compare_mode); + + #[cfg(feature = "build-metrics")] + builder.metrics.begin_test_suite( + crate::metrics::TestSuiteMetadata::Compiletest { + suite: suite.into(), + mode: mode.into(), + compare_mode: Some(compare_mode.into()), + target: self.target.triple.to_string(), + host: self.compiler.host.triple.to_string(), + stage: self.compiler.stage, + }, + builder, + ); + builder.info(&format!( "Check compiletest suite={} mode={} compare_mode={} ({} -> {})", suite, mode, compare_mode, &compiler.host, target @@ -2094,6 +2068,17 @@ fn run_cargo_test( let mut cargo = prepare_cargo_test(cargo, libtest_args, crates, primary_crate, compiler, target, builder); let _time = util::timeit(&builder); + + #[cfg(feature = "build-metrics")] + builder.metrics.begin_test_suite( + crate::metrics::TestSuiteMetadata::CargoPackage { + crates: crates.iter().map(|c| c.to_string()).collect(), + target: target.triple.to_string(), + host: compiler.host.triple.to_string(), + stage: compiler.stage, + }, + builder, + ); add_flags_and_try_run_tests(builder, &mut cargo) } diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index f13d365e375..0f0a3bb8775 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -116,7 +116,7 @@ impl Step for ToolBuild { if !is_expected { if !is_optional_tool { - crate::detail_exit(1); + crate::detail_exit_macro!(1); } else { None } @@ -302,6 +302,7 @@ 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"; ); #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, Ord, PartialOrd)] diff --git a/src/bootstrap/toolstate.rs b/src/bootstrap/toolstate.rs index 7aab88a1a73..9c4d0ea265d 100644 --- a/src/bootstrap/toolstate.rs +++ b/src/bootstrap/toolstate.rs @@ -91,7 +91,7 @@ fn print_error(tool: &str, submodule: &str) { eprintln!("If you do NOT intend to update '{}', please ensure you did not accidentally", tool); eprintln!("change the submodule at '{}'. You may ask your reviewer for the", submodule); eprintln!("proper steps."); - crate::detail_exit(3); + crate::detail_exit_macro!(3); } fn check_changed_files(toolstates: &HashMap<Box<str>, ToolState>) { @@ -106,7 +106,7 @@ fn check_changed_files(toolstates: &HashMap<Box<str>, ToolState>) { Ok(o) => o, Err(e) => { eprintln!("Failed to get changed files: {:?}", e); - crate::detail_exit(1); + crate::detail_exit_macro!(1); } }; @@ -177,7 +177,7 @@ impl Step for ToolStateCheck { } if did_error { - crate::detail_exit(1); + crate::detail_exit_macro!(1); } check_changed_files(&toolstates); @@ -223,7 +223,7 @@ impl Step for ToolStateCheck { } if did_error { - crate::detail_exit(1); + crate::detail_exit_macro!(1); } if builder.config.channel == "nightly" && env::var_os("TOOLSTATE_PUBLISH").is_some() { diff --git a/src/bootstrap/util.rs b/src/bootstrap/util.rs index 2e1adbf63bb..e4bbccdb067 100644 --- a/src/bootstrap/util.rs +++ b/src/bootstrap/util.rs @@ -3,6 +3,7 @@ //! Simple things like testing the various filesystem operations here and there, //! not a lot of interesting happenings here unfortunately. +use build_helper::util::{fail, try_run}; use std::env; use std::fs; use std::io; @@ -230,25 +231,10 @@ pub fn is_valid_test_suite_arg<'a, P: AsRef<Path>>( pub fn run(cmd: &mut Command, print_cmd_on_fail: bool) { if !try_run(cmd, print_cmd_on_fail) { - crate::detail_exit(1); + crate::detail_exit_macro!(1); } } -pub fn try_run(cmd: &mut Command, print_cmd_on_fail: bool) -> bool { - let status = match cmd.status() { - Ok(status) => status, - Err(e) => fail(&format!("failed to execute command: {:?}\nerror: {}", cmd, e)), - }; - if !status.success() && print_cmd_on_fail { - println!( - "\n\ncommand did not execute successfully: {:?}\n\ - expected success, got: {}\n\n", - cmd, status - ); - } - status.success() -} - pub fn check_run(cmd: &mut Command, print_cmd_on_fail: bool) -> bool { let status = match cmd.status() { Ok(status) => status, @@ -269,7 +255,7 @@ pub fn check_run(cmd: &mut Command, print_cmd_on_fail: bool) -> bool { pub fn run_suppressed(cmd: &mut Command) { if !try_run_suppressed(cmd) { - crate::detail_exit(1); + crate::detail_exit_macro!(1); } } @@ -374,11 +360,6 @@ fn dir_up_to_date(src: &Path, threshold: SystemTime) -> bool { }) } -fn fail(s: &str) -> ! { - eprintln!("\n\n{}\n\n", s); - crate::detail_exit(1); -} - /// Copied from `std::path::absolute` until it stabilizes. /// /// FIXME: this shouldn't exist. @@ -488,7 +469,7 @@ fn absolute_windows(path: &std::path::Path) -> std::io::Result<std::path::PathBu } } -/// Adapted from https://github.com/llvm/llvm-project/blob/782e91224601e461c019e0a4573bbccc6094fbcd/llvm/cmake/modules/HandleLLVMOptions.cmake#L1058-L1079 +/// Adapted from <https://github.com/llvm/llvm-project/blob/782e91224601e461c019e0a4573bbccc6094fbcd/llvm/cmake/modules/HandleLLVMOptions.cmake#L1058-L1079> /// /// When `clang-cl` is used with instrumentation, we need to add clang's runtime library resource /// directory to the linker flags, otherwise there will be linker errors about the profiler runtime diff --git a/src/ci/docker/host-x86_64/test-various/uefi_qemu_test/Cargo.toml b/src/ci/docker/host-x86_64/test-various/uefi_qemu_test/Cargo.toml index fa8e5b3d080..2d17cf7d47a 100644 --- a/src/ci/docker/host-x86_64/test-various/uefi_qemu_test/Cargo.toml +++ b/src/ci/docker/host-x86_64/test-various/uefi_qemu_test/Cargo.toml @@ -4,6 +4,7 @@ version = "0.0.0" edition = "2021" [workspace] +resolver = "1" [dependencies] r-efi = "4.1.0" diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version index 806935b827f..3ccca1e8b89 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version +++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version @@ -1 +1 @@ -0.16.4 \ No newline at end of file +0.16.5 \ No newline at end of file diff --git a/src/doc/rustc/src/exploit-mitigations.md b/src/doc/rustc/src/exploit-mitigations.md index a82a53248d4..172048704f4 100644 --- a/src/doc/rustc/src/exploit-mitigations.md +++ b/src/doc/rustc/src/exploit-mitigations.md @@ -55,88 +55,18 @@ Table I \ Summary of exploit mitigations supported by the Rust compiler when building programs for the Linux operating system on the AMD64 architecture and equivalent. -<table class="table"> - <tr> - <td><strong>Exploit mitigation</strong> - </td> - <td><strong>Supported and enabled by default</strong> - </td> - <td><strong>Since</strong> - </td> - </tr> - <tr> - <td>Position-independent executable - </td> - <td>Yes - </td> - <td>0.12.0 (2014-10-09) - </td> - </tr> - <tr> - <td>Integer overflow checks - </td> - <td>Yes (enabled when debug assertions are enabled, and disabled when debug assertions are disabled) - </td> - <td>1.1.0 (2015-06-25) - </td> - </tr> - <tr> - <td>Non-executable memory regions - </td> - <td>Yes - </td> - <td>1.8.0 (2016-04-14) - </td> - </tr> - <tr> - <td>Stack clashing protection - </td> - <td>Yes - </td> - <td>1.20.0 (2017-08-31) - </td> - </tr> - <tr> - <td>Read-only relocations and immediate binding - </td> - <td>Yes - </td> - <td>1.21.0 (2017-10-12) - </td> - </tr> - <tr> - <td>Heap corruption protection - </td> - <td>Yes - </td> - <td>1.32.0 (2019-01-17) (via operating system default or specified allocator) - </td> - </tr> - <tr> - <td>Stack smashing protection - </td> - <td>Yes - </td> - <td>Nightly - </td> - </tr> - <tr> - <td>Forward-edge control flow protection - </td> - <td>Yes - </td> - <td>Nightly - </td> - </tr> - <tr> - <td>Backward-edge control flow protection (e.g., shadow and safe stack) - </td> - <td>No - </td> - <td> - </td> - </tr> -</table> + +| Exploit mitigation | Supported and enabled by default | Since | +| - | - | - | +| Position-independent executable | Yes | 0.12.0 (2014-10-09) | +| Integer overflow checks | Yes (enabled when debug assertions are enabled, and disabled when debug assertions are disabled) | 1.1.0 (2015-06-25) | +| Non-executable memory regions | Yes | 1.8.0 (2016-04-14) | +| Stack clashing protection | Yes | 1.20.0 (2017-08-31) | +| Read-only relocations and immediate binding | Yes | 1.21.0 (2017-10-12) | +| Heap corruption protection | Yes | 1.32.0 (2019-01-17) (via operating system default or specified allocator) | +| Stack smashing protection | Yes | Nightly | +| Forward-edge control flow protection | Yes | Nightly | +| Backward-edge control flow protection (e.g., shadow and safe stack) | Yes | Nightly | <small id="fn:1">1\. See <https://github.com/rust-lang/rust/tree/master/compiler/rustc_target/src/spec> @@ -513,20 +443,21 @@ Newer processors provide hardware assistance for backward-edge control flow protection, such as ARM Pointer Authentication, and Intel Shadow Stack as part of Intel CET. -The Rust compiler does not support shadow or safe stack. There is work -currently ongoing to add support for the sanitizers[40], which may or may -not include support for safe stack<sup id="fnref:7" role="doc-noteref"><a -href="#fn:7" class="footnote">7</a></sup>. +The Rust compiler supports shadow stack for aarch64 only +<sup id="fnref:7" role="doc-noteref"><a href="#fn:7" class="footnote">7</a></sup> +on nightly Rust compilers [43]-[44]. Safe stack is available on nightly +Rust compilers [45]-[46]. ```text $ readelf -s target/release/hello-rust | grep __safestack_init + 1177: 00000000000057b0 444 FUNC GLOBAL DEFAULT 9 __safestack_init ``` Fig. 16. Checking if LLVM SafeStack is enabled for a given binary. The presence of the `__safestack_init` symbol indicates that LLVM SafeStack -is enabled for a given binary. Conversely, the absence of the +is enabled for a given binary (see Fig. 16). Conversely, the absence of the `__safestack_init` symbol indicates that LLVM SafeStack is not enabled for a -given binary (see Fig. 16). +given binary. <small id="fn:7">7\. The shadow stack implementation for the AMD64 architecture and equivalent in LLVM was removed due to performance and @@ -698,3 +629,15 @@ defaults (unrelated to `READ_IMPLIES_EXEC`). 42. bbjornse. “add codegen option for using LLVM stack smash protection #84197.” GitHub. <https://github.com/rust-lang/rust/pull/84197> + +43. ivanloz. “Add support for LLVM ShadowCallStack. #98208.” GitHub. + <https://github.com/rust-lang/rust/pull/98208>. + +44. “ShadowCallStack.” The Rust Unstable Book. + [https://doc.rust-lang.org/unstable-book/compiler-flags/sanitizer.html#shadowcallstack](../unstable-book/compiler-flags/sanitizer.html#shadowcallstack). + +45. W. Wiser. “Add support for LLVM SafeStack #112000” GitHub. + <https://github.com/rust-lang/rust/pull/112000> + +46. “SafeStack.” The Rust Unstable Book. + [https://doc.rust-lang/org/unstable-book/compiler-flags/sanitizer.html#safestack](../unstable-book/compiler-flags/sanitizer.html#safestack). diff --git a/src/doc/unstable-book/src/compiler-flags/sanitizer.md b/src/doc/unstable-book/src/compiler-flags/sanitizer.md index aa776daf09d..49389b28c8f 100644 --- a/src/doc/unstable-book/src/compiler-flags/sanitizer.md +++ b/src/doc/unstable-book/src/compiler-flags/sanitizer.md @@ -21,7 +21,8 @@ This feature allows for use of one of following sanitizers: * [MemorySanitizer](#memorysanitizer) a detector of uninitialized reads. * [MemTagSanitizer](#memtagsanitizer) fast memory error detector based on Armv8.5-A Memory Tagging Extension. -* [ShadowCallStack](#shadowcallstack) provides backward-edge control flow protection. +* [SafeStack](#safestack) provides backward-edge control flow protection by separating the stack into safe and unsafe regions. +* [ShadowCallStack](#shadowcallstack) provides backward-edge control flow protection (aarch64 only). * [ThreadSanitizer](#threadsanitizer) a fast data race detector. To enable a sanitizer compile with `-Zsanitizer=address`,`-Zsanitizer=cfi`, @@ -712,6 +713,16 @@ To enable this target feature compile with `-C target-feature="+mte"`. See the [LLVM MemTagSanitizer documentation][llvm-memtag] for more details. +# SafeStack + +SafeStack provides backward edge control flow protection by separating the stack into data which is only accessed safely (the safe stack) and all other data (the unsafe stack). + +SafeStack can be enabled with the `-Zsanitizer=safestack` option and is supported on the following targets: + +* `x86_64-unknown-linux-gnu` + +See the [Clang SafeStack documentation][clang-safestack] for more details. + # ShadowCallStack ShadowCallStack provides backward edge control flow protection by storing a function's return address in a separately allocated 'shadow call stack' and loading the return address from that shadow call stack. @@ -828,6 +839,7 @@ Sanitizers produce symbolized stacktraces when llvm-symbolizer binary is in `PAT [clang-kcfi]: https://clang.llvm.org/docs/ControlFlowIntegrity.html#fsanitize-kcfi [clang-lsan]: https://clang.llvm.org/docs/LeakSanitizer.html [clang-msan]: https://clang.llvm.org/docs/MemorySanitizer.html +[clang-safestack]: https://clang.llvm.org/docs/SafeStack.html [clang-scs]: https://clang.llvm.org/docs/ShadowCallStack.html [clang-tsan]: https://clang.llvm.org/docs/ThreadSanitizer.html [linux-kasan]: https://www.kernel.org/doc/html/latest/dev-tools/kasan.html diff --git a/src/doc/unstable-book/src/language-features/asm-experimental-arch.md b/src/doc/unstable-book/src/language-features/asm-experimental-arch.md index 532cb9eea11..c634dc50d6d 100644 --- a/src/doc/unstable-book/src/language-features/asm-experimental-arch.md +++ b/src/doc/unstable-book/src/language-features/asm-experimental-arch.md @@ -17,7 +17,6 @@ This feature tracks `asm!` and `global_asm!` support for the following architect - AVR - MSP430 - M68k -- LoongArch - s390x ## Register classes @@ -47,8 +46,6 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | M68k | `reg` | `d[0-7]`, `a[0-7]` | `r` | | M68k | `reg_data` | `d[0-7]` | `d` | | M68k | `reg_addr` | `a[0-3]` | `a` | -| LoongArch | `reg` | `$r1`, `$r[4-20]`, `$r[23,30]` | `r` | -| LoongArch | `freg` | `$f[0-31]` | `f` | | s390x | `reg` | `r[0-10]`, `r[12-14]` | `r` | | s390x | `freg` | `f[0-15]` | `f` | @@ -82,8 +79,6 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | MSP430 | `reg` | None | `i8`, `i16` | | M68k | `reg`, `reg_addr` | None | `i16`, `i32` | | M68k | `reg_data` | None | `i8`, `i16`, `i32` | -| LoongArch64 | `reg` | None | `i8`, `i16`, `i32`, `i64`, `f32`, `f64` | -| LoongArch64 | `freg` | None | `f32`, `f64` | | s390x | `reg` | None | `i8`, `i16`, `i32`, `i64` | | s390x | `freg` | None | `f32`, `f64` | @@ -107,10 +102,6 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | M68k | `a5` | `bp` | | M68k | `a6` | `fp` | | M68k | `a7` | `sp`, `usp`, `ssp`, `isp` | -| LoongArch | `$r0` | `zero` | -| LoongArch | `$r2` | `tp` | -| LoongArch | `$r3` | `sp` | -| LoongArch | `$r22` | `fp` | > **Notes**: > - TI does not mandate a frame pointer for MSP430, but toolchains are allowed @@ -121,7 +112,7 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | Architecture | Unsupported register | Reason | | ------------ | --------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | All | `sp`, `r15` (s390x) | The stack pointer must be restored to its original value at the end of an asm code block. | -| All | `fr` (Hexagon), `$fp` (MIPS), `Y` (AVR), `r4` (MSP430), `a6` (M68k), `$fp` (LoongArch), `r11` (s390x) | The frame pointer cannot be used as an input or output. | +| All | `fr` (Hexagon), `$fp` (MIPS), `Y` (AVR), `r4` (MSP430), `a6` (M68k), `r11` (s390x) | The frame pointer cannot be used as an input or output. | | All | `r19` (Hexagon) | This is used internally by LLVM as a "base pointer" for functions with complex stack frames. | | MIPS | `$0` or `$zero` | This is a constant zero register which can't be modified. | | MIPS | `$1` or `$at` | Reserved for assembler. | @@ -132,10 +123,6 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | AVR | `r0`, `r1`, `r1r0` | Due to an issue in LLVM, the `r0` and `r1` registers cannot be used as inputs or outputs. If modified, they must be restored to their original values before the end of the block. | |MSP430 | `r0`, `r2`, `r3` | These are the program counter, status register, and constant generator respectively. Neither the status register nor constant generator can be written to. | | M68k | `a4`, `a5` | Used internally by LLVM for the base pointer and global base pointer. | -| LoongArch | `$r0` or `$zero` | This is a constant zero register which can't be modified. | -| LoongArch | `$r2` or `$tp` | This is reserved for TLS. | -| LoongArch | `$r21` | This is reserved by the ABI. | -| LoongArch | `$r31` or `$s8` | This is used internally by LLVM. | ## Template modifiers @@ -150,8 +137,6 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | PowerPC | `reg` | None | `0` | None | | PowerPC | `reg_nonzero` | None | `3` | `b` | | PowerPC | `freg` | None | `0` | None | -| LoongArch | `reg` | None | `$r2` | None | -| LoongArch | `freg` | None | `$f0` | None | | s390x | `reg` | None | `%r0` | None | | s390x | `freg` | None | `%f0` | None | diff --git a/src/etc/test-float-parse/Cargo.toml b/src/etc/test-float-parse/Cargo.toml index 7ee19a0b6d9..6d7b227d0ad 100644 --- a/src/etc/test-float-parse/Cargo.toml +++ b/src/etc/test-float-parse/Cargo.toml @@ -5,6 +5,7 @@ edition = "2021" publish = false [workspace] +resolver = "1" [dependencies] rand = "0.4" diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs index e4c05b57378..83887cc44b9 100644 --- a/src/librustdoc/clean/blanket_impl.rs +++ b/src/librustdoc/clean/blanket_impl.rs @@ -21,7 +21,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { let mut impls = Vec::new(); for trait_def_id in cx.tcx.all_traits() { if !cx.cache.effective_visibilities.is_reachable(cx.tcx, trait_def_id) - || cx.generated_synthetics.get(&(ty.0, trait_def_id)).is_some() + || cx.generated_synthetics.get(&(ty.skip_binder(), trait_def_id)).is_some() { continue; } @@ -34,13 +34,13 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { impl_def_id ); let trait_ref = cx.tcx.impl_trait_ref(impl_def_id).unwrap(); - if !matches!(trait_ref.0.self_ty().kind(), ty::Param(_)) { + if !matches!(trait_ref.skip_binder().self_ty().kind(), ty::Param(_)) { continue; } let infcx = cx.tcx.infer_ctxt().build(); let substs = infcx.fresh_substs_for_item(DUMMY_SP, item_def_id); let impl_ty = ty.subst(infcx.tcx, substs); - let param_env = EarlyBinder(param_env).subst(infcx.tcx, substs); + let param_env = EarlyBinder::bind(param_env).subst(infcx.tcx, substs); let impl_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id); let impl_trait_ref = trait_ref.subst(infcx.tcx, impl_substs); @@ -87,7 +87,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { trait_ref, ty ); - cx.generated_synthetics.insert((ty.0, trait_def_id)); + cx.generated_synthetics.insert((ty.skip_binder(), trait_def_id)); impls.push(Item { name: None, @@ -104,10 +104,10 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { // the post-inference `trait_ref`, as it's more accurate. trait_: Some(clean_trait_ref_with_bindings( cx, - ty::Binder::dummy(trait_ref.0), + ty::Binder::dummy(trait_ref.skip_binder()), ThinVec::new(), )), - for_: clean_middle_ty(ty::Binder::dummy(ty.0), cx, None), + for_: clean_middle_ty(ty::Binder::dummy(ty.skip_binder()), cx, None), items: cx .tcx .associated_items(impl_def_id) @@ -116,7 +116,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { .collect::<Vec<_>>(), polarity: ty::ImplPolarity::Positive, kind: ImplKind::Blanket(Box::new(clean_middle_ty( - ty::Binder::dummy(trait_ref.0.self_ty()), + ty::Binder::dummy(trait_ref.skip_binder().self_ty()), cx, None, ))), diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index c852f9cca2b..7dc08b3b1ff 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -355,9 +355,9 @@ pub(crate) fn build_impl( return; } - let _prof_timer = cx.tcx.sess.prof.generic_activity("build_impl"); - let tcx = cx.tcx; + let _prof_timer = tcx.sess.prof.generic_activity("build_impl"); + let associated_trait = tcx.impl_trait_ref(did).map(ty::EarlyBinder::skip_binder); // Only inline impl if the implemented trait is diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 59a3e631724..5fd867189fd 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1111,8 +1111,8 @@ fn clean_fn_decl_with_args<'tcx>( args: Arguments, ) -> FnDecl { let output = match decl.output { - hir::FnRetTy::Return(typ) => Return(clean_ty(typ, cx)), - hir::FnRetTy::DefaultReturn(..) => DefaultReturn, + hir::FnRetTy::Return(typ) => clean_ty(typ, cx), + hir::FnRetTy::DefaultReturn(..) => Type::Tuple(Vec::new()), }; FnDecl { inputs: args, output, c_variadic: decl.c_variadic } } @@ -1126,10 +1126,7 @@ fn clean_fn_decl_from_did_and_sig<'tcx>( // We assume all empty tuples are default return type. This theoretically can discard `-> ()`, // but shouldn't change any code meaning. - let output = match clean_middle_ty(sig.output(), cx, None) { - Type::Tuple(inner) if inner.is_empty() => DefaultReturn, - ty => Return(ty), - }; + let output = clean_middle_ty(sig.output(), cx, None); FnDecl { output, @@ -2592,7 +2589,8 @@ fn clean_use_statement_inner<'tcx>( } else { if inline_attr.is_none() && let Res::Def(DefKind::Mod, did) = path.res - && !did.is_local() && did.is_crate_root() + && !did.is_local() + && did.is_crate_root() { // if we're `pub use`ing an extern crate root, don't inline it unless we // were specifically asked for it diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index e9ccea2cf27..1999a6b671d 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -42,7 +42,6 @@ use crate::formats::item_type::ItemType; use crate::html::render::Context; use crate::passes::collect_intra_doc_links::UrlFragment; -pub(crate) use self::FnRetTy::*; pub(crate) use self::ItemKind::*; pub(crate) use self::SelfTy::*; pub(crate) use self::Type::{ @@ -1353,7 +1352,7 @@ pub(crate) struct Function { #[derive(Clone, PartialEq, Eq, Debug, Hash)] pub(crate) struct FnDecl { pub(crate) inputs: Arguments, - pub(crate) output: FnRetTy, + pub(crate) output: Type, pub(crate) c_variadic: bool, } @@ -1371,18 +1370,16 @@ impl FnDecl { /// /// This function will panic if the return type does not match the expected sugaring for async /// functions. - pub(crate) fn sugared_async_return_type(&self) -> FnRetTy { - match &self.output { - FnRetTy::Return(Type::ImplTrait(bounds)) => match &bounds[0] { - GenericBound::TraitBound(PolyTrait { trait_, .. }, ..) => { - let bindings = trait_.bindings().unwrap(); - let ret_ty = bindings[0].term(); - let ty = ret_ty.ty().expect("Unexpected constant return term"); - FnRetTy::Return(ty.clone()) - } - _ => panic!("unexpected desugaring of async function"), - }, - _ => panic!("unexpected desugaring of async function"), + pub(crate) fn sugared_async_return_type(&self) -> Type { + if let Type::ImplTrait(v) = &self.output && + let [GenericBound::TraitBound(PolyTrait { trait_, .. }, _ )] = &v[..] + { + let bindings = trait_.bindings().unwrap(); + let ret_ty = bindings[0].term(); + let ty = ret_ty.ty().expect("Unexpected constant return term"); + ty.clone() + } else { + panic!("unexpected desugaring of async function") } } } @@ -1425,21 +1422,6 @@ impl Argument { } } -#[derive(Clone, PartialEq, Eq, Debug, Hash)] -pub(crate) enum FnRetTy { - Return(Type), - DefaultReturn, -} - -impl FnRetTy { - pub(crate) fn as_return(&self) -> Option<&Type> { - match self { - Return(ret) => Some(ret), - DefaultReturn => None, - } - } -} - #[derive(Clone, Debug)] pub(crate) struct Trait { pub(crate) def_id: DefId, @@ -1641,6 +1623,10 @@ impl Type { matches!(self, Type::ImplTrait(_)) } + pub(crate) fn is_unit(&self) -> bool { + matches!(self, Type::Tuple(v) if v.is_empty()) + } + pub(crate) fn projection(&self) -> Option<(&Type, DefId, PathSegment)> { if let QPath(box QPathData { self_type, trait_, assoc, .. }) = self { Some((self_type, trait_.as_ref()?.def_id(), assoc.clone())) diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index 17aa6b38e38..366f9395296 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -193,7 +193,7 @@ pub(crate) fn build_deref_target_impls( }; if let Some(prim) = target.primitive_type() { - let _prof_timer = cx.tcx.sess.prof.generic_activity("build_primitive_inherent_impls"); + let _prof_timer = tcx.sess.prof.generic_activity("build_primitive_inherent_impls"); for did in prim.impls(tcx).filter(|did| !did.is_local()) { inline::build_impl(cx, did, None, ret); } diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index dfa4b091b01..9f08609a6d1 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -314,7 +314,6 @@ impl Options { matches: &getopts::Matches, args: Vec<String>, ) -> Result<(Options, RenderOptions), i32> { - let args = &args[1..]; // Check for unstable options. nightly_options::check_nightly_options(matches, &opts()); diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index c4758fd9866..8aaad8bce1b 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -147,7 +147,7 @@ impl Cache { // Cache where all our extern crates are located // FIXME: this part is specific to HTML so it'd be nice to remove it from the common code - for &crate_num in cx.tcx.crates(()) { + for &crate_num in tcx.crates(()) { let e = ExternalCrate { crate_num }; let name = e.name(tcx); diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index d963d6092c4..f26d74629dd 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -1257,9 +1257,9 @@ impl clean::Impl { }; primitive_link_fragment(f, PrimitiveType::Tuple, &format!("fn ({name}₁, {name}₂, …, {name}ₙ{ellipsis})"), "#trait-implementations-1", cx)?; // Write output. - if let clean::FnRetTy::Return(ty) = &bare_fn.decl.output { + if !bare_fn.decl.output.is_unit() { write!(f, " -> ")?; - fmt_type(ty, f, use_absolute, cx)?; + fmt_type(&bare_fn.decl.output, f, use_absolute, cx)?; } } else if let Some(ty) = self.kind.as_blanket_ty() { fmt_type(ty, f, use_absolute, cx)?; @@ -1296,22 +1296,6 @@ impl clean::Arguments { } } -impl clean::FnRetTy { - pub(crate) fn print<'a, 'tcx: 'a>( - &'a self, - cx: &'a Context<'tcx>, - ) -> impl fmt::Display + 'a + Captures<'tcx> { - display_fn(move |f| match self { - clean::Return(clean::Tuple(tys)) if tys.is_empty() => Ok(()), - clean::Return(ty) if f.alternate() => { - write!(f, " -> {:#}", ty.print(cx)) - } - clean::Return(ty) => write!(f, " -> {}", ty.print(cx)), - clean::DefaultReturn => Ok(()), - }) - } -} - impl clean::BareFunctionDecl { fn print_hrtb_with_space<'a, 'tcx: 'a>( &'a self, @@ -1366,7 +1350,7 @@ impl clean::FnDecl { "({args:#}{ellipsis}){arrow:#}", args = self.inputs.print(cx), ellipsis = ellipsis, - arrow = self.output.print(cx) + arrow = self.print_output(cx) ) } else { write!( @@ -1374,7 +1358,7 @@ impl clean::FnDecl { "({args}{ellipsis}){arrow}", args = self.inputs.print(cx), ellipsis = ellipsis, - arrow = self.output.print(cx) + arrow = self.print_output(cx) ) } }) @@ -1464,9 +1448,22 @@ impl clean::FnDecl { Some(n) => write!(f, "\n{})", Indent(n))?, }; - fmt::Display::fmt(&self.output.print(cx), f)?; + fmt::Display::fmt(&self.print_output(cx), f)?; Ok(()) } + + pub(crate) fn print_output<'a, 'tcx: 'a>( + &'a self, + cx: &'a Context<'tcx>, + ) -> impl fmt::Display + 'a + Captures<'tcx> { + display_fn(move |f| match &self.output { + clean::Tuple(tys) if tys.is_empty() => Ok(()), + ty if f.alternate() => { + write!(f, " -> {:#}", ty.print(cx)) + } + ty => write!(f, " -> {}", ty.print(cx)), + }) + } } pub(crate) fn visibility_print_with_space<'a, 'tcx: 'a>( diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 09e7ed293d4..b26a5c32ec6 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -781,7 +781,7 @@ impl<'tcx> ExtraInfo<'tcx> { ExtraInfo { def_id, sp, tcx } } - fn error_invalid_codeblock_attr(&self, msg: String, help: &str) { + fn error_invalid_codeblock_attr(&self, msg: String, help: &'static str) { if let Some(def_id) = self.def_id.as_local() { self.tcx.struct_span_lint_hir( crate::lint::INVALID_CODEBLOCK_ATTRIBUTES, @@ -1237,7 +1237,27 @@ pub(crate) fn plain_text_summary(md: &str, link_names: &[RenderedLink]) -> Strin pub(crate) struct MarkdownLink { pub kind: LinkType, pub link: String, - pub range: Range<usize>, + pub range: MarkdownLinkRange, +} + +#[derive(Clone, Debug)] +pub(crate) enum MarkdownLinkRange { + /// Normally, markdown link warnings point only at the destination. + Destination(Range<usize>), + /// In some cases, it's not possible to point at the destination. + /// Usually, this happens because backslashes `\\` are used. + /// When that happens, point at the whole link, and don't provide structured suggestions. + WholeLink(Range<usize>), +} + +impl MarkdownLinkRange { + /// Extracts the inner range. + pub fn inner_range(&self) -> &Range<usize> { + match self { + MarkdownLinkRange::Destination(range) => range, + MarkdownLinkRange::WholeLink(range) => range, + } + } } pub(crate) fn markdown_links<R>( @@ -1257,9 +1277,9 @@ pub(crate) fn markdown_links<R>( if md_start <= s_start && s_end <= md_end { let start = s_start.offset_from(md_start) as usize; let end = s_end.offset_from(md_start) as usize; - start..end + MarkdownLinkRange::Destination(start..end) } else { - fallback + MarkdownLinkRange::WholeLink(fallback) } }; @@ -1267,6 +1287,7 @@ pub(crate) fn markdown_links<R>( // For diagnostics, we want to underline the link's definition but `span` will point at // where the link is used. This is a problem for reference-style links, where the definition // is separate from the usage. + match link { // `Borrowed` variant means the string (the link's destination) may come directly from // the markdown text and we can locate the original link destination. @@ -1275,8 +1296,80 @@ pub(crate) fn markdown_links<R>( CowStr::Borrowed(s) => locate(s, span), // For anything else, we can only use the provided range. - CowStr::Boxed(_) | CowStr::Inlined(_) => span, + CowStr::Boxed(_) | CowStr::Inlined(_) => MarkdownLinkRange::WholeLink(span), + } + }; + + let span_for_offset_backward = |span: Range<usize>, open: u8, close: u8| { + let mut open_brace = !0; + let mut close_brace = !0; + for (i, b) in md.as_bytes()[span.clone()].iter().copied().enumerate().rev() { + let i = i + span.start; + if b == close { + close_brace = i; + break; + } + } + if close_brace < span.start || close_brace >= span.end { + return MarkdownLinkRange::WholeLink(span); + } + let mut nesting = 1; + for (i, b) in md.as_bytes()[span.start..close_brace].iter().copied().enumerate().rev() { + let i = i + span.start; + if b == close { + nesting += 1; + } + if b == open { + nesting -= 1; + } + if nesting == 0 { + open_brace = i; + break; + } + } + assert!(open_brace != close_brace); + if open_brace < span.start || open_brace >= span.end { + return MarkdownLinkRange::WholeLink(span); + } + // do not actually include braces in the span + let range = (open_brace + 1)..close_brace; + MarkdownLinkRange::Destination(range.clone()) + }; + + let span_for_offset_forward = |span: Range<usize>, open: u8, close: u8| { + let mut open_brace = !0; + let mut close_brace = !0; + for (i, b) in md.as_bytes()[span.clone()].iter().copied().enumerate() { + let i = i + span.start; + if b == open { + open_brace = i; + break; + } + } + if open_brace < span.start || open_brace >= span.end { + return MarkdownLinkRange::WholeLink(span); } + let mut nesting = 0; + for (i, b) in md.as_bytes()[open_brace..span.end].iter().copied().enumerate() { + let i = i + open_brace; + if b == close { + nesting -= 1; + } + if b == open { + nesting += 1; + } + if nesting == 0 { + close_brace = i; + break; + } + } + assert!(open_brace != close_brace); + if open_brace < span.start || open_brace >= span.end { + return MarkdownLinkRange::WholeLink(span); + } + // do not actually include braces in the span + let range = (open_brace + 1)..close_brace; + MarkdownLinkRange::Destination(range.clone()) }; Parser::new_with_broken_link_callback( @@ -1287,11 +1380,20 @@ pub(crate) fn markdown_links<R>( .into_offset_iter() .filter_map(|(event, span)| match event { Event::Start(Tag::Link(link_type, dest, _)) if may_be_doc_link(link_type) => { - preprocess_link(MarkdownLink { - kind: link_type, - range: span_for_link(&dest, span), - link: dest.into_string(), - }) + let range = match link_type { + // Link is pulled from the link itself. + LinkType::ReferenceUnknown | LinkType::ShortcutUnknown => { + span_for_offset_backward(span, b'[', b']') + } + LinkType::CollapsedUnknown => span_for_offset_forward(span, b'[', b']'), + LinkType::Inline => span_for_offset_backward(span, b'(', b')'), + // Link is pulled from elsewhere in the document. + LinkType::Reference | LinkType::Collapsed | LinkType::Shortcut => { + span_for_link(&dest, span) + } + LinkType::Autolink | LinkType::Email => unreachable!(), + }; + preprocess_link(MarkdownLink { kind: link_type, range, link: dest.into_string() }) } _ => None, }) diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 42e27d35a94..a5223bd6309 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -844,7 +844,7 @@ fn assoc_method( + name.as_str().len() + generics_len; - let notable_traits = d.output.as_return().and_then(|output| notable_traits_button(output, cx)); + let notable_traits = notable_traits_button(&d.output, cx); let (indent, indent_str, end_newline) = if parent == ItemType::Trait { header_len += 4; @@ -1282,6 +1282,11 @@ fn should_render_item(item: &clean::Item, deref_mut_: bool, tcx: TyCtxt<'_>) -> pub(crate) fn notable_traits_button(ty: &clean::Type, cx: &mut Context<'_>) -> Option<String> { let mut has_notable_trait = false; + if ty.is_unit() { + // Very common fast path. + return None; + } + let did = ty.def_id(cx.cache())?; // Box has pass-through impls for Read, Write, Iterator, and Future when the diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 76c8e0885a0..21f61acb2c5 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -9,6 +9,8 @@ use rustc_middle::middle::stability; use rustc_middle::ty::{self, TyCtxt}; use rustc_span::hygiene::MacroKind; use rustc_span::symbol::{kw, sym, Symbol}; +use std::borrow::Borrow; +use std::cell::{RefCell, RefMut}; use std::cmp::Ordering; use std::fmt; use std::rc::Rc; @@ -216,6 +218,53 @@ fn toggle_close(mut w: impl fmt::Write) { w.write_str("</details>").unwrap(); } +trait ItemTemplate<'a, 'cx: 'a>: askama::Template + fmt::Display { + fn item_and_mut_cx(&self) -> (&'a clean::Item, RefMut<'_, &'a mut Context<'cx>>); +} + +fn item_template_document<'a: 'b, 'b, 'cx: 'a>( + templ: &'b impl ItemTemplate<'a, 'cx>, +) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> { + display_fn(move |f| { + let (item, mut cx) = templ.item_and_mut_cx(); + let v = document(*cx, item, None, HeadingOffset::H2); + write!(f, "{v}") + }) +} + +fn item_template_document_type_layout<'a: 'b, 'b, 'cx: 'a>( + templ: &'b impl ItemTemplate<'a, 'cx>, +) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> { + display_fn(move |f| { + let (item, cx) = templ.item_and_mut_cx(); + let def_id = item.item_id.expect_def_id(); + let v = document_type_layout(*cx, def_id); + write!(f, "{v}") + }) +} + +fn item_template_render_attributes_in_pre<'a: 'b, 'b, 'cx: 'a>( + templ: &'b impl ItemTemplate<'a, 'cx>, +) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> { + display_fn(move |f| { + let (item, cx) = templ.item_and_mut_cx(); + let tcx = cx.tcx(); + let v = render_attributes_in_pre(item, "", tcx); + write!(f, "{v}") + }) +} + +fn item_template_render_assoc_items<'a: 'b, 'b, 'cx: 'a>( + templ: &'b impl ItemTemplate<'a, 'cx>, +) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> { + display_fn(move |f| { + let (item, mut cx) = templ.item_and_mut_cx(); + let def_id = item.item_id.expect_def_id(); + let v = render_assoc_items(*cx, item, def_id, AssocItemRender::All); + write!(f, "{v}") + }) +} + fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items: &[clean::Item]) { write!(w, "{}", document(cx, item, None, HeadingOffset::H2)); @@ -356,18 +405,18 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items: clean::ImportItem(ref import) => { let stab_tags = if let Some(import_def_id) = import.source.did { - let ast_attrs = cx.tcx().get_attrs_unchecked(import_def_id); + let ast_attrs = tcx.get_attrs_unchecked(import_def_id); let import_attrs = Box::new(clean::Attributes::from_ast(ast_attrs)); // Just need an item with the correct def_id and attrs let import_item = clean::Item { item_id: import_def_id.into(), attrs: import_attrs, - cfg: ast_attrs.cfg(cx.tcx(), &cx.cache().hidden_cfg), + cfg: ast_attrs.cfg(tcx, &cx.cache().hidden_cfg), ..myitem.clone() }; - let stab_tags = Some(extra_info_tags(&import_item, item, cx.tcx()).to_string()); + let stab_tags = Some(extra_info_tags(&import_item, item, tcx).to_string()); stab_tags } else { None @@ -405,8 +454,7 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items: let unsafety_flag = match *myitem.kind { clean::FunctionItem(_) | clean::ForeignFunctionItem(_) - if myitem.fn_header(cx.tcx()).unwrap().unsafety - == hir::Unsafety::Unsafe => + if myitem.fn_header(tcx).unwrap().unsafety == hir::Unsafety::Unsafe => { "<sup title=\"unsafe function\">⚠</sup>" } @@ -439,7 +487,7 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items: {docs_before}{docs}{docs_after}", name = myitem.name.unwrap(), visibility_emoji = visibility_emoji, - stab_tags = extra_info_tags(myitem, item, cx.tcx()), + stab_tags = extra_info_tags(myitem, item, tcx), class = myitem.type_(), unsafety_flag = unsafety_flag, href = item_path(myitem.type_(), myitem.name.unwrap().as_str()), @@ -539,8 +587,7 @@ fn item_function(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, f: &cle + name.as_str().len() + generics_len; - let notable_traits = - f.decl.output.as_return().and_then(|output| notable_traits_button(output, cx)); + let notable_traits = notable_traits_button(&f.decl.output, cx); wrap_item(w, |w| { w.reserve(header_len); @@ -886,7 +933,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: write_small_section_header(w, "foreign-impls", "Implementations on Foreign Types", ""); for implementor in foreign { - let provided_methods = implementor.inner_impl().provided_trait_methods(cx.tcx()); + let provided_methods = implementor.inner_impl().provided_trait_methods(tcx); let assoc_link = AssocItemLink::GotoSource(implementor.impl_item.item_id, &provided_methods); render_impl( @@ -919,7 +966,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: } w.write_str("</div>"); - if t.is_auto(cx.tcx()) { + if t.is_auto(tcx) { write_small_section_header( w, "synthetic-implementors", @@ -948,7 +995,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: "<div id=\"implementors-list\"></div>", ); - if t.is_auto(cx.tcx()) { + if t.is_auto(tcx) { write_small_section_header( w, "synthetic-implementors", @@ -1131,32 +1178,18 @@ fn item_union(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean: #[derive(Template)] #[template(path = "item_union.html")] struct ItemUnion<'a, 'cx> { - cx: std::cell::RefCell<&'a mut Context<'cx>>, + cx: RefCell<&'a mut Context<'cx>>, it: &'a clean::Item, s: &'a clean::Union, } - impl<'a, 'cx: 'a> ItemUnion<'a, 'cx> { - fn render_assoc_items<'b>( - &'b self, - ) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> { - display_fn(move |f| { - let def_id = self.it.item_id.expect_def_id(); - let mut cx = self.cx.borrow_mut(); - let v = render_assoc_items(*cx, self.it, def_id, AssocItemRender::All); - write!(f, "{v}") - }) - } - fn document_type_layout<'b>( - &'b self, - ) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> { - display_fn(move |f| { - let def_id = self.it.item_id.expect_def_id(); - let cx = self.cx.borrow_mut(); - let v = document_type_layout(*cx, def_id); - write!(f, "{v}") - }) + impl<'a, 'cx: 'a> ItemTemplate<'a, 'cx> for ItemUnion<'a, 'cx> { + fn item_and_mut_cx(&self) -> (&'a clean::Item, RefMut<'_, &'a mut Context<'cx>>) { + (self.it, self.cx.borrow_mut()) } + } + + impl<'a, 'cx: 'a> ItemUnion<'a, 'cx> { fn render_union<'b>(&'b self) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> { display_fn(move |f| { let cx = self.cx.borrow_mut(); @@ -1164,22 +1197,6 @@ fn item_union(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean: write!(f, "{v}") }) } - fn render_attributes_in_pre<'b>( - &'b self, - ) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> { - display_fn(move |f| { - let tcx = self.cx.borrow().tcx(); - let v = render_attributes_in_pre(self.it, "", tcx); - write!(f, "{v}") - }) - } - fn document<'b>(&'b self) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> { - display_fn(move |f| { - let mut cx = self.cx.borrow_mut(); - let v = document(*cx, self.it, None, HeadingOffset::H2); - write!(f, "{v}") - }) - } fn document_field<'b>( &'b self, field: &'a clean::Item, @@ -1219,7 +1236,7 @@ fn item_union(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean: } } - ItemUnion { cx: std::cell::RefCell::new(cx), it, s }.render_into(w).unwrap(); + ItemUnion { cx: RefCell::new(cx), it, s }.render_into(w).unwrap(); } fn print_tuple_struct_fields<'a, 'cx: 'a>( @@ -1402,30 +1419,36 @@ fn item_macro(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: write!(w, "{}", document(cx, it, None, HeadingOffset::H2)) } -fn item_proc_macro(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, m: &clean::ProcMacro) { - wrap_item(w, |w| { +fn item_proc_macro( + w: &mut impl fmt::Write, + cx: &mut Context<'_>, + it: &clean::Item, + m: &clean::ProcMacro, +) { + let mut buffer = Buffer::new(); + wrap_item(&mut buffer, |buffer| { let name = it.name.expect("proc-macros always have names"); match m.kind { MacroKind::Bang => { - write!(w, "{}!() {{ /* proc-macro */ }}", name); + write!(buffer, "{}!() {{ /* proc-macro */ }}", name); } MacroKind::Attr => { - write!(w, "#[{}]", name); + write!(buffer, "#[{}]", name); } MacroKind::Derive => { - write!(w, "#[derive({})]", name); + write!(buffer, "#[derive({})]", name); if !m.helpers.is_empty() { - w.push_str("\n{\n"); - w.push_str(" // Attributes available to this derive:\n"); + buffer.push_str("\n{\n"); + buffer.push_str(" // Attributes available to this derive:\n"); for attr in &m.helpers { - writeln!(w, " #[{}]", attr); + writeln!(buffer, " #[{}]", attr); } - w.push_str("}\n"); + buffer.push_str("}\n"); } } } }); - write!(w, "{}", document(cx, it, None, HeadingOffset::H2)) + write!(w, "{}{}", buffer.into_inner(), document(cx, it, None, HeadingOffset::H2)).unwrap(); } fn item_primitive(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item) { @@ -1541,11 +1564,12 @@ fn item_struct(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean write!(w, "{}", document_type_layout(cx, def_id)); } -fn item_static(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean::Static) { - wrap_item(w, |w| { - render_attributes_in_code(w, it, cx.tcx()); +fn item_static(w: &mut impl fmt::Write, cx: &mut Context<'_>, it: &clean::Item, s: &clean::Static) { + let mut buffer = Buffer::new(); + wrap_item(&mut buffer, |buffer| { + render_attributes_in_code(buffer, it, cx.tcx()); write!( - w, + buffer, "{vis}static {mutability}{name}: {typ}", vis = visibility_print_with_space(it.visibility(cx.tcx()), it.item_id, cx), mutability = s.mutability.print_with_space(), @@ -1553,24 +1577,29 @@ fn item_static(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean typ = s.type_.print(cx) ); }); - write!(w, "{}", document(cx, it, None, HeadingOffset::H2)) + + write!(w, "{}", buffer.into_inner()).unwrap(); + + write!(w, "{}", document(cx, it, None, HeadingOffset::H2)).unwrap(); } -fn item_foreign_type(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item) { - wrap_item(w, |w| { - w.write_str("extern {\n"); - render_attributes_in_code(w, it, cx.tcx()); +fn item_foreign_type(w: &mut impl fmt::Write, cx: &mut Context<'_>, it: &clean::Item) { + let mut buffer = Buffer::new(); + wrap_item(&mut buffer, |buffer| { + buffer.write_str("extern {\n"); + render_attributes_in_code(buffer, it, cx.tcx()); write!( - w, + buffer, " {}type {};\n}}", visibility_print_with_space(it.visibility(cx.tcx()), it.item_id, cx), it.name.unwrap(), ); }); - write!(w, "{}", document(cx, it, None, HeadingOffset::H2)); + write!(w, "{}{}", buffer.into_inner(), document(cx, it, None, HeadingOffset::H2)).unwrap(); write!(w, "{}", render_assoc_items(cx, it, it.item_id.expect_def_id(), AssocItemRender::All)) + .unwrap(); } fn item_keyword(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item) { diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs index 846299f02e3..f34be120d29 100644 --- a/src/librustdoc/html/render/search_index.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -7,7 +7,7 @@ use rustc_span::symbol::Symbol; use serde::ser::{Serialize, SerializeStruct, Serializer}; use crate::clean; -use crate::clean::types::{FnRetTy, Function, Generics, ItemId, Type, WherePredicate}; +use crate::clean::types::{Function, Generics, ItemId, Type, WherePredicate}; use crate::formats::cache::{Cache, OrphanImplItem}; use crate::formats::item_type::ItemType; use crate::html::format::join_with_double_colon; @@ -656,22 +656,9 @@ fn get_fn_inputs_and_outputs<'tcx>( } let mut ret_types = Vec::new(); - match decl.output { - FnRetTy::Return(ref return_type) => { - add_generics_and_bounds_as_types( - self_, - generics, - return_type, - tcx, - 0, - &mut ret_types, - cache, - ); - if ret_types.is_empty() { - ret_types.push(get_index_type(return_type, vec![])); - } - } - _ => {} - }; + add_generics_and_bounds_as_types(self_, generics, &decl.output, tcx, 0, &mut ret_types, cache); + if ret_types.is_empty() { + ret_types.push(get_index_type(&decl.output, vec![])); + } (all_types, ret_types) } diff --git a/src/librustdoc/html/render/type_layout.rs b/src/librustdoc/html/render/type_layout.rs index 22aec623335..c9b95b1e645 100644 --- a/src/librustdoc/html/render/type_layout.rs +++ b/src/librustdoc/html/render/type_layout.rs @@ -54,13 +54,13 @@ pub(crate) fn document_type_layout<'a, 'cx: 'a>( } else if let Primitive::Int(i, _) = tag.primitive() { i.size().bytes() } else { - span_bug!(cx.tcx().def_span(ty_def_id), "tag is neither niche nor int") + span_bug!(tcx.def_span(ty_def_id), "tag is neither niche nor int") }; variants .iter_enumerated() .map(|(variant_idx, variant_layout)| { let Adt(adt, _) = type_layout.ty.kind() else { - span_bug!(cx.tcx().def_span(ty_def_id), "not an adt") + span_bug!(tcx.def_span(ty_def_id), "not an adt") }; let name = adt.variant(variant_idx).name; let is_unsized = variant_layout.abi.is_unsized(); diff --git a/src/librustdoc/html/templates/item_union.html b/src/librustdoc/html/templates/item_union.html index a01457971c1..c2196700513 100644 --- a/src/librustdoc/html/templates/item_union.html +++ b/src/librustdoc/html/templates/item_union.html @@ -1,8 +1,8 @@ <pre class="rust item-decl"><code> - {{ self.render_attributes_in_pre() | safe }} + {{ self::item_template_render_attributes_in_pre(self.borrow()) | safe }} {{ self.render_union() | safe }} </code></pre> -{{ self.document() | safe }} +{{ self::item_template_document(self.borrow()) | safe }} {% if self.fields_iter().peek().is_some() %} <h2 id="fields" class="fields small-section-header"> Fields<a href="#fields" class="anchor">§</a> @@ -19,5 +19,5 @@ {{ self.document_field(field) | safe }} {% endfor %} {% endif %} -{{ self.render_assoc_items() | safe }} -{{ self.document_type_layout() | safe }} +{{ self::item_template_render_assoc_items(self.borrow()) | safe }} +{{ self::item_template_document_type_layout(self.borrow()) | safe }} diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 935bb721f18..91cd55b1113 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -624,10 +624,7 @@ impl FromWithTcx<clean::FnDecl> for FnDecl { .into_iter() .map(|arg| (arg.name.to_string(), arg.type_.into_tcx(tcx))) .collect(), - output: match output { - clean::FnRetTy::Return(t) => Some(t.into_tcx(tcx)), - clean::FnRetTy::DefaultReturn => None, - }, + output: if output.is_unit() { None } else { Some(output.into_tcx(tcx)) }, c_variadic, } } diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 0a56916edcd..12c622e026f 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -712,13 +712,23 @@ fn run_renderer<'tcx, T: formats::FormatRenderer<'tcx>>( } fn main_args(at_args: &[String]) -> MainResult { + // Throw away the first argument, the name of the binary. + // In case of at_args being empty, as might be the case by + // passing empty argument array to execve under some platforms, + // just use an empty slice. + // + // This situation was possible before due to arg_expand_all being + // called before removing the argument, enabling a crash by calling + // the compiler with @empty_file as argv[0] and no more arguments. + let at_args = at_args.get(1..).unwrap_or_default(); + let args = rustc_driver::args::arg_expand_all(at_args); let mut options = getopts::Options::new(); for option in opts() { (option.apply)(&mut options); } - let matches = match options.parse(&args[1..]) { + let matches = match options.parse(&args) { Ok(m) => m, Err(err) => { early_error(ErrorOutputType::default(), err.to_string()); diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 9e6894a77df..2b0fef267e9 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -31,7 +31,7 @@ use std::ops::Range; use crate::clean::{self, utils::find_nearest_parent_module}; use crate::clean::{Crate, Item, ItemLink, PrimitiveType}; use crate::core::DocContext; -use crate::html::markdown::{markdown_links, MarkdownLink}; +use crate::html::markdown::{markdown_links, MarkdownLink, MarkdownLinkRange}; use crate::lint::{BROKEN_INTRA_DOC_LINKS, PRIVATE_INTRA_DOC_LINKS}; use crate::passes::Pass; use crate::visit::DocVisitor; @@ -248,7 +248,7 @@ struct DiagnosticInfo<'a> { item: &'a Item, dox: &'a str, ori_link: &'a str, - link_range: Range<usize>, + link_range: MarkdownLinkRange, } struct LinkCollector<'a, 'tcx> { @@ -723,7 +723,7 @@ fn resolve_associated_trait_item<'a>( .iter() .flat_map(|&(impl_, trait_)| { filter_assoc_items_by_name_and_namespace( - cx.tcx, + tcx, trait_, Ident::with_dummy_span(item_name), ns, @@ -833,7 +833,7 @@ impl<'a, 'tcx> DocVisitor for LinkCollector<'a, 'tcx> { enum PreprocessingError { /// User error: `[std#x#y]` is not valid MultipleAnchors, - Disambiguator(Range<usize>, String), + Disambiguator(MarkdownLinkRange, String), MalformedGenerics(MalformedGenerics, String), } @@ -842,7 +842,7 @@ impl PreprocessingError { match self { PreprocessingError::MultipleAnchors => report_multiple_anchors(cx, diag_info), PreprocessingError::Disambiguator(range, msg) => { - disambiguator_error(cx, diag_info, range.clone(), msg.as_str()) + disambiguator_error(cx, diag_info, range.clone(), msg.clone()) } PreprocessingError::MalformedGenerics(err, path_str) => { report_malformed_generics(cx, diag_info, *err, path_str) @@ -873,6 +873,7 @@ pub(crate) struct PreprocessedMarkdownLink( /// `link_buffer` is needed for lifetime reasons; it will always be overwritten and the contents ignored. fn preprocess_link( ori_link: &MarkdownLink, + dox: &str, ) -> Option<Result<PreprocessingInfo, PreprocessingError>> { // [] is mostly likely not supposed to be a link if ori_link.link.is_empty() { @@ -906,9 +907,15 @@ fn preprocess_link( Err((err_msg, relative_range)) => { // Only report error if we would not have ignored this link. See issue #83859. if !should_ignore_link_with_disambiguators(link) { - let no_backticks_range = range_between_backticks(ori_link); - let disambiguator_range = (no_backticks_range.start + relative_range.start) - ..(no_backticks_range.start + relative_range.end); + let disambiguator_range = match range_between_backticks(&ori_link.range, dox) { + MarkdownLinkRange::Destination(no_backticks_range) => { + MarkdownLinkRange::Destination( + (no_backticks_range.start + relative_range.start) + ..(no_backticks_range.start + relative_range.end), + ) + } + mdlr @ MarkdownLinkRange::WholeLink(_) => mdlr, + }; return Some(Err(PreprocessingError::Disambiguator(disambiguator_range, err_msg))); } else { return None; @@ -947,7 +954,7 @@ fn preprocess_link( fn preprocessed_markdown_links(s: &str) -> Vec<PreprocessedMarkdownLink> { markdown_links(s, |link| { - preprocess_link(&link).map(|pp_link| PreprocessedMarkdownLink(pp_link, link)) + preprocess_link(&link, s).map(|pp_link| PreprocessedMarkdownLink(pp_link, link)) }) } @@ -1060,22 +1067,12 @@ impl LinkCollector<'_, '_> { // valid omission. See https://github.com/rust-lang/rust/pull/80660#discussion_r551585677 // for discussion on the matter. let kind = self.cx.tcx.def_kind(id); - self.verify_disambiguator( - path_str, - ori_link, - kind, - id, - disambiguator, - item, - &diag_info, - )?; + self.verify_disambiguator(path_str, kind, id, disambiguator, item, &diag_info)?; } else { match disambiguator { Some(Disambiguator::Primitive | Disambiguator::Namespace(_)) | None => {} Some(other) => { - self.report_disambiguator_mismatch( - path_str, ori_link, other, res, &diag_info, - ); + self.report_disambiguator_mismatch(path_str, other, res, &diag_info); return None; } } @@ -1096,7 +1093,6 @@ impl LinkCollector<'_, '_> { }; self.verify_disambiguator( path_str, - ori_link, kind_for_dis, id_for_dis, disambiguator, @@ -1118,7 +1114,6 @@ impl LinkCollector<'_, '_> { fn verify_disambiguator( &self, path_str: &str, - ori_link: &MarkdownLink, kind: DefKind, id: DefId, disambiguator: Option<Disambiguator>, @@ -1142,7 +1137,7 @@ impl LinkCollector<'_, '_> { => {} (actual, Some(Disambiguator::Kind(expected))) if actual == expected => {} (_, Some(specified @ Disambiguator::Kind(_) | specified @ Disambiguator::Primitive)) => { - self.report_disambiguator_mismatch(path_str,ori_link,specified, Res::Def(kind, id),diag_info); + self.report_disambiguator_mismatch(path_str, specified, Res::Def(kind, id), diag_info); return None; } } @@ -1164,14 +1159,13 @@ impl LinkCollector<'_, '_> { fn report_disambiguator_mismatch( &self, path_str: &str, - ori_link: &MarkdownLink, specified: Disambiguator, resolved: Res, diag_info: &DiagnosticInfo<'_>, ) { // The resolved item did not match the disambiguator; give a better error than 'not found' let msg = format!("incompatible link kind for `{}`", path_str); - let callback = |diag: &mut Diagnostic, sp: Option<rustc_span::Span>| { + let callback = |diag: &mut Diagnostic, sp: Option<rustc_span::Span>, link_range| { let note = format!( "this link resolved to {} {}, which is not {} {}", resolved.article(), @@ -1184,14 +1178,24 @@ impl LinkCollector<'_, '_> { } else { diag.note(note); } - suggest_disambiguator(resolved, diag, path_str, &ori_link.link, sp); + suggest_disambiguator(resolved, diag, path_str, link_range, sp, diag_info); }; report_diagnostic(self.cx.tcx, BROKEN_INTRA_DOC_LINKS, msg, diag_info, callback); } - fn report_rawptr_assoc_feature_gate(&self, dox: &str, ori_link: &Range<usize>, item: &Item) { - let span = super::source_span_for_markdown_range(self.cx.tcx, dox, ori_link, &item.attrs) - .unwrap_or_else(|| item.attr_span(self.cx.tcx)); + fn report_rawptr_assoc_feature_gate( + &self, + dox: &str, + ori_link: &MarkdownLinkRange, + item: &Item, + ) { + let span = super::source_span_for_markdown_range( + self.cx.tcx, + dox, + ori_link.inner_range(), + &item.attrs, + ) + .unwrap_or_else(|| item.attr_span(self.cx.tcx)); rustc_session::parse::feature_err( &self.cx.tcx.sess.parse_sess, sym::intra_doc_pointers, @@ -1371,16 +1375,23 @@ impl LinkCollector<'_, '_> { /// [`Foo`] /// ^^^ /// ``` -fn range_between_backticks(ori_link: &MarkdownLink) -> Range<usize> { - let after_first_backtick_group = ori_link.link.bytes().position(|b| b != b'`').unwrap_or(0); - let before_second_backtick_group = ori_link - .link +/// +/// This function does nothing if `ori_link.range` is a `MarkdownLinkRange::WholeLink`. +fn range_between_backticks(ori_link_range: &MarkdownLinkRange, dox: &str) -> MarkdownLinkRange { + let range = match ori_link_range { + mdlr @ MarkdownLinkRange::WholeLink(_) => return mdlr.clone(), + MarkdownLinkRange::Destination(inner) => inner.clone(), + }; + let ori_link_text = &dox[range.clone()]; + let after_first_backtick_group = ori_link_text.bytes().position(|b| b != b'`').unwrap_or(0); + let before_second_backtick_group = ori_link_text .bytes() .skip(after_first_backtick_group) .position(|b| b == b'`') - .unwrap_or(ori_link.link.len()); - (ori_link.range.start + after_first_backtick_group) - ..(ori_link.range.start + before_second_backtick_group) + .unwrap_or(ori_link_text.len()); + MarkdownLinkRange::Destination( + (range.start + after_first_backtick_group)..(range.start + before_second_backtick_group), + ) } /// Returns true if we should ignore `link` due to it being unlikely @@ -1530,14 +1541,23 @@ impl Suggestion { sp: rustc_span::Span, ) -> Vec<(rustc_span::Span, String)> { let inner_sp = match ori_link.find('(') { + Some(index) if index != 0 && ori_link.as_bytes()[index - 1] == b'\\' => { + sp.with_hi(sp.lo() + BytePos((index - 1) as _)) + } Some(index) => sp.with_hi(sp.lo() + BytePos(index as _)), None => sp, }; let inner_sp = match ori_link.find('!') { + Some(index) if index != 0 && ori_link.as_bytes()[index - 1] == b'\\' => { + sp.with_hi(sp.lo() + BytePos((index - 1) as _)) + } Some(index) => inner_sp.with_hi(inner_sp.lo() + BytePos(index as _)), None => inner_sp, }; let inner_sp = match ori_link.find('@') { + Some(index) if index != 0 && ori_link.as_bytes()[index - 1] == b'\\' => { + sp.with_hi(sp.lo() + BytePos((index - 1) as _)) + } Some(index) => inner_sp.with_lo(inner_sp.lo() + BytePos(index as u32 + 1)), None => inner_sp, }; @@ -1584,7 +1604,7 @@ fn report_diagnostic( lint: &'static Lint, msg: impl Into<DiagnosticMessage> + Display, DiagnosticInfo { item, ori_link: _, dox, link_range }: &DiagnosticInfo<'_>, - decorate: impl FnOnce(&mut Diagnostic, Option<rustc_span::Span>), + decorate: impl FnOnce(&mut Diagnostic, Option<rustc_span::Span>, MarkdownLinkRange), ) { let Some(hir_id) = DocContext::as_local_hir_id(tcx, item.item_id) else { @@ -1596,16 +1616,32 @@ fn report_diagnostic( let sp = item.attr_span(tcx); tcx.struct_span_lint_hir(lint, hir_id, sp, msg, |lint| { - let span = - super::source_span_for_markdown_range(tcx, dox, link_range, &item.attrs).map(|sp| { - if dox.as_bytes().get(link_range.start) == Some(&b'`') - && dox.as_bytes().get(link_range.end - 1) == Some(&b'`') - { - sp.with_lo(sp.lo() + BytePos(1)).with_hi(sp.hi() - BytePos(1)) - } else { - sp - } - }); + let (span, link_range) = match link_range { + MarkdownLinkRange::Destination(md_range) => { + let mut md_range = md_range.clone(); + let sp = super::source_span_for_markdown_range(tcx, dox, &md_range, &item.attrs) + .map(|mut sp| { + while dox.as_bytes().get(md_range.start) == Some(&b' ') + || dox.as_bytes().get(md_range.start) == Some(&b'`') + { + md_range.start += 1; + sp = sp.with_lo(sp.lo() + BytePos(1)); + } + while dox.as_bytes().get(md_range.end - 1) == Some(&b' ') + || dox.as_bytes().get(md_range.end - 1) == Some(&b'`') + { + md_range.end -= 1; + sp = sp.with_hi(sp.hi() - BytePos(1)); + } + sp + }); + (sp, MarkdownLinkRange::Destination(md_range)) + } + MarkdownLinkRange::WholeLink(md_range) => ( + super::source_span_for_markdown_range(tcx, dox, &md_range, &item.attrs), + link_range.clone(), + ), + }; if let Some(sp) = span { lint.set_span(sp); @@ -1614,21 +1650,22 @@ fn report_diagnostic( // ^ ~~~~ // | link_range // last_new_line_offset - let last_new_line_offset = dox[..link_range.start].rfind('\n').map_or(0, |n| n + 1); + let md_range = link_range.inner_range().clone(); + let last_new_line_offset = dox[..md_range.start].rfind('\n').map_or(0, |n| n + 1); let line = dox[last_new_line_offset..].lines().next().unwrap_or(""); - // Print the line containing the `link_range` and manually mark it with '^'s. + // Print the line containing the `md_range` and manually mark it with '^'s. lint.note(format!( "the link appears in this line:\n\n{line}\n\ {indicator: <before$}{indicator:^<found$}", line = line, indicator = "", - before = link_range.start - last_new_line_offset, - found = link_range.len(), + before = md_range.start - last_new_line_offset, + found = md_range.len(), )); } - decorate(lint, span); + decorate(lint, span, link_range); lint }); @@ -1652,7 +1689,7 @@ fn resolution_failure( BROKEN_INTRA_DOC_LINKS, format!("unresolved link to `{}`", path_str), &diag_info, - |diag, sp| { + |diag, sp, link_range| { let item = |res: Res| format!("the {} `{}`", res.descr(), res.name(tcx),); let assoc_item_not_allowed = |res: Res| { let name = res.name(tcx); @@ -1706,7 +1743,7 @@ fn resolution_failure( if let Ok(v_res) = collector.resolve(start, ns, item_id, module_id) { debug!("found partial_res={:?}", v_res); if !v_res.is_empty() { - *partial_res = Some(full_res(collector.cx.tcx, v_res[0])); + *partial_res = Some(full_res(tcx, v_res[0])); *unresolved = end.into(); break 'outer; } @@ -1845,7 +1882,14 @@ fn resolution_failure( let note = match failure { ResolutionFailure::NotResolved { .. } => unreachable!("handled above"), ResolutionFailure::WrongNamespace { res, expected_ns } => { - suggest_disambiguator(res, diag, path_str, diag_info.ori_link, sp); + suggest_disambiguator( + res, + diag, + path_str, + link_range.clone(), + sp, + &diag_info, + ); format!( "this link resolves to {}, which is not in the {} namespace", @@ -1882,7 +1926,7 @@ fn anchor_failure( msg: String, anchor_idx: usize, ) { - report_diagnostic(cx.tcx, BROKEN_INTRA_DOC_LINKS, msg, &diag_info, |diag, sp| { + report_diagnostic(cx.tcx, BROKEN_INTRA_DOC_LINKS, msg, &diag_info, |diag, sp, _link_range| { if let Some(mut sp) = sp { if let Some((fragment_offset, _)) = diag_info.ori_link.char_indices().filter(|(_, x)| *x == '#').nth(anchor_idx) @@ -1898,11 +1942,11 @@ fn anchor_failure( fn disambiguator_error( cx: &DocContext<'_>, mut diag_info: DiagnosticInfo<'_>, - disambiguator_range: Range<usize>, + disambiguator_range: MarkdownLinkRange, msg: impl Into<DiagnosticMessage> + Display, ) { diag_info.link_range = disambiguator_range; - report_diagnostic(cx.tcx, BROKEN_INTRA_DOC_LINKS, msg, &diag_info, |diag, _sp| { + report_diagnostic(cx.tcx, BROKEN_INTRA_DOC_LINKS, msg, &diag_info, |diag, _sp, _link_range| { let msg = format!( "see {}/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators", crate::DOC_RUST_LANG_ORG_CHANNEL @@ -1922,7 +1966,7 @@ fn report_malformed_generics( BROKEN_INTRA_DOC_LINKS, format!("unresolved link to `{}`", path_str), &diag_info, - |diag, sp| { + |diag, sp, _link_range| { let note = match err { MalformedGenerics::UnbalancedAngleBrackets => "unbalanced angle brackets", MalformedGenerics::MissingType => "missing type for generic parameters", @@ -1995,7 +2039,7 @@ fn ambiguity_error( } } - report_diagnostic(cx.tcx, BROKEN_INTRA_DOC_LINKS, msg, diag_info, |diag, sp| { + report_diagnostic(cx.tcx, BROKEN_INTRA_DOC_LINKS, msg, diag_info, |diag, sp, link_range| { if let Some(sp) = sp { diag.span_label(sp, "ambiguous link"); } else { @@ -2003,7 +2047,7 @@ fn ambiguity_error( } for res in kinds { - suggest_disambiguator(res, diag, path_str, diag_info.ori_link, sp); + suggest_disambiguator(res, diag, path_str, link_range.clone(), sp, diag_info); } }); true @@ -2015,13 +2059,19 @@ fn suggest_disambiguator( res: Res, diag: &mut Diagnostic, path_str: &str, - ori_link: &str, + link_range: MarkdownLinkRange, sp: Option<rustc_span::Span>, + diag_info: &DiagnosticInfo<'_>, ) { let suggestion = res.disambiguator_suggestion(); let help = format!("to link to the {}, {}", res.descr(), suggestion.descr()); - if let Some(sp) = sp { + let ori_link = match link_range { + MarkdownLinkRange::Destination(range) => Some(&diag_info.dox[range]), + MarkdownLinkRange::WholeLink(_) => None, + }; + + if let (Some(sp), Some(ori_link)) = (sp, ori_link) { let mut spans = suggestion.as_help_span(path_str, ori_link, sp); if spans.len() > 1 { diag.multipart_suggestion(help, spans, Applicability::MaybeIncorrect); @@ -2047,7 +2097,7 @@ fn privacy_error(cx: &DocContext<'_>, diag_info: &DiagnosticInfo<'_>, path_str: let msg = format!("public documentation for `{}` links to private item `{}`", item_name, path_str); - report_diagnostic(cx.tcx, PRIVATE_INTRA_DOC_LINKS, msg, diag_info, |diag, sp| { + report_diagnostic(cx.tcx, PRIVATE_INTRA_DOC_LINKS, msg, diag_info, |diag, sp, _link_range| { if let Some(sp) = sp { diag.span_label(sp, "this item is private"); } diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs index 8d204ddb79e..fbf827cce09 100644 --- a/src/librustdoc/passes/collect_trait_impls.rs +++ b/src/librustdoc/passes/collect_trait_impls.rs @@ -19,9 +19,10 @@ pub(crate) const COLLECT_TRAIT_IMPLS: Pass = Pass { }; pub(crate) fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> Crate { + let tcx = cx.tcx; // We need to check if there are errors before running this pass because it would crash when // we try to get auto and blanket implementations. - if cx.tcx.sess.diagnostic().has_errors_or_lint_errors().is_some() { + if tcx.sess.diagnostic().has_errors_or_lint_errors().is_some() { return krate; } @@ -32,8 +33,7 @@ pub(crate) fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> }); let local_crate = ExternalCrate { crate_num: LOCAL_CRATE }; - let prims: FxHashSet<PrimitiveType> = - local_crate.primitives(cx.tcx).iter().map(|p| p.1).collect(); + let prims: FxHashSet<PrimitiveType> = local_crate.primitives(tcx).iter().map(|p| p.1).collect(); let crate_items = { let mut coll = ItemCollector::new(); @@ -46,9 +46,9 @@ pub(crate) fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> // External trait impls. { - let _prof_timer = cx.tcx.sess.prof.generic_activity("build_extern_trait_impls"); - for &cnum in cx.tcx.crates(()) { - for &impl_def_id in cx.tcx.trait_impls_in_crate(cnum) { + let _prof_timer = tcx.sess.prof.generic_activity("build_extern_trait_impls"); + for &cnum in tcx.crates(()) { + for &impl_def_id in tcx.trait_impls_in_crate(cnum) { inline::build_impl(cx, impl_def_id, None, &mut new_items_external); } } @@ -56,14 +56,13 @@ pub(crate) fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> // Local trait impls. { - let _prof_timer = cx.tcx.sess.prof.generic_activity("build_local_trait_impls"); + let _prof_timer = tcx.sess.prof.generic_activity("build_local_trait_impls"); let mut attr_buf = Vec::new(); - for &impl_def_id in cx.tcx.trait_impls_in_crate(LOCAL_CRATE) { - let mut parent = Some(cx.tcx.parent(impl_def_id)); + for &impl_def_id in tcx.trait_impls_in_crate(LOCAL_CRATE) { + let mut parent = Some(tcx.parent(impl_def_id)); while let Some(did) = parent { attr_buf.extend( - cx.tcx - .get_attrs(did, sym::doc) + tcx.get_attrs(did, sym::doc) .filter(|attr| { if let Some([attr]) = attr.meta_item_list().as_deref() { attr.has_name(sym::cfg) @@ -73,25 +72,24 @@ pub(crate) fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> }) .cloned(), ); - parent = cx.tcx.opt_parent(did); + parent = tcx.opt_parent(did); } inline::build_impl(cx, impl_def_id, Some((&attr_buf, None)), &mut new_items_local); attr_buf.clear(); } } - cx.tcx.sess.prof.generic_activity("build_primitive_trait_impls").run(|| { - for def_id in PrimitiveType::all_impls(cx.tcx) { + tcx.sess.prof.generic_activity("build_primitive_trait_impls").run(|| { + for def_id in PrimitiveType::all_impls(tcx) { // Try to inline primitive impls from other crates. if !def_id.is_local() { inline::build_impl(cx, def_id, None, &mut new_items_external); } } - for (prim, did) in PrimitiveType::primitive_locations(cx.tcx) { + for (prim, did) in PrimitiveType::primitive_locations(tcx) { // Do not calculate blanket impl list for docs that are not going to be rendered. // While the `impl` blocks themselves are only in `libcore`, the module with `doc` // attached is directly included in `libstd` as well. - let tcx = cx.tcx; if did.is_local() { for def_id in prim.impls(tcx).filter(|def_id| { // Avoid including impl blocks with filled-in generics. @@ -157,7 +155,7 @@ pub(crate) fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> // scan through included items ahead of time to splice in Deref targets to the "valid" sets for it in new_items_external.iter().chain(new_items_local.iter()) { if let ImplItem(box Impl { ref for_, ref trait_, ref items, .. }) = *it.kind && - trait_.as_ref().map(|t| t.def_id()) == cx.tcx.lang_items().deref_trait() && + trait_.as_ref().map(|t| t.def_id()) == tcx.lang_items().deref_trait() && cleaner.keep_impl(for_, true) { let target = items @@ -199,7 +197,7 @@ pub(crate) fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> if let ImplItem(box Impl { ref for_, ref trait_, ref kind, .. }) = *it.kind { cleaner.keep_impl( for_, - trait_.as_ref().map(|t| t.def_id()) == cx.tcx.lang_items().deref_trait(), + trait_.as_ref().map(|t| t.def_id()) == tcx.lang_items().deref_trait(), ) || trait_.as_ref().map_or(false, |t| cleaner.keep_impl_with_def_id(t.def_id().into())) || kind.is_blanket() } else { diff --git a/src/librustdoc/passes/lint/bare_urls.rs b/src/librustdoc/passes/lint/bare_urls.rs index a10d5fdb410..e9cee92d22b 100644 --- a/src/librustdoc/passes/lint/bare_urls.rs +++ b/src/librustdoc/passes/lint/bare_urls.rs @@ -20,19 +20,20 @@ pub(super) fn visit_item(cx: &DocContext<'_>, item: &Item) { }; let dox = item.doc_value(); if !dox.is_empty() { - let report_diag = |cx: &DocContext<'_>, msg: &str, url: &str, range: Range<usize>| { - let sp = source_span_for_markdown_range(cx.tcx, &dox, &range, &item.attrs) - .unwrap_or_else(|| item.attr_span(cx.tcx)); - cx.tcx.struct_span_lint_hir(crate::lint::BARE_URLS, hir_id, sp, msg, |lint| { - lint.note("bare URLs are not automatically turned into clickable links") - .span_suggestion( - sp, - "use an automatic link instead", - format!("<{}>", url), - Applicability::MachineApplicable, - ) - }); - }; + let report_diag = + |cx: &DocContext<'_>, msg: &'static str, url: &str, range: Range<usize>| { + let sp = source_span_for_markdown_range(cx.tcx, &dox, &range, &item.attrs) + .unwrap_or_else(|| item.attr_span(cx.tcx)); + cx.tcx.struct_span_lint_hir(crate::lint::BARE_URLS, hir_id, sp, msg, |lint| { + lint.note("bare URLs are not automatically turned into clickable links") + .span_suggestion( + sp, + "use an automatic link instead", + format!("<{}>", url), + Applicability::MachineApplicable, + ) + }); + }; let mut p = Parser::new_ext(&dox, main_body_opts()).into_offset_iter(); @@ -72,7 +73,7 @@ fn find_raw_urls( cx: &DocContext<'_>, text: &str, range: Range<usize>, - f: &impl Fn(&DocContext<'_>, &str, &str, Range<usize>), + f: &impl Fn(&DocContext<'_>, &'static str, &str, Range<usize>), ) { trace!("looking for raw urls in {}", text); // For now, we only check "full" URLs (meaning, starting with "http://" or "https://"). diff --git a/src/librustdoc/passes/lint/html_tags.rs b/src/librustdoc/passes/lint/html_tags.rs index f0403647af0..5273f52bc6f 100644 --- a/src/librustdoc/passes/lint/html_tags.rs +++ b/src/librustdoc/passes/lint/html_tags.rs @@ -17,90 +17,96 @@ pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item) { else { return }; let dox = item.doc_value(); if !dox.is_empty() { - let report_diag = |msg: &str, range: &Range<usize>, is_open_tag: bool| { + let report_diag = |msg: String, range: &Range<usize>, is_open_tag: bool| { let sp = match source_span_for_markdown_range(tcx, &dox, range, &item.attrs) { Some(sp) => sp, None => item.attr_span(tcx), }; - tcx.struct_span_lint_hir(crate::lint::INVALID_HTML_TAGS, hir_id, sp, msg, |lint| { - use rustc_lint_defs::Applicability; - // If a tag looks like `<this>`, it might actually be a generic. - // We don't try to detect stuff `<like, this>` because that's not valid HTML, - // and we don't try to detect stuff `<like this>` because that's not valid Rust. - let mut generics_end = range.end; - if let Some(Some(mut generics_start)) = (is_open_tag - && dox[..generics_end].ends_with('>')) - .then(|| extract_path_backwards(&dox, range.start)) - { - while generics_start != 0 - && generics_end < dox.len() - && dox.as_bytes()[generics_start - 1] == b'<' - && dox.as_bytes()[generics_end] == b'>' + tcx.struct_span_lint_hir( + crate::lint::INVALID_HTML_TAGS, + hir_id, + sp, + msg.to_string(), + |lint| { + use rustc_lint_defs::Applicability; + // If a tag looks like `<this>`, it might actually be a generic. + // We don't try to detect stuff `<like, this>` because that's not valid HTML, + // and we don't try to detect stuff `<like this>` because that's not valid Rust. + let mut generics_end = range.end; + if let Some(Some(mut generics_start)) = (is_open_tag + && dox[..generics_end].ends_with('>')) + .then(|| extract_path_backwards(&dox, range.start)) { - generics_end += 1; - generics_start -= 1; - if let Some(new_start) = extract_path_backwards(&dox, generics_start) { - generics_start = new_start; + while generics_start != 0 + && generics_end < dox.len() + && dox.as_bytes()[generics_start - 1] == b'<' + && dox.as_bytes()[generics_end] == b'>' + { + generics_end += 1; + generics_start -= 1; + if let Some(new_start) = extract_path_backwards(&dox, generics_start) { + generics_start = new_start; + } + if let Some(new_end) = extract_path_forward(&dox, generics_end) { + generics_end = new_end; + } } if let Some(new_end) = extract_path_forward(&dox, generics_end) { generics_end = new_end; } + let generics_sp = match source_span_for_markdown_range( + tcx, + &dox, + &(generics_start..generics_end), + &item.attrs, + ) { + Some(sp) => sp, + None => item.attr_span(tcx), + }; + // Sometimes, we only extract part of a path. For example, consider this: + // + // <[u32] as IntoIter<u32>>::Item + // ^^^^^ unclosed HTML tag `u32` + // + // We don't have any code for parsing fully-qualified trait paths. + // In theory, we could add it, but doing it correctly would require + // parsing the entire path grammar, which is problematic because of + // overlap between the path grammar and Markdown. + // + // The example above shows that ambiguity. Is `[u32]` intended to be an + // intra-doc link to the u32 primitive, or is it intended to be a slice? + // + // If the below conditional were removed, we would suggest this, which is + // not what the user probably wants. + // + // <[u32] as `IntoIter<u32>`>::Item + // + // We know that the user actually wants to wrap the whole thing in a code + // block, but the only reason we know that is because `u32` does not, in + // fact, implement IntoIter. If the example looks like this: + // + // <[Vec<i32>] as IntoIter<i32>::Item + // + // The ideal fix would be significantly different. + if (generics_start > 0 && dox.as_bytes()[generics_start - 1] == b'<') + || (generics_end < dox.len() && dox.as_bytes()[generics_end] == b'>') + { + return lint; + } + // multipart form is chosen here because ``Vec<i32>`` would be confusing. + lint.multipart_suggestion( + "try marking as source code", + vec![ + (generics_sp.shrink_to_lo(), String::from("`")), + (generics_sp.shrink_to_hi(), String::from("`")), + ], + Applicability::MaybeIncorrect, + ); } - if let Some(new_end) = extract_path_forward(&dox, generics_end) { - generics_end = new_end; - } - let generics_sp = match source_span_for_markdown_range( - tcx, - &dox, - &(generics_start..generics_end), - &item.attrs, - ) { - Some(sp) => sp, - None => item.attr_span(tcx), - }; - // Sometimes, we only extract part of a path. For example, consider this: - // - // <[u32] as IntoIter<u32>>::Item - // ^^^^^ unclosed HTML tag `u32` - // - // We don't have any code for parsing fully-qualified trait paths. - // In theory, we could add it, but doing it correctly would require - // parsing the entire path grammar, which is problematic because of - // overlap between the path grammar and Markdown. - // - // The example above shows that ambiguity. Is `[u32]` intended to be an - // intra-doc link to the u32 primitive, or is it intended to be a slice? - // - // If the below conditional were removed, we would suggest this, which is - // not what the user probably wants. - // - // <[u32] as `IntoIter<u32>`>::Item - // - // We know that the user actually wants to wrap the whole thing in a code - // block, but the only reason we know that is because `u32` does not, in - // fact, implement IntoIter. If the example looks like this: - // - // <[Vec<i32>] as IntoIter<i32>::Item - // - // The ideal fix would be significantly different. - if (generics_start > 0 && dox.as_bytes()[generics_start - 1] == b'<') - || (generics_end < dox.len() && dox.as_bytes()[generics_end] == b'>') - { - return lint; - } - // multipart form is chosen here because ``Vec<i32>`` would be confusing. - lint.multipart_suggestion( - "try marking as source code", - vec![ - (generics_sp.shrink_to_lo(), String::from("`")), - (generics_sp.shrink_to_hi(), String::from("`")), - ], - Applicability::MaybeIncorrect, - ); - } - lint - }); + lint + }, + ); }; let mut tags = Vec::new(); @@ -147,11 +153,11 @@ pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item) { let t = t.to_lowercase(); !ALLOWED_UNCLOSED.contains(&t.as_str()) }) { - report_diag(&format!("unclosed HTML tag `{}`", tag), range, true); + report_diag(format!("unclosed HTML tag `{}`", tag), range, true); } if let Some(range) = is_in_comment { - report_diag("Unclosed HTML comment", &range, false); + report_diag("Unclosed HTML comment".to_string(), &range, false); } } } @@ -165,7 +171,7 @@ fn drop_tag( tags: &mut Vec<(String, Range<usize>)>, tag_name: String, range: Range<usize>, - f: &impl Fn(&str, &Range<usize>, bool), + f: &impl Fn(String, &Range<usize>, bool), ) { let tag_name_low = tag_name.to_lowercase(); if let Some(pos) = tags.iter().rposition(|(t, _)| t.to_lowercase() == tag_name_low) { @@ -186,14 +192,14 @@ fn drop_tag( // `tags` is used as a queue, meaning that everything after `pos` is included inside it. // So `<h2><h3></h2>` will look like `["h2", "h3"]`. So when closing `h2`, we will still // have `h3`, meaning the tag wasn't closed as it should have. - f(&format!("unclosed HTML tag `{}`", last_tag_name), &last_tag_span, true); + f(format!("unclosed HTML tag `{}`", last_tag_name), &last_tag_span, true); } // Remove the `tag_name` that was originally closed tags.pop(); } else { // It can happen for example in this case: `<h2></script></h2>` (the `h2` tag isn't required // but it helps for the visualization). - f(&format!("unopened HTML tag `{}`", tag_name), &range, false); + f(format!("unopened HTML tag `{}`", tag_name), &range, false); } } @@ -261,7 +267,7 @@ fn extract_html_tag( range: &Range<usize>, start_pos: usize, iter: &mut Peekable<CharIndices<'_>>, - f: &impl Fn(&str, &Range<usize>, bool), + f: &impl Fn(String, &Range<usize>, bool), ) { let mut tag_name = String::new(); let mut is_closing = false; @@ -347,7 +353,7 @@ fn extract_html_tag( if let Some(quote_pos) = quote_pos { let qr = Range { start: quote_pos, end: quote_pos }; f( - &format!("unclosed quoted HTML attribute on tag `{}`", tag_name), + format!("unclosed quoted HTML attribute on tag `{}`", tag_name), &qr, false, ); @@ -360,7 +366,7 @@ fn extract_html_tag( at == "svg" || at == "math" }); if !valid { - f(&format!("invalid self-closing HTML tag `{}`", tag_name), &r, false); + f(format!("invalid self-closing HTML tag `{}`", tag_name), &r, false); } } else { tags.push((tag_name, r)); @@ -378,7 +384,7 @@ fn extract_tags( text: &str, range: Range<usize>, is_in_comment: &mut Option<Range<usize>>, - f: &impl Fn(&str, &Range<usize>, bool), + f: &impl Fn(String, &Range<usize>, bool), ) { let mut iter = text.char_indices().peekable(); diff --git a/src/librustdoc/passes/lint/unescaped_backticks.rs b/src/librustdoc/passes/lint/unescaped_backticks.rs index 683c224c4be..256958d7160 100644 --- a/src/librustdoc/passes/lint/unescaped_backticks.rs +++ b/src/librustdoc/passes/lint/unescaped_backticks.rs @@ -56,7 +56,7 @@ pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item) { ) .unwrap_or_else(|| item.attr_span(tcx)); - cx.tcx.struct_span_lint_hir(crate::lint::UNESCAPED_BACKTICKS, hir_id, span, "unescaped backtick", |lint| { + tcx.struct_span_lint_hir(crate::lint::UNESCAPED_BACKTICKS, hir_id, span, "unescaped backtick", |lint| { let mut help_emitted = false; match element.prev_code_guess { @@ -373,7 +373,7 @@ fn suggest_insertion( lint: &mut DiagnosticBuilder<'_, ()>, insert_index: usize, suggestion: char, - message: &str, + message: &'static str, ) { /// Maximum bytes of context to show around the insertion. const CONTEXT_MAX_LEN: usize = 80; diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 8f8dc6b7090..abb9229fbd5 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -267,6 +267,10 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { let is_no_inline = use_attrs.lists(sym::doc).has_word(sym::no_inline) || use_attrs.lists(sym::doc).has_word(sym::hidden); + if is_no_inline { + return false; + } + // For cross-crate impl inlining we need to know whether items are // reachable in documentation -- a previously unreachable item can be // made reachable by cross-crate inlining which we're checking here. @@ -280,40 +284,57 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { return false; }; - let is_private = - !self.cx.cache.effective_visibilities.is_directly_public(self.cx.tcx, ori_res_did); - let is_hidden = inherits_doc_hidden(self.cx.tcx, res_did, None); + let is_private = !self.cx.cache.effective_visibilities.is_directly_public(tcx, ori_res_did); + let is_hidden = tcx.is_doc_hidden(ori_res_did); + let item = tcx.hir().get_by_def_id(res_did); - // Only inline if requested or if the item would otherwise be stripped. - if (!please_inline && !is_private && !is_hidden) || is_no_inline { - return false; - } - - if !please_inline && - let Some(item_def_id) = reexport_chain(self.cx.tcx, def_id, res_did).iter() + if !please_inline { + let inherits_hidden = inherits_doc_hidden(tcx, res_did, None); + // Only inline if requested or if the item would otherwise be stripped. + // + // If it's a doc hidden module, we need to keep it in case some of its inner items + // are re-exported. + if (!is_private && !inherits_hidden) || ( + is_hidden && + !matches!(item, Node::Item(&hir::Item { kind: hir::ItemKind::Mod(_), .. })) + ) { + return false; + } else if let Some(item_def_id) = reexport_chain(tcx, def_id, res_did).iter() .flat_map(|reexport| reexport.id()).map(|id| id.expect_local()) .chain(iter::once(res_did)).nth(1) && - item_def_id != def_id && - self - .cx - .cache - .effective_visibilities - .is_directly_public(self.cx.tcx, item_def_id.to_def_id()) && - !inherits_doc_hidden(self.cx.tcx, item_def_id, None) - { - // The imported item is public and not `doc(hidden)` so no need to inline it. - return false; + item_def_id != def_id && + self + .cx + .cache + .effective_visibilities + .is_directly_public(tcx, item_def_id.to_def_id()) && + !inherits_doc_hidden(tcx, item_def_id, None) + { + // The imported item is public and not `doc(hidden)` so no need to inline it. + return false; + } } - if !self.view_item_stack.insert(res_did) { + let is_bang_macro = matches!( + item, + Node::Item(&hir::Item { kind: hir::ItemKind::Macro(_, MacroKind::Bang), .. }) + ); + + if !self.view_item_stack.insert(res_did) && !is_bang_macro { return false; } let ret = match tcx.hir().get_by_def_id(res_did) { + // Bang macros are handled a bit on their because of how they are handled by the + // compiler. If they have `#[doc(hidden)]` and the re-export doesn't have + // `#[doc(inline)]`, then we don't inline it. + Node::Item(_) if is_bang_macro && !please_inline && renamed.is_some() && is_hidden => { + return false; + } Node::Item(&hir::Item { kind: hir::ItemKind::Mod(ref m), .. }) if glob => { let prev = mem::replace(&mut self.inlining, true); for &i in m.item_ids { - let i = self.cx.tcx.hir().item(i); + let i = tcx.hir().item(i); self.visit_item_inner(i, None, Some(def_id)); } self.inlining = prev; @@ -440,6 +461,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { is_glob, please_inline, ) { + debug!("Inlining {:?}", item.owner_id.def_id); continue; } } diff --git a/src/tools/build_helper/src/lib.rs b/src/tools/build_helper/src/lib.rs index d3d2323db85..3fa970373b3 100644 --- a/src/tools/build_helper/src/lib.rs +++ b/src/tools/build_helper/src/lib.rs @@ -1,2 +1,3 @@ pub mod ci; pub mod git; +pub mod util; diff --git a/src/tools/build_helper/src/util.rs b/src/tools/build_helper/src/util.rs new file mode 100644 index 00000000000..731095023a9 --- /dev/null +++ b/src/tools/build_helper/src/util.rs @@ -0,0 +1,41 @@ +use std::process::Command; + +/// Invokes `build_helper::util::detail_exit` with `cfg!(test)` +#[macro_export] +macro_rules! detail_exit_macro { + ($code:expr) => { + build_helper::util::detail_exit($code, cfg!(test)); + }; +} + +/// If code is not 0 (successful exit status), exit status is 101 (rust's default error code.) +/// If `is_test` true and code is an error code, it will cause a panic. +pub fn detail_exit(code: i32, is_test: bool) -> ! { + // if in test and code is an error code, panic with status code provided + if is_test { + panic!("status code: {}", code); + } else { + // otherwise,exit with provided status code + std::process::exit(code); + } +} + +pub fn fail(s: &str) -> ! { + eprintln!("\n\n{}\n\n", s); + detail_exit(1, cfg!(test)); +} + +pub fn try_run(cmd: &mut Command, print_cmd_on_fail: bool) -> bool { + let status = match cmd.status() { + Ok(status) => status, + Err(e) => fail(&format!("failed to execute command: {:?}\nerror: {}", cmd, e)), + }; + if !status.success() && print_cmd_on_fail { + println!( + "\n\ncommand did not execute successfully: {:?}\n\ + expected success, got: {}\n\n", + cmd, status + ); + } + status.success() +} diff --git a/src/tools/cargo b/src/tools/cargo -Subproject 64fb38c97ac4d3a327fc9032c862dd28c8833b1 +Subproject f7b95e31642e09c2b6eabb18ed75007dda6677a diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs index 423eee47742..0ae95b045e0 100644 --- a/src/tools/clippy/clippy_lints/src/declared_lints.rs +++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs @@ -212,7 +212,6 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::instant_subtraction::UNCHECKED_DURATION_SUBTRACTION_INFO, crate::int_plus_one::INT_PLUS_ONE_INFO, crate::invalid_upcast_comparisons::INVALID_UPCAST_COMPARISONS_INFO, - crate::invalid_utf8_in_unchecked::INVALID_UTF8_IN_UNCHECKED_INFO, crate::items_after_statements::ITEMS_AFTER_STATEMENTS_INFO, crate::items_after_test_module::ITEMS_AFTER_TEST_MODULE_INFO, crate::iter_not_returning_iterator::ITER_NOT_RETURNING_ITERATOR_INFO, diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs index b27ffe73ffd..a1d2147cb49 100644 --- a/src/tools/clippy/clippy_lints/src/dereference.rs +++ b/src/tools/clippy/clippy_lints/src/dereference.rs @@ -1219,7 +1219,7 @@ fn needless_borrow_impl_arg_position<'tcx>( return false; } - let predicate = EarlyBinder(predicate).subst(cx.tcx, &substs_with_referent_ty); + let predicate = EarlyBinder::bind(predicate).subst(cx.tcx, &substs_with_referent_ty); let obligation = Obligation::new(cx.tcx, ObligationCause::dummy(), cx.param_env, predicate); let infcx = cx.tcx.infer_ctxt().build(); infcx.predicate_must_hold_modulo_regions(&obligation) diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs index b2071f4dcb1..c919b4de65d 100644 --- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs +++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs @@ -243,7 +243,7 @@ fn get_ufcs_type_name<'tcx>(cx: &LateContext<'tcx>, method_def_id: DefId, substs | ty::Ref(..) | ty::Slice(_) | ty::Tuple(_) => { - format!("<{}>", EarlyBinder(ty).subst(cx.tcx, substs)) + format!("<{}>", EarlyBinder::bind(ty).subst(cx.tcx, substs)) }, _ => ty.to_string(), } diff --git a/src/tools/clippy/clippy_lints/src/invalid_utf8_in_unchecked.rs b/src/tools/clippy/clippy_lints/src/invalid_utf8_in_unchecked.rs deleted file mode 100644 index 6a4861747d2..00000000000 --- a/src/tools/clippy/clippy_lints/src/invalid_utf8_in_unchecked.rs +++ /dev/null @@ -1,74 +0,0 @@ -use clippy_utils::diagnostics::span_lint; -use clippy_utils::{match_function_call, paths}; -use rustc_ast::{BorrowKind, LitKind}; -use rustc_hir::{Expr, ExprKind}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::source_map::Spanned; -use rustc_span::Span; - -declare_clippy_lint! { - /// ### What it does - /// Checks for `std::str::from_utf8_unchecked` with an invalid UTF-8 literal - /// - /// ### Why is this bad? - /// Creating such a `str` would result in undefined behavior - /// - /// ### Example - /// ```rust - /// # #[allow(unused)] - /// unsafe { - /// std::str::from_utf8_unchecked(b"cl\x82ippy"); - /// } - /// ``` - #[clippy::version = "1.64.0"] - pub INVALID_UTF8_IN_UNCHECKED, - correctness, - "using a non UTF-8 literal in `std::std::from_utf8_unchecked`" -} -declare_lint_pass!(InvalidUtf8InUnchecked => [INVALID_UTF8_IN_UNCHECKED]); - -impl<'tcx> LateLintPass<'tcx> for InvalidUtf8InUnchecked { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { - if let Some([arg]) = match_function_call(cx, expr, &paths::STR_FROM_UTF8_UNCHECKED) { - match &arg.kind { - ExprKind::Lit(Spanned { node: lit, .. }) => { - if let LitKind::ByteStr(bytes, _) = &lit - && std::str::from_utf8(bytes).is_err() - { - lint(cx, expr.span); - } - }, - ExprKind::AddrOf(BorrowKind::Ref, _, Expr { kind: ExprKind::Array(args), .. }) => { - let elements = args.iter().map(|e|{ - match &e.kind { - ExprKind::Lit(Spanned { node: lit, .. }) => match lit { - LitKind::Byte(b) => Some(*b), - #[allow(clippy::cast_possible_truncation)] - LitKind::Int(b, _) => Some(*b as u8), - _ => None - } - _ => None - } - }).collect::<Option<Vec<_>>>(); - - if let Some(elements) = elements - && std::str::from_utf8(&elements).is_err() - { - lint(cx, expr.span); - } - } - _ => {} - } - } - } -} - -fn lint(cx: &LateContext<'_>, span: Span) { - span_lint( - cx, - INVALID_UTF8_IN_UNCHECKED, - span, - "non UTF-8 literal in `std::str::from_utf8_unchecked`", - ); -} diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs index b442a4ac5f6..fcca595c2bc 100644 --- a/src/tools/clippy/clippy_lints/src/lib.rs +++ b/src/tools/clippy/clippy_lints/src/lib.rs @@ -157,7 +157,6 @@ mod inline_fn_without_body; mod instant_subtraction; mod int_plus_one; mod invalid_upcast_comparisons; -mod invalid_utf8_in_unchecked; mod items_after_statements; mod items_after_test_module; mod iter_not_returning_iterator; @@ -937,7 +936,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(move |_| Box::new(manual_retain::ManualRetain::new(msrv()))); let verbose_bit_mask_threshold = conf.verbose_bit_mask_threshold; store.register_late_pass(move |_| Box::new(operators::Operators::new(verbose_bit_mask_threshold))); - store.register_late_pass(|_| Box::new(invalid_utf8_in_unchecked::InvalidUtf8InUnchecked)); store.register_late_pass(|_| Box::<std_instead_of_core::StdReexports>::default()); store.register_late_pass(move |_| Box::new(instant_subtraction::InstantSubtraction::new(msrv()))); store.register_late_pass(|_| Box::new(partialeq_to_none::PartialeqToNone)); 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 6841aaf626c..99f810c27cf 100644 --- a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs +++ b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs @@ -241,7 +241,7 @@ fn is_contains_sig(cx: &LateContext<'_>, call_id: HirId, iter_expr: &Expr<'_>) - && let proj_ty = cx.tcx.mk_projection(iter_item.def_id, substs) && let Ok(item_ty) = cx.tcx.try_normalize_erasing_regions(cx.param_env, proj_ty) { - item_ty == EarlyBinder(search_ty).subst(cx.tcx, cx.typeck_results().node_substs(call_id)) + item_ty == EarlyBinder::bind(search_ty).subst(cx.tcx, cx.typeck_results().node_substs(call_id)) } else { false } 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 67b7d3691dc..309d2157b76 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 @@ -428,7 +428,7 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty< })); if trait_predicates.any(|predicate| { - let predicate = EarlyBinder(predicate).subst(cx.tcx, new_subst); + let predicate = EarlyBinder::bind(predicate).subst(cx.tcx, new_subst); let obligation = Obligation::new(cx.tcx, ObligationCause::dummy(), cx.param_env, predicate); !cx.tcx.infer_ctxt().build().predicate_must_hold_modulo_regions(&obligation) }) { @@ -438,7 +438,7 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty< let output_ty = fn_sig.output(); if output_ty.contains(*param_ty) { if let Ok(new_ty) = cx.tcx.try_subst_and_normalize_erasing_regions( - new_subst, cx.param_env, EarlyBinder(output_ty)) { + new_subst, cx.param_env, EarlyBinder::bind(output_ty)) { expr = parent_expr; ty = new_ty; continue; diff --git a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs index f1831a30461..3b7eccad79d 100644 --- a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs +++ b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs @@ -154,7 +154,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn { if let Err((span, err)) = is_min_const_fn(cx.tcx, mir, &self.msrv) { if cx.tcx.is_const_fn_raw(def_id.to_def_id()) { - cx.tcx.sess.span_err(span, err.as_ref()); + cx.tcx.sess.span_err(span, err); } } else { span_lint(cx, MISSING_CONST_FOR_FN, span, "this could be a `const fn`"); diff --git a/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs b/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs index 2abdfacd276..e6fd65f001a 100644 --- a/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs +++ b/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs @@ -138,7 +138,7 @@ fn collect_unsafe_exprs<'tcx>( .type_dependent_def_id(expr.hir_id) .map(|def_id| cx.tcx.fn_sig(def_id)) { - if sig.0.unsafety() == Unsafety::Unsafe { + if sig.skip_binder().unsafety() == Unsafety::Unsafe { unsafe_ops.push(("unsafe method call occurs here", expr.span)); } } diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs index 0bb1775aae9..7d53fe65658 100644 --- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs +++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs @@ -26,7 +26,6 @@ use rustc_span::{sym, Span}; use rustc_target::spec::abi::Abi; use rustc_trait_selection::traits; use rustc_trait_selection::traits::misc::type_allowed_to_implement_copy; -use std::borrow::Cow; declare_clippy_lint! { /// ### What it does @@ -240,9 +239,8 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { snippet_opt(cx, span) .map_or( "change the call to".into(), - |x| Cow::from(format!("change `{x}` to")), - ) - .as_ref(), + |x| format!("change `{x}` to"), + ), suggestion, Applicability::Unspecified, ); @@ -270,9 +268,8 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { snippet_opt(cx, span) .map_or( "change the call to".into(), - |x| Cow::from(format!("change `{x}` to")) - ) - .as_ref(), + |x| format!("change `{x}` to") + ), suggestion, Applicability::Unspecified, ); diff --git a/src/tools/clippy/clippy_lints/src/renamed_lints.rs b/src/tools/clippy/clippy_lints/src/renamed_lints.rs index b0db56bb417..7c2a100efda 100644 --- a/src/tools/clippy/clippy_lints/src/renamed_lints.rs +++ b/src/tools/clippy/clippy_lints/src/renamed_lints.rs @@ -43,6 +43,7 @@ pub static RENAMED_LINTS: &[(&str, &str)] = &[ ("clippy::into_iter_on_array", "array_into_iter"), ("clippy::invalid_atomic_ordering", "invalid_atomic_ordering"), ("clippy::invalid_ref", "invalid_value"), + ("clippy::invalid_utf8_in_unchecked", "invalid_from_utf8_unchecked"), ("clippy::let_underscore_drop", "let_underscore_drop"), ("clippy::mem_discriminant_non_enum", "enum_intrinsics_non_enums"), ("clippy::panic_params", "non_fmt_panics"), diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs b/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs index 8b0e0ce5a30..5073eb02bd8 100644 --- a/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs +++ b/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs @@ -163,7 +163,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps { span_lint_and_then(cx, UNNECESSARY_WRAPS, span, lint_msg.as_str(), |diag| { diag.span_suggestion( fn_decl.output.span(), - return_type_sugg_msg.as_str(), + return_type_sugg_msg, return_type_sugg, Applicability::MaybeIncorrect, ); diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs index fb772644c0d..cc3183759ae 100644 --- a/src/tools/clippy/clippy_utils/src/consts.rs +++ b/src/tools/clippy/clippy_utils/src/consts.rs @@ -462,7 +462,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { let substs = if self.substs.is_empty() { substs } else { - EarlyBinder(substs).subst(self.lcx.tcx, self.substs) + EarlyBinder::bind(substs).subst(self.lcx.tcx, self.substs) }; let result = self diff --git a/src/tools/clippy/clippy_utils/src/diagnostics.rs b/src/tools/clippy/clippy_utils/src/diagnostics.rs index 812f6fe71a0..edd87546a5f 100644 --- a/src/tools/clippy/clippy_utils/src/diagnostics.rs +++ b/src/tools/clippy/clippy_utils/src/diagnostics.rs @@ -46,7 +46,7 @@ fn docs_link(diag: &mut Diagnostic, lint: &'static Lint) { /// | ^^^^^^^^^^^^^^^^^^^^^^^ /// ``` pub fn span_lint<T: LintContext>(cx: &T, lint: &'static Lint, sp: impl Into<MultiSpan>, msg: &str) { - cx.struct_span_lint(lint, sp, msg, |diag| { + cx.struct_span_lint(lint, sp, msg.to_string(), |diag| { docs_link(diag, lint); diag }); @@ -80,11 +80,12 @@ pub fn span_lint_and_help<T: LintContext>( help_span: Option<Span>, help: &str, ) { - cx.struct_span_lint(lint, span, msg, |diag| { + cx.struct_span_lint(lint, span, msg.to_string(), |diag| { + let help = help.to_string(); if let Some(help_span) = help_span { - diag.span_help(help_span, help); + diag.span_help(help_span, help.to_string()); } else { - diag.help(help); + diag.help(help.to_string()); } docs_link(diag, lint); diag @@ -122,7 +123,8 @@ pub fn span_lint_and_note<T: LintContext>( note_span: Option<Span>, note: &str, ) { - cx.struct_span_lint(lint, span, msg, |diag| { + cx.struct_span_lint(lint, span, msg.to_string(), |diag| { + let note = note.to_string(); if let Some(note_span) = note_span { diag.span_note(note_span, note); } else { @@ -143,7 +145,7 @@ where S: Into<MultiSpan>, F: FnOnce(&mut Diagnostic), { - cx.struct_span_lint(lint, sp, msg, |diag| { + cx.struct_span_lint(lint, sp, msg.to_string(), |diag| { f(diag); docs_link(diag, lint); diag @@ -151,7 +153,7 @@ where } pub fn span_lint_hir(cx: &LateContext<'_>, lint: &'static Lint, hir_id: HirId, sp: Span, msg: &str) { - cx.tcx.struct_span_lint_hir(lint, hir_id, sp, msg, |diag| { + cx.tcx.struct_span_lint_hir(lint, hir_id, sp, msg.to_string(), |diag| { docs_link(diag, lint); diag }); @@ -165,7 +167,7 @@ pub fn span_lint_hir_and_then( msg: &str, f: impl FnOnce(&mut Diagnostic), ) { - cx.tcx.struct_span_lint_hir(lint, hir_id, sp, msg, |diag| { + cx.tcx.struct_span_lint_hir(lint, hir_id, sp, msg.to_string(), |diag| { f(diag); docs_link(diag, lint); diag @@ -202,7 +204,7 @@ pub fn span_lint_and_sugg<T: LintContext>( applicability: Applicability, ) { span_lint_and_then(cx, lint, sp, msg, |diag| { - diag.span_suggestion(sp, help, sugg, applicability); + diag.span_suggestion(sp, help.to_string(), sugg, applicability); }); } @@ -232,5 +234,5 @@ pub fn multispan_sugg_with_applicability<I>( ) where I: IntoIterator<Item = (Span, String)>, { - diag.multipart_suggestion(help_msg, sugg.into_iter().collect(), applicability); + diag.multipart_suggestion(help_msg.to_string(), sugg.into_iter().collect(), applicability); } diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs index 14f7f03016f..f477524eec5 100644 --- a/src/tools/clippy/clippy_utils/src/sugg.rs +++ b/src/tools/clippy/clippy_utils/src/sugg.rs @@ -741,7 +741,7 @@ impl<T: LintContext> DiagnosticExt<T> for rustc_errors::Diagnostic { if let Some(indent) = indentation(cx, item) { let span = item.with_hi(item.lo()); - self.span_suggestion(span, msg, format!("{attr}\n{indent}"), applicability); + self.span_suggestion(span, msg.to_string(), format!("{attr}\n{indent}"), applicability); } } @@ -762,7 +762,7 @@ impl<T: LintContext> DiagnosticExt<T> for rustc_errors::Diagnostic { }) .collect::<String>(); - self.span_suggestion(span, msg, format!("{new_item}\n{indent}"), applicability); + self.span_suggestion(span, msg.to_string(), format!("{new_item}\n{indent}"), applicability); } } @@ -779,7 +779,7 @@ impl<T: LintContext> DiagnosticExt<T> for rustc_errors::Diagnostic { } } - self.span_suggestion(remove_span, msg, "", applicability); + self.span_suggestion(remove_span, msg.to_string(), "", applicability); } } diff --git a/src/tools/clippy/tests/ui/invalid_utf8_in_unchecked.rs b/src/tools/clippy/tests/ui/invalid_utf8_in_unchecked.rs deleted file mode 100644 index 3dc096d3197..00000000000 --- a/src/tools/clippy/tests/ui/invalid_utf8_in_unchecked.rs +++ /dev/null @@ -1,20 +0,0 @@ -#![warn(clippy::invalid_utf8_in_unchecked)] - -fn main() { - // Valid - unsafe { - std::str::from_utf8_unchecked(&[99, 108, 105, 112, 112, 121]); - std::str::from_utf8_unchecked(&[b'c', b'l', b'i', b'p', b'p', b'y']); - std::str::from_utf8_unchecked(b"clippy"); - - let x = 0xA0; - std::str::from_utf8_unchecked(&[0xC0, x]); - } - - // Invalid - unsafe { - std::str::from_utf8_unchecked(&[99, 108, 130, 105, 112, 112, 121]); - std::str::from_utf8_unchecked(&[b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']); - std::str::from_utf8_unchecked(b"cl\x82ippy"); - } -} diff --git a/src/tools/clippy/tests/ui/invalid_utf8_in_unchecked.stderr b/src/tools/clippy/tests/ui/invalid_utf8_in_unchecked.stderr deleted file mode 100644 index c89cd2758ee..00000000000 --- a/src/tools/clippy/tests/ui/invalid_utf8_in_unchecked.stderr +++ /dev/null @@ -1,22 +0,0 @@ -error: non UTF-8 literal in `std::str::from_utf8_unchecked` - --> $DIR/invalid_utf8_in_unchecked.rs:16:9 - | -LL | std::str::from_utf8_unchecked(&[99, 108, 130, 105, 112, 112, 121]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `-D clippy::invalid-utf8-in-unchecked` implied by `-D warnings` - -error: non UTF-8 literal in `std::str::from_utf8_unchecked` - --> $DIR/invalid_utf8_in_unchecked.rs:17:9 - | -LL | std::str::from_utf8_unchecked(&[b'c', b'l', b'/x82', b'i', b'p', b'p', b'y']); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: non UTF-8 literal in `std::str::from_utf8_unchecked` - --> $DIR/invalid_utf8_in_unchecked.rs:18:9 - | -LL | std::str::from_utf8_unchecked(b"cl/x82ippy"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 3 previous errors - diff --git a/src/tools/clippy/tests/ui/rename.fixed b/src/tools/clippy/tests/ui/rename.fixed index dfe45dec8a7..53ac65473b8 100644 --- a/src/tools/clippy/tests/ui/rename.fixed +++ b/src/tools/clippy/tests/ui/rename.fixed @@ -38,6 +38,7 @@ #![allow(array_into_iter)] #![allow(invalid_atomic_ordering)] #![allow(invalid_value)] +#![allow(invalid_from_utf8_unchecked)] #![allow(let_underscore_drop)] #![allow(enum_intrinsics_non_enums)] #![allow(non_fmt_panics)] @@ -87,6 +88,7 @@ #![warn(array_into_iter)] #![warn(invalid_atomic_ordering)] #![warn(invalid_value)] +#![warn(invalid_from_utf8_unchecked)] #![warn(let_underscore_drop)] #![warn(enum_intrinsics_non_enums)] #![warn(non_fmt_panics)] diff --git a/src/tools/clippy/tests/ui/rename.rs b/src/tools/clippy/tests/ui/rename.rs index ce8eca5a308..722c0b3eb27 100644 --- a/src/tools/clippy/tests/ui/rename.rs +++ b/src/tools/clippy/tests/ui/rename.rs @@ -38,6 +38,7 @@ #![allow(array_into_iter)] #![allow(invalid_atomic_ordering)] #![allow(invalid_value)] +#![allow(invalid_from_utf8_unchecked)] #![allow(let_underscore_drop)] #![allow(enum_intrinsics_non_enums)] #![allow(non_fmt_panics)] @@ -87,6 +88,7 @@ #![warn(clippy::into_iter_on_array)] #![warn(clippy::invalid_atomic_ordering)] #![warn(clippy::invalid_ref)] +#![warn(clippy::invalid_utf8_in_unchecked)] #![warn(clippy::let_underscore_drop)] #![warn(clippy::mem_discriminant_non_enum)] #![warn(clippy::panic_params)] diff --git a/src/tools/clippy/tests/ui/rename.stderr b/src/tools/clippy/tests/ui/rename.stderr index 3fca60aa2eb..1ff83917660 100644 --- a/src/tools/clippy/tests/ui/rename.stderr +++ b/src/tools/clippy/tests/ui/rename.stderr @@ -1,5 +1,5 @@ error: lint `clippy::almost_complete_letter_range` has been renamed to `clippy::almost_complete_range` - --> $DIR/rename.rs:49:9 + --> $DIR/rename.rs:50:9 | LL | #![warn(clippy::almost_complete_letter_range)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::almost_complete_range` @@ -7,286 +7,292 @@ LL | #![warn(clippy::almost_complete_letter_range)] = note: `-D renamed-and-removed-lints` implied by `-D warnings` error: lint `clippy::blacklisted_name` has been renamed to `clippy::disallowed_names` - --> $DIR/rename.rs:50:9 + --> $DIR/rename.rs:51:9 | LL | #![warn(clippy::blacklisted_name)] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_names` error: lint `clippy::block_in_if_condition_expr` has been renamed to `clippy::blocks_in_if_conditions` - --> $DIR/rename.rs:51:9 + --> $DIR/rename.rs:52:9 | LL | #![warn(clippy::block_in_if_condition_expr)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions` error: lint `clippy::block_in_if_condition_stmt` has been renamed to `clippy::blocks_in_if_conditions` - --> $DIR/rename.rs:52:9 + --> $DIR/rename.rs:53:9 | LL | #![warn(clippy::block_in_if_condition_stmt)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions` error: lint `clippy::box_vec` has been renamed to `clippy::box_collection` - --> $DIR/rename.rs:53:9 + --> $DIR/rename.rs:54:9 | LL | #![warn(clippy::box_vec)] | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::box_collection` error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes` - --> $DIR/rename.rs:54:9 + --> $DIR/rename.rs:55:9 | LL | #![warn(clippy::const_static_lifetime)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes` error: lint `clippy::cyclomatic_complexity` has been renamed to `clippy::cognitive_complexity` - --> $DIR/rename.rs:55:9 + --> $DIR/rename.rs:56:9 | LL | #![warn(clippy::cyclomatic_complexity)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity` error: lint `clippy::derive_hash_xor_eq` has been renamed to `clippy::derived_hash_with_manual_eq` - --> $DIR/rename.rs:56:9 + --> $DIR/rename.rs:57:9 | LL | #![warn(clippy::derive_hash_xor_eq)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::derived_hash_with_manual_eq` error: lint `clippy::disallowed_method` has been renamed to `clippy::disallowed_methods` - --> $DIR/rename.rs:57:9 + --> $DIR/rename.rs:58:9 | LL | #![warn(clippy::disallowed_method)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_methods` error: lint `clippy::disallowed_type` has been renamed to `clippy::disallowed_types` - --> $DIR/rename.rs:58:9 + --> $DIR/rename.rs:59:9 | LL | #![warn(clippy::disallowed_type)] | ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_types` error: lint `clippy::eval_order_dependence` has been renamed to `clippy::mixed_read_write_in_expression` - --> $DIR/rename.rs:59:9 + --> $DIR/rename.rs:60:9 | LL | #![warn(clippy::eval_order_dependence)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::mixed_read_write_in_expression` error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion` - --> $DIR/rename.rs:60:9 + --> $DIR/rename.rs:61:9 | LL | #![warn(clippy::identity_conversion)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion` error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok` - --> $DIR/rename.rs:61:9 + --> $DIR/rename.rs:62:9 | LL | #![warn(clippy::if_let_some_result)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok` error: lint `clippy::integer_arithmetic` has been renamed to `clippy::arithmetic_side_effects` - --> $DIR/rename.rs:62:9 + --> $DIR/rename.rs:63:9 | LL | #![warn(clippy::integer_arithmetic)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::arithmetic_side_effects` error: lint `clippy::logic_bug` has been renamed to `clippy::overly_complex_bool_expr` - --> $DIR/rename.rs:63:9 + --> $DIR/rename.rs:64:9 | LL | #![warn(clippy::logic_bug)] | ^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::overly_complex_bool_expr` error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default` - --> $DIR/rename.rs:64:9 + --> $DIR/rename.rs:65:9 | LL | #![warn(clippy::new_without_default_derive)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default` error: lint `clippy::option_and_then_some` has been renamed to `clippy::bind_instead_of_map` - --> $DIR/rename.rs:65:9 + --> $DIR/rename.rs:66:9 | LL | #![warn(clippy::option_and_then_some)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map` error: lint `clippy::option_expect_used` has been renamed to `clippy::expect_used` - --> $DIR/rename.rs:66:9 + --> $DIR/rename.rs:67:9 | LL | #![warn(clippy::option_expect_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used` error: lint `clippy::option_map_unwrap_or` has been renamed to `clippy::map_unwrap_or` - --> $DIR/rename.rs:67:9 + --> $DIR/rename.rs:68:9 | LL | #![warn(clippy::option_map_unwrap_or)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::option_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or` - --> $DIR/rename.rs:68:9 + --> $DIR/rename.rs:69:9 | LL | #![warn(clippy::option_map_unwrap_or_else)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::option_unwrap_used` has been renamed to `clippy::unwrap_used` - --> $DIR/rename.rs:69:9 + --> $DIR/rename.rs:70:9 | LL | #![warn(clippy::option_unwrap_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used` error: lint `clippy::ref_in_deref` has been renamed to `clippy::needless_borrow` - --> $DIR/rename.rs:70:9 + --> $DIR/rename.rs:71:9 | LL | #![warn(clippy::ref_in_deref)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::needless_borrow` error: lint `clippy::result_expect_used` has been renamed to `clippy::expect_used` - --> $DIR/rename.rs:71:9 + --> $DIR/rename.rs:72:9 | LL | #![warn(clippy::result_expect_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used` error: lint `clippy::result_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or` - --> $DIR/rename.rs:72:9 + --> $DIR/rename.rs:73:9 | LL | #![warn(clippy::result_map_unwrap_or_else)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::result_unwrap_used` has been renamed to `clippy::unwrap_used` - --> $DIR/rename.rs:73:9 + --> $DIR/rename.rs:74:9 | LL | #![warn(clippy::result_unwrap_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used` error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str` - --> $DIR/rename.rs:74:9 + --> $DIR/rename.rs:75:9 | LL | #![warn(clippy::single_char_push_str)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::single_char_add_str` error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions` - --> $DIR/rename.rs:75:9 + --> $DIR/rename.rs:76:9 | LL | #![warn(clippy::stutter)] | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions` error: lint `clippy::to_string_in_display` has been renamed to `clippy::recursive_format_impl` - --> $DIR/rename.rs:76:9 + --> $DIR/rename.rs:77:9 | LL | #![warn(clippy::to_string_in_display)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::recursive_format_impl` error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters` - --> $DIR/rename.rs:77:9 + --> $DIR/rename.rs:78:9 | LL | #![warn(clippy::zero_width_space)] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters` error: lint `clippy::clone_double_ref` has been renamed to `suspicious_double_ref_op` - --> $DIR/rename.rs:78:9 + --> $DIR/rename.rs:79:9 | LL | #![warn(clippy::clone_double_ref)] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `suspicious_double_ref_op` error: lint `clippy::drop_bounds` has been renamed to `drop_bounds` - --> $DIR/rename.rs:79:9 + --> $DIR/rename.rs:80:9 | LL | #![warn(clippy::drop_bounds)] | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds` error: lint `clippy::drop_copy` has been renamed to `dropping_copy_types` - --> $DIR/rename.rs:80:9 + --> $DIR/rename.rs:81:9 | LL | #![warn(clippy::drop_copy)] | ^^^^^^^^^^^^^^^^^ help: use the new name: `dropping_copy_types` error: lint `clippy::drop_ref` has been renamed to `dropping_references` - --> $DIR/rename.rs:81:9 + --> $DIR/rename.rs:82:9 | LL | #![warn(clippy::drop_ref)] | ^^^^^^^^^^^^^^^^ help: use the new name: `dropping_references` error: lint `clippy::for_loop_over_option` has been renamed to `for_loops_over_fallibles` - --> $DIR/rename.rs:82:9 + --> $DIR/rename.rs:83:9 | LL | #![warn(clippy::for_loop_over_option)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles` error: lint `clippy::for_loop_over_result` has been renamed to `for_loops_over_fallibles` - --> $DIR/rename.rs:83:9 + --> $DIR/rename.rs:84:9 | LL | #![warn(clippy::for_loop_over_result)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles` error: lint `clippy::for_loops_over_fallibles` has been renamed to `for_loops_over_fallibles` - --> $DIR/rename.rs:84:9 + --> $DIR/rename.rs:85:9 | LL | #![warn(clippy::for_loops_over_fallibles)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles` error: lint `clippy::forget_copy` has been renamed to `forgetting_copy_types` - --> $DIR/rename.rs:85:9 + --> $DIR/rename.rs:86:9 | LL | #![warn(clippy::forget_copy)] | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_copy_types` error: lint `clippy::forget_ref` has been renamed to `forgetting_references` - --> $DIR/rename.rs:86:9 + --> $DIR/rename.rs:87:9 | LL | #![warn(clippy::forget_ref)] | ^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_references` error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter` - --> $DIR/rename.rs:87:9 + --> $DIR/rename.rs:88:9 | LL | #![warn(clippy::into_iter_on_array)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter` error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering` - --> $DIR/rename.rs:88:9 + --> $DIR/rename.rs:89:9 | LL | #![warn(clippy::invalid_atomic_ordering)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering` error: lint `clippy::invalid_ref` has been renamed to `invalid_value` - --> $DIR/rename.rs:89:9 + --> $DIR/rename.rs:90:9 | LL | #![warn(clippy::invalid_ref)] | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value` +error: lint `clippy::invalid_utf8_in_unchecked` has been renamed to `invalid_from_utf8_unchecked` + --> $DIR/rename.rs:91:9 + | +LL | #![warn(clippy::invalid_utf8_in_unchecked)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_from_utf8_unchecked` + error: lint `clippy::let_underscore_drop` has been renamed to `let_underscore_drop` - --> $DIR/rename.rs:90:9 + --> $DIR/rename.rs:92:9 | LL | #![warn(clippy::let_underscore_drop)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `let_underscore_drop` error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums` - --> $DIR/rename.rs:91:9 + --> $DIR/rename.rs:93:9 | LL | #![warn(clippy::mem_discriminant_non_enum)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums` error: lint `clippy::panic_params` has been renamed to `non_fmt_panics` - --> $DIR/rename.rs:92:9 + --> $DIR/rename.rs:94:9 | LL | #![warn(clippy::panic_params)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics` error: lint `clippy::positional_named_format_parameters` has been renamed to `named_arguments_used_positionally` - --> $DIR/rename.rs:93:9 + --> $DIR/rename.rs:95:9 | LL | #![warn(clippy::positional_named_format_parameters)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `named_arguments_used_positionally` error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr` - --> $DIR/rename.rs:94:9 + --> $DIR/rename.rs:96:9 | LL | #![warn(clippy::temporary_cstring_as_ptr)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr` error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints` - --> $DIR/rename.rs:95:9 + --> $DIR/rename.rs:97:9 | LL | #![warn(clippy::unknown_clippy_lints)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints` error: lint `clippy::unused_label` has been renamed to `unused_labels` - --> $DIR/rename.rs:96:9 + --> $DIR/rename.rs:98:9 | LL | #![warn(clippy::unused_label)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels` -error: aborting due to 48 previous errors +error: aborting due to 49 previous errors diff --git a/src/tools/compiletest/Cargo.toml b/src/tools/compiletest/Cargo.toml index e5297d41a61..d2f258320f0 100644 --- a/src/tools/compiletest/Cargo.toml +++ b/src/tools/compiletest/Cargo.toml @@ -3,6 +3,9 @@ name = "compiletest" version = "0.0.0" edition = "2021" +[lib] +doctest = false + [dependencies] colored = "2" diff = "0.1.10" diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index ba68b5ee9d5..f796c898731 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -69,6 +69,12 @@ string_enum! { } } +impl Default for Mode { + fn default() -> Self { + Mode::Ui + } +} + impl Mode { pub fn disambiguator(self) -> &'static str { // Pretty-printing tests could run concurrently, and if they do, @@ -125,7 +131,7 @@ pub enum PanicStrategy { } /// Configuration for compiletest -#[derive(Debug, Clone)] +#[derive(Debug, Default, Clone)] pub struct Config { /// `true` to overwrite stderr/stdout files instead of complaining about changes in output. pub bless: bool, diff --git a/src/tools/compiletest/src/header/needs.rs b/src/tools/compiletest/src/header/needs.rs index 4a57c61406c..18b3b913a68 100644 --- a/src/tools/compiletest/src/header/needs.rs +++ b/src/tools/compiletest/src/header/needs.rs @@ -71,6 +71,11 @@ pub(super) fn handle_needs( ignore_reason: "ignored on targets without shadow call stacks", }, Need { + name: "needs-sanitizer-safestack", + condition: cache.sanitizer_safestack, + ignore_reason: "ignored on targets without SafeStack support", + }, + Need { name: "needs-run-enabled", condition: config.run_enabled(), ignore_reason: "ignored when running the resulting test binaries is disabled", @@ -184,6 +189,7 @@ pub(super) struct CachedNeedsConditions { sanitizer_hwaddress: bool, sanitizer_memtag: bool, sanitizer_shadow_call_stack: bool, + sanitizer_safestack: bool, xray: bool, rust_lld: bool, i686_dlltool: bool, @@ -220,6 +226,7 @@ impl CachedNeedsConditions { sanitizer_hwaddress: util::HWASAN_SUPPORTED_TARGETS.contains(target), sanitizer_memtag: util::MEMTAG_SUPPORTED_TARGETS.contains(target), sanitizer_shadow_call_stack: util::SHADOWCALLSTACK_SUPPORTED_TARGETS.contains(target), + sanitizer_safestack: util::SAFESTACK_SUPPORTED_TARGETS.contains(target), xray: util::XRAY_SUPPORTED_TARGETS.contains(target), // For tests using the `needs-rust-lld` directive (e.g. for `-Zgcc-ld=lld`), we need to find diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs new file mode 100644 index 00000000000..fc48d015990 --- /dev/null +++ b/src/tools/compiletest/src/lib.rs @@ -0,0 +1,1136 @@ +#![crate_name = "compiletest"] +// The `test` crate is the only unstable feature +// allowed here, just to share similar code. +#![feature(test)] + +extern crate test; + +#[cfg(test)] +mod tests; + +pub mod common; +pub mod compute_diff; +pub mod errors; +pub mod header; +mod json; +mod raise_fd_limit; +mod read2; +pub mod runtest; +pub mod util; + +use crate::common::{expected_output_path, output_base_dir, output_relative_path, UI_EXTENSIONS}; +use crate::common::{Config, Debugger, Mode, PassMode, TestPaths}; +use crate::util::logv; +use build_helper::git::{get_git_modified_files, get_git_untracked_files}; +use core::panic; +use getopts::Options; +use lazycell::AtomicLazyCell; +use std::collections::BTreeSet; +use std::ffi::OsString; +use std::fs; +use std::io::{self, ErrorKind}; +use std::path::{Path, PathBuf}; +use std::process::{Command, Stdio}; +use std::time::SystemTime; +use std::{env, vec}; +use test::ColorConfig; +use tracing::*; +use walkdir::WalkDir; + +use self::header::{make_test_description, EarlyProps}; +use crate::header::HeadersCache; +use std::sync::Arc; + +pub fn parse_config(args: Vec<String>) -> Config { + let mut opts = Options::new(); + opts.reqopt("", "compile-lib-path", "path to host shared libraries", "PATH") + .reqopt("", "run-lib-path", "path to target shared libraries", "PATH") + .reqopt("", "rustc-path", "path to rustc to use for compiling", "PATH") + .optopt("", "rustdoc-path", "path to rustdoc to use for compiling", "PATH") + .optopt("", "rust-demangler-path", "path to rust-demangler to use in tests", "PATH") + .reqopt("", "python", "path to python to use for doc tests", "PATH") + .optopt("", "jsondocck-path", "path to jsondocck to use for doc tests", "PATH") + .optopt("", "jsondoclint-path", "path to jsondoclint to use for doc tests", "PATH") + .optopt("", "valgrind-path", "path to Valgrind executable for Valgrind tests", "PROGRAM") + .optflag("", "force-valgrind", "fail if Valgrind tests cannot be run under Valgrind") + .optopt("", "run-clang-based-tests-with", "path to Clang executable", "PATH") + .optopt("", "llvm-filecheck", "path to LLVM's FileCheck binary", "DIR") + .reqopt("", "src-base", "directory to scan for test files", "PATH") + .reqopt("", "build-base", "directory to deposit test outputs", "PATH") + .reqopt("", "sysroot-base", "directory containing the compiler sysroot", "PATH") + .reqopt("", "stage-id", "the target-stage identifier", "stageN-TARGET") + .reqopt( + "", + "mode", + "which sort of compile tests to run", + "run-pass-valgrind | pretty | debug-info | codegen | rustdoc \ + | rustdoc-json | codegen-units | incremental | run-make | ui | js-doc-test | mir-opt | assembly", + ) + .reqopt( + "", + "suite", + "which suite of compile tests to run. used for nicer error reporting.", + "SUITE", + ) + .optopt( + "", + "pass", + "force {check,build,run}-pass tests to this mode.", + "check | build | run", + ) + .optopt("", "run", "whether to execute run-* tests", "auto | always | never") + .optflag("", "ignored", "run tests marked as ignored") + .optmulti("", "skip", "skip tests matching SUBSTRING. Can be passed multiple times", "SUBSTRING") + .optflag("", "exact", "filters match exactly") + .optopt( + "", + "runtool", + "supervisor program to run tests under \ + (eg. emulator, valgrind)", + "PROGRAM", + ) + .optmulti("", "host-rustcflags", "flags to pass to rustc for host", "FLAGS") + .optmulti("", "target-rustcflags", "flags to pass to rustc for target", "FLAGS") + .optflag("", "optimize-tests", "run tests with optimizations enabled") + .optflag("", "verbose", "run tests verbosely, showing all output") + .optflag( + "", + "bless", + "overwrite stderr/stdout files instead of complaining about a mismatch", + ) + .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") + .optopt("", "gdb", "path to GDB to use for GDB debuginfo tests", "PATH") + .optopt("", "lldb-version", "the version of LLDB used", "VERSION STRING") + .optopt("", "llvm-version", "the version of LLVM used", "VERSION STRING") + .optflag("", "system-llvm", "is LLVM the system LLVM") + .optopt("", "android-cross-path", "Android NDK standalone path", "PATH") + .optopt("", "adb-path", "path to the android debugger", "PATH") + .optopt("", "adb-test-dir", "path to tests for the android debugger", "PATH") + .optopt("", "lldb-python-dir", "directory containing LLDB's python module", "PATH") + .reqopt("", "cc", "path to a C compiler", "PATH") + .reqopt("", "cxx", "path to a C++ compiler", "PATH") + .reqopt("", "cflags", "flags for the C compiler", "FLAGS") + .reqopt("", "cxxflags", "flags for the CXX compiler", "FLAGS") + .optopt("", "ar", "path to an archiver", "PATH") + .optopt("", "target-linker", "path to a linker for the target", "PATH") + .optopt("", "host-linker", "path to a linker for the host", "PATH") + .reqopt("", "llvm-components", "list of LLVM components built in", "LIST") + .optopt("", "llvm-bin-dir", "Path to LLVM's `bin` directory", "PATH") + .optopt("", "nodejs", "the name of nodejs", "PATH") + .optopt("", "npm", "the name of npm", "PATH") + .optopt("", "remote-test-client", "path to the remote test client", "PATH") + .optopt( + "", + "compare-mode", + "mode describing what file the actual ui output will be compared to", + "COMPARE MODE", + ) + .optflag( + "", + "rustfix-coverage", + "enable this to generate a Rustfix coverage file, which is saved in \ + `./<build_base>/rustfix_missing_coverage.txt`", + ) + .optflag("", "force-rerun", "rerun tests even if the inputs are unchanged") + .optflag("", "only-modified", "only run tests that result been modified") + .optflag("", "nocapture", "") + .optflag("h", "help", "show this message") + .reqopt("", "channel", "current Rust channel", "CHANNEL") + .optflag("", "git-hash", "run tests which rely on commit version being compiled into the binaries") + .optopt("", "edition", "default Rust edition", "EDITION"); + + let (argv0, args_) = args.split_first().unwrap(); + if args.len() == 1 || args[1] == "-h" || args[1] == "--help" { + let message = format!("Usage: {} [OPTIONS] [TESTNAME...]", argv0); + println!("{}", opts.usage(&message)); + println!(); + panic!() + } + + let matches = &match opts.parse(args_) { + Ok(m) => m, + Err(f) => panic!("{:?}", f), + }; + + if matches.opt_present("h") || matches.opt_present("help") { + let message = format!("Usage: {} [OPTIONS] [TESTNAME...]", argv0); + println!("{}", opts.usage(&message)); + println!(); + 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: PathBuf) -> PathBuf { + if path.is_relative() { env::current_dir().unwrap().join(path) } else { path } + } + + let target = opt_str2(matches.opt_str("target")); + let android_cross_path = opt_path(matches, "android-cross-path"); + let (cdb, cdb_version) = analyze_cdb(matches.opt_str("cdb"), &target); + let (gdb, gdb_version, gdb_native_rust) = + analyze_gdb(matches.opt_str("gdb"), &target, &android_cross_path); + let (lldb_version, lldb_native_rust) = matches + .opt_str("lldb-version") + .as_deref() + .and_then(extract_lldb_version) + .map(|(v, b)| (Some(v), b)) + .unwrap_or((None, false)); + let color = match matches.opt_str("color").as_deref() { + Some("auto") | None => ColorConfig::AutoColor, + Some("always") => ColorConfig::AlwaysColor, + Some("never") => ColorConfig::NeverColor, + Some(x) => panic!("argument for --color must be auto, always, or never, but found `{}`", x), + }; + let llvm_version = + matches.opt_str("llvm-version").as_deref().and_then(header::extract_llvm_version).or_else( + || header::extract_llvm_version_from_binary(&matches.opt_str("llvm-filecheck")?), + ); + + let src_base = opt_path(matches, "src-base"); + let run_ignored = matches.opt_present("ignored"); + let mode = matches.opt_str("mode").unwrap().parse().expect("invalid mode"); + let has_tidy = if mode == Mode::Rustdoc { + Command::new("tidy") + .arg("--version") + .stdout(Stdio::null()) + .status() + .map_or(false, |status| status.success()) + } else { + // Avoid spawning an external command when we know tidy won't be used. + false + }; + Config { + bless: matches.opt_present("bless"), + 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"), + rustdoc_path: matches.opt_str("rustdoc-path").map(PathBuf::from), + rust_demangler_path: matches.opt_str("rust-demangler-path").map(PathBuf::from), + python: matches.opt_str("python").unwrap(), + jsondocck_path: matches.opt_str("jsondocck-path"), + jsondoclint_path: matches.opt_str("jsondoclint-path"), + valgrind_path: matches.opt_str("valgrind-path"), + force_valgrind: matches.opt_present("force-valgrind"), + 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), + src_base, + build_base: opt_path(matches, "build-base"), + sysroot_base: opt_path(matches, "sysroot-base"), + stage_id: matches.opt_str("stage-id").unwrap(), + mode, + suite: matches.opt_str("suite").unwrap(), + debugger: None, + run_ignored, + filters: matches.free.clone(), + skip: matches.opt_strs("skip"), + filter_exact: matches.opt_present("exact"), + force_pass_mode: matches.opt_str("pass").map(|mode| { + mode.parse::<PassMode>() + .unwrap_or_else(|_| panic!("unknown `--pass` option `{}` given", mode)) + }), + run: matches.opt_str("run").and_then(|mode| match mode.as_str() { + "auto" => None, + "always" => Some(true), + "never" => Some(false), + _ => panic!("unknown `--run` option `{}` given", mode), + }), + logfile: matches.opt_str("logfile").map(|s| PathBuf::from(&s)), + runtool: matches.opt_str("runtool"), + host_rustcflags: matches.opt_strs("host-rustcflags"), + target_rustcflags: matches.opt_strs("target-rustcflags"), + optimize_tests: matches.opt_present("optimize-tests"), + target, + host: opt_str2(matches.opt_str("host")), + cdb, + cdb_version, + gdb, + gdb_version, + gdb_native_rust, + lldb_version, + lldb_native_rust, + llvm_version, + system_llvm: matches.opt_present("system-llvm"), + android_cross_path, + adb_path: opt_str2(matches.opt_str("adb-path")), + adb_test_dir: opt_str2(matches.opt_str("adb-test-dir")), + adb_device_status: opt_str2(matches.opt_str("target")).contains("android") + && "(none)" != opt_str2(matches.opt_str("adb-test-dir")) + && !opt_str2(matches.opt_str("adb-test-dir")).is_empty(), + lldb_python_dir: matches.opt_str("lldb-python-dir"), + verbose: matches.opt_present("verbose"), + format: match (matches.opt_present("quiet"), matches.opt_present("json")) { + (true, true) => panic!("--quiet and --json are incompatible"), + (true, false) => test::OutputFormat::Terse, + (false, true) => test::OutputFormat::Json, + (false, false) => test::OutputFormat::Pretty, + }, + only_modified: matches.opt_present("only-modified"), + color, + remote_test_client: matches.opt_str("remote-test-client").map(PathBuf::from), + compare_mode: matches + .opt_str("compare-mode") + .map(|s| s.parse().expect("invalid --compare-mode provided")), + rustfix_coverage: matches.opt_present("rustfix-coverage"), + has_tidy, + channel: matches.opt_str("channel").unwrap(), + git_hash: matches.opt_present("git-hash"), + edition: matches.opt_str("edition"), + + cc: matches.opt_str("cc").unwrap(), + cxx: matches.opt_str("cxx").unwrap(), + cflags: matches.opt_str("cflags").unwrap(), + cxxflags: matches.opt_str("cxxflags").unwrap(), + ar: matches.opt_str("ar").unwrap_or_else(|| String::from("ar")), + target_linker: matches.opt_str("target-linker"), + host_linker: matches.opt_str("host-linker"), + llvm_components: matches.opt_str("llvm-components").unwrap(), + nodejs: matches.opt_str("nodejs"), + npm: matches.opt_str("npm"), + + force_rerun: matches.opt_present("force-rerun"), + + target_cfgs: AtomicLazyCell::new(), + + nocapture: matches.opt_present("nocapture"), + } +} + +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!("rustdoc_path: {:?}", config.rustdoc_path)); + logv(c, format!("rust_demangler_path: {:?}", config.rust_demangler_path)); + logv(c, format!("src_base: {:?}", config.src_base.display())); + logv(c, format!("build_base: {:?}", config.build_base.display())); + logv(c, format!("stage_id: {}", config.stage_id)); + logv(c, format!("mode: {}", config.mode)); + logv(c, format!("run_ignored: {}", config.run_ignored)); + logv(c, format!("filters: {:?}", config.filters)); + logv(c, format!("skip: {:?}", config.skip)); + logv(c, format!("filter_exact: {}", config.filter_exact)); + logv( + c, + format!("force_pass_mode: {}", opt_str(&config.force_pass_mode.map(|m| format!("{}", m))),), + ); + logv(c, format!("runtool: {}", opt_str(&config.runtool))); + logv(c, format!("host-rustcflags: {:?}", config.host_rustcflags)); + 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!("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, "\n".to_string()); +} + +pub fn opt_str(maybestr: &Option<String>) -> &str { + match *maybestr { + None => "(none)", + Some(ref s) => s, + } +} + +pub fn opt_str2(maybestr: Option<String>) -> String { + match maybestr { + None => "(none)".to_owned(), + Some(s) => s, + } +} + +pub fn run_tests(config: Arc<Config>) { + // If we want to collect rustfix coverage information, + // we first make sure that the coverage file does not exist. + // It will be created later on. + if config.rustfix_coverage { + let mut coverage_file_path = config.build_base.clone(); + 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) + } + } + } + + // sadly osx needs some file descriptor limits raised for running tests in + // parallel (especially when we have lots and lots of child processes). + // For context, see #8904 + unsafe { + raise_fd_limit::raise_fd_limit(); + } + // 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"); + + // Let tests know which target they're running as + env::set_var("TARGET", &config.target); + + let opts = test_opts(&config); + + let mut configs = Vec::new(); + if let Mode::DebugInfo = config.mode { + // Debugging emscripten code doesn't make sense today + if !config.target.contains("emscripten") { + configs.extend(configure_cdb(&config)); + configs.extend(configure_gdb(&config)); + configs.extend(configure_lldb(&config)); + } + } else { + configs.push(config.clone()); + }; + + let mut tests = Vec::new(); + for c in configs { + let mut found_paths = BTreeSet::new(); + make_tests(c, &mut tests, &mut found_paths); + check_overlapping_tests(&found_paths); + } + + tests.sort_by(|a, b| a.desc.name.as_slice().cmp(&b.desc.name.as_slice())); + + let res = test::run_tests_console(&opts, tests); + match res { + Ok(true) => {} + Ok(false) => { + // We want to report that the tests failed, but we also want to give + // some indication of just what tests we were running. Especially on + // CI, where there can be cross-compiled tests for a lot of + // architectures, without this critical information it can be quite + // easy to miss which tests failed, and as such fail to reproduce + // the failure locally. + + println!( + "Some tests failed in compiletest suite={}{} mode={} host={} target={}", + config.suite, + config + .compare_mode + .as_ref() + .map(|c| format!(" compare_mode={:?}", c)) + .unwrap_or_default(), + config.mode, + config.host, + config.target + ); + + std::process::exit(1); + } + Err(e) => { + // We don't know if tests passed or not, but if there was an error + // during testing we don't want to just succeed (we may not have + // tested something), so fail. + // + // This should realistically "never" happen, so don't try to make + // this a pretty error message. + panic!("I/O failure during tests: {:?}", e); + } + } +} + +fn configure_cdb(config: &Config) -> Option<Arc<Config>> { + config.cdb.as_ref()?; + + Some(Arc::new(Config { debugger: Some(Debugger::Cdb), ..config.clone() })) +} + +fn configure_gdb(config: &Config) -> Option<Arc<Config>> { + config.gdb_version?; + + if config.matches_env("msvc") { + return None; + } + + if config.remote_test_client.is_some() && !config.target.contains("android") { + println!( + "WARNING: debuginfo tests are not available when \ + testing with remote" + ); + return None; + } + + if config.target.contains("android") { + println!( + "{} debug-info test uses tcp 5039 port.\ + please reserve it", + config.target + ); + + // android debug-info test uses remote debugger so, we test 1 thread + // at once as they're all sharing the same TCP port to communicate + // over. + // + // we should figure out how to lift this restriction! (run them all + // on different ports allocated dynamically). + env::set_var("RUST_TEST_THREADS", "1"); + } + + Some(Arc::new(Config { debugger: Some(Debugger::Gdb), ..config.clone() })) +} + +fn configure_lldb(config: &Config) -> Option<Arc<Config>> { + config.lldb_python_dir.as_ref()?; + + if let Some(350) = config.lldb_version { + println!( + "WARNING: The used version of LLDB (350) has a \ + known issue that breaks debuginfo tests. See \ + issue #32520 for more information. Skipping all \ + LLDB-based tests!", + ); + return None; + } + + Some(Arc::new(Config { debugger: Some(Debugger::Lldb), ..config.clone() })) +} + +pub fn test_opts(config: &Config) -> test::TestOpts { + if env::var("RUST_TEST_NOCAPTURE").is_ok() { + eprintln!( + "WARNING: RUST_TEST_NOCAPTURE is no longer used. \ + Use the `--nocapture` flag instead." + ); + } + + 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, + logfile: config.logfile.clone(), + run_tests: true, + bench_benchmarks: true, + nocapture: config.nocapture, + color: config.color, + 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: std::env::var_os("RUSTC_TEST_FAIL_FAST").is_some(), + } +} + +pub fn make_tests( + config: Arc<Config>, + tests: &mut Vec<test::TestDescAndFn>, + found_paths: &mut BTreeSet<PathBuf>, +) { + debug!("making tests from {:?}", config.src_base.display()); + let inputs = common_inputs_stamp(&config); + let modified_tests = modified_tests(&config, &config.src_base).unwrap_or_else(|err| { + panic!("modified_tests got error from dir: {}, error: {}", config.src_base.display(), err) + }); + + let cache = HeadersCache::load(&config); + let mut poisoned = false; + collect_tests_from_dir( + config.clone(), + &cache, + &config.src_base, + &PathBuf::new(), + &inputs, + tests, + found_paths, + &modified_tests, + &mut poisoned, + ) + .unwrap_or_else(|_| panic!("Could not read tests from {}", config.src_base.display())); + + if poisoned { + eprintln!(); + panic!("there are errors in tests"); + } +} + +/// Returns a stamp constructed from input files common to all test cases. +fn common_inputs_stamp(config: &Config) -> Stamp { + let rust_src_dir = config.find_rust_src_root().expect("Could not find Rust source root"); + + let mut stamp = Stamp::from_path(&config.rustc_path); + + // Relevant pretty printer files + let pretty_printer_files = [ + "src/etc/rust_types.py", + "src/etc/gdb_load_rust_pretty_printers.py", + "src/etc/gdb_lookup.py", + "src/etc/gdb_providers.py", + "src/etc/lldb_batchmode.py", + "src/etc/lldb_lookup.py", + "src/etc/lldb_providers.py", + ]; + for file in &pretty_printer_files { + let path = rust_src_dir.join(file); + stamp.add_path(&path); + } + + stamp.add_dir(&rust_src_dir.join("src/etc/natvis")); + + stamp.add_dir(&config.run_lib_path); + + if let Some(ref rustdoc_path) = config.rustdoc_path { + stamp.add_path(&rustdoc_path); + stamp.add_path(&rust_src_dir.join("src/etc/htmldocck.py")); + } + + // Compiletest itself. + stamp.add_dir(&rust_src_dir.join("src/tools/compiletest/")); + + stamp +} + +fn modified_tests(config: &Config, dir: &Path) -> Result<Vec<PathBuf>, String> { + if !config.only_modified { + return Ok(vec![]); + } + let files = + get_git_modified_files(Some(dir), &vec!["rs", "stderr", "fixed"])?.unwrap_or(vec![]); + // Add new test cases to the list, it will be convenient in daily development. + let untracked_files = get_git_untracked_files(None)?.unwrap_or(vec![]); + + let all_paths = [&files[..], &untracked_files[..]].concat(); + let full_paths = { + let mut full_paths: Vec<PathBuf> = 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 }) + .collect(); + full_paths.dedup(); + full_paths.sort_unstable(); + full_paths + }; + Ok(full_paths) +} + +fn collect_tests_from_dir( + config: Arc<Config>, + cache: &HeadersCache, + dir: &Path, + relative_dir_path: &Path, + inputs: &Stamp, + tests: &mut Vec<test::TestDescAndFn>, + found_paths: &mut BTreeSet<PathBuf>, + modified_tests: &Vec<PathBuf>, + poisoned: &mut bool, +) -> io::Result<()> { + // Ignore directories that contain a file named `compiletest-ignore-dir`. + if dir.join("compiletest-ignore-dir").exists() { + return Ok(()); + } + + if config.mode == Mode::RunMake && dir.join("Makefile").exists() { + let paths = TestPaths { + file: dir.to_path_buf(), + relative_dir: relative_dir_path.parent().unwrap().to_path_buf(), + }; + tests.extend(make_test(config, cache, &paths, inputs, poisoned)); + return Ok(()); + } + + // If we find a test foo/bar.rs, we have to build the + // output directory `$build/foo` so we can write + // `$build/foo/bar` into it. We do this *now* in this + // sequential loop because otherwise, if we do it in the + // tests themselves, they race for the privilege of + // creating the directories and sometimes fail randomly. + let build_dir = output_relative_path(&config, relative_dir_path); + fs::create_dir_all(&build_dir).unwrap(); + + // Add each `.rs` file as a test, and recurse further on any + // subdirectories we find, except for `aux` directories. + for file in fs::read_dir(dir)? { + let file = file?; + let file_path = file.path(); + let file_name = file.file_name(); + if is_test(&file_name) && (!config.only_modified || modified_tests.contains(&file_path)) { + debug!("found test file: {:?}", file_path.display()); + let rel_test_path = relative_dir_path.join(file_path.file_stem().unwrap()); + found_paths.insert(rel_test_path); + let paths = + TestPaths { file: file_path, relative_dir: relative_dir_path.to_path_buf() }; + + tests.extend(make_test(config.clone(), cache, &paths, inputs, poisoned)) + } else if file_path.is_dir() { + let relative_file_path = relative_dir_path.join(file.file_name()); + if &file_name != "auxiliary" { + debug!("found directory: {:?}", file_path.display()); + collect_tests_from_dir( + config.clone(), + cache, + &file_path, + &relative_file_path, + inputs, + tests, + found_paths, + modified_tests, + poisoned, + )?; + } + } else { + debug!("found other file/directory: {:?}", file_path.display()); + } + } + 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(); + + if !file_name.ends_with(".rs") { + return false; + } + + // `.`, `#`, and `~` are common temp-file prefixes. + let invalid_prefixes = &[".", "#", "~"]; + !invalid_prefixes.iter().any(|p| file_name.starts_with(p)) +} + +fn make_test( + config: Arc<Config>, + cache: &HeadersCache, + testpaths: &TestPaths, + inputs: &Stamp, + poisoned: &mut bool, +) -> Vec<test::TestDescAndFn> { + let test_path = if config.mode == Mode::RunMake { + // Parse directives in the Makefile + testpaths.file.join("Makefile") + } else { + PathBuf::from(&testpaths.file) + }; + let early_props = EarlyProps::from_file(&config, &test_path); + + // Incremental tests are special, they inherently cannot be run in parallel. + // `runtest::run` will be responsible for iterating over revisions. + let revisions = if early_props.revisions.is_empty() || config.mode == Mode::Incremental { + vec![None] + } else { + early_props.revisions.iter().map(Some).collect() + }; + + revisions + .into_iter() + .map(|revision| { + let src_file = + std::fs::File::open(&test_path).expect("open test file to parse ignores"); + let cfg = revision.map(|v| &**v); + let test_name = crate::make_test_name(&config, testpaths, revision); + let mut desc = make_test_description( + &config, cache, test_name, &test_path, src_file, cfg, poisoned, + ); + // Ignore tests that already run and are up to date with respect to inputs. + if !config.force_rerun { + desc.ignore |= is_up_to_date( + &config, + testpaths, + &early_props, + revision.map(|s| s.as_str()), + inputs, + ); + } + test::TestDescAndFn { + desc, + testfn: make_test_closure(config.clone(), testpaths, revision), + } + }) + .collect() +} + +fn stamp(config: &Config, testpaths: &TestPaths, revision: Option<&str>) -> PathBuf { + output_base_dir(config, testpaths, revision).join("stamp") +} + +fn files_related_to_test( + config: &Config, + testpaths: &TestPaths, + props: &EarlyProps, + revision: Option<&str>, +) -> Vec<PathBuf> { + let mut related = vec![]; + + if testpaths.file.is_dir() { + // run-make tests use their individual directory + for entry in WalkDir::new(&testpaths.file) { + let path = entry.unwrap().into_path(); + if path.is_file() { + related.push(path); + } + } + } else { + related.push(testpaths.file.clone()); + } + + for aux in &props.aux { + let path = testpaths.file.parent().unwrap().join("auxiliary").join(aux); + related.push(path); + } + + // UI test files. + for extension in UI_EXTENSIONS { + let path = expected_output_path(testpaths, revision, &config.compare_mode, extension); + related.push(path); + } + + related +} + +fn is_up_to_date( + config: &Config, + testpaths: &TestPaths, + props: &EarlyProps, + revision: Option<&str>, + inputs: &Stamp, +) -> bool { + let stamp_name = stamp(config, testpaths, revision); + // Check hash. + let contents = match fs::read_to_string(&stamp_name) { + Ok(f) => f, + Err(ref e) if e.kind() == ErrorKind::InvalidData => panic!("Can't read stamp contents"), + Err(_) => return false, + }; + let expected_hash = runtest::compute_stamp_hash(config); + if contents != expected_hash { + return false; + } + + // Check timestamps. + let mut inputs = inputs.clone(); + for path in files_related_to_test(config, testpaths, props, revision) { + inputs.add_path(&path); + } + + inputs < Stamp::from_path(&stamp_name) +} + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +struct Stamp { + time: SystemTime, +} + +impl Stamp { + fn from_path(path: &Path) -> Self { + let mut stamp = Stamp { time: SystemTime::UNIX_EPOCH }; + stamp.add_path(path); + stamp + } + + fn add_path(&mut self, path: &Path) { + let modified = fs::metadata(path) + .and_then(|metadata| metadata.modified()) + .unwrap_or(SystemTime::UNIX_EPOCH); + self.time = self.time.max(modified); + } + + fn add_dir(&mut self, path: &Path) { + for entry in WalkDir::new(path) { + let entry = entry.unwrap(); + if entry.file_type().is_file() { + let modified = entry + .metadata() + .ok() + .and_then(|metadata| metadata.modified().ok()) + .unwrap_or(SystemTime::UNIX_EPOCH); + self.time = self.time.max(modified); + } + } + } +} + +fn make_test_name( + config: &Config, + testpaths: &TestPaths, + revision: Option<&String>, +) -> test::TestName { + // Print the name of the file, relative to the repository root. + // `src_base` looks like `/path/to/rust/tests/ui` + let root_directory = config.src_base.parent().unwrap().parent().unwrap(); + let path = testpaths.file.strip_prefix(root_directory).unwrap(); + let debugger = match config.debugger { + Some(d) => format!("-{}", d), + None => String::new(), + }; + let mode_suffix = match config.compare_mode { + Some(ref mode) => format!(" ({})", mode.to_str()), + None => String::new(), + }; + + test::DynTestName(format!( + "[{}{}{}] {}{}", + config.mode, + debugger, + mode_suffix, + path.display(), + revision.map_or("".to_string(), |rev| format!("#{}", rev)) + )) +} + +fn make_test_closure( + config: Arc<Config>, + testpaths: &TestPaths, + revision: Option<&String>, +) -> test::TestFn { + let config = config.clone(); + let testpaths = testpaths.clone(); + let revision = revision.cloned(); + test::DynTestFn(Box::new(move || { + runtest::run(config, &testpaths, revision.as_deref()); + Ok(()) + })) +} + +/// Returns `true` if the given target is an Android target for the +/// purposes of GDB testing. +fn is_android_gdb_target(target: &str) -> bool { + matches!( + &target[..], + "arm-linux-androideabi" | "armv7-linux-androideabi" | "aarch64-linux-android" + ) +} + +/// Returns `true` if the given target is a MSVC target for the purpouses of CDB testing. +fn is_pc_windows_msvc_target(target: &str) -> bool { + target.ends_with("-pc-windows-msvc") +} + +fn find_cdb(target: &str) -> Option<OsString> { + 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 cdb_arch = if cfg!(target_arch = "x86") { + "x86" + } else if cfg!(target_arch = "x86_64") { + "x64" + } else if cfg!(target_arch = "aarch64") { + "arm64" + } else if cfg!(target_arch = "arm") { + "arm" + } else { + return None; // No compatible CDB.exe in the Windows 10 SDK + }; + + let mut path = PathBuf::new(); + path.push(pf86); + path.push(r"Windows Kits\10\Debuggers"); // We could check 8.1 etc. too? + path.push(cdb_arch); + path.push(r"cdb.exe"); + + if !path.exists() { + return None; + } + + Some(path.into_os_string()) +} + +/// Returns Path to CDB +fn analyze_cdb(cdb: Option<String>, target: &str) -> (Option<OsString>, Option<[u16; 4]>) { + let cdb = cdb.map(OsString::from).or_else(|| find_cdb(target)); + + let mut version = None; + if let Some(cdb) = cdb.as_ref() { + if let Ok(output) = Command::new(cdb).arg("/version").output() { + if let Some(first_line) = String::from_utf8_lossy(&output.stdout).lines().next() { + version = extract_cdb_version(&first_line); + } + } + } + + (cdb, version) +} + +fn extract_cdb_version(full_version_line: &str) -> Option<[u16; 4]> { + // Example full_version_line: "cdb version 10.0.18362.1" + let version = full_version_line.rsplit(' ').next()?; + let mut components = version.split('.'); + let major: u16 = components.next().unwrap().parse().unwrap(); + let minor: u16 = components.next().unwrap().parse().unwrap(); + let patch: u16 = components.next().unwrap_or("0").parse().unwrap(); + let build: u16 = components.next().unwrap_or("0").parse().unwrap(); + Some([major, minor, patch, build]) +} + +/// Returns (Path to GDB, GDB Version, GDB has Rust Support) +fn analyze_gdb( + gdb: Option<String>, + target: &str, + android_cross_path: &PathBuf, +) -> (Option<String>, Option<u32>, bool) { + #[cfg(not(windows))] + const GDB_FALLBACK: &str = "gdb"; + #[cfg(windows)] + const GDB_FALLBACK: &str = "gdb.exe"; + + const MIN_GDB_WITH_RUST: u32 = 7011010; + + 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"), + }; + gdb_path.push_str("/bin/gdb"); + gdb_path + } else { + GDB_FALLBACK.to_owned() + } + }; + + let gdb = match gdb { + None => fallback_gdb(), + Some(ref s) if s.is_empty() => fallback_gdb(), // may be empty if configure found no gdb + Some(ref s) => s.to_owned(), + }; + + let mut version_line = None; + if let Ok(output) = Command::new(&gdb).arg("--version").output() { + if let Some(first_line) = String::from_utf8_lossy(&output.stdout).lines().next() { + version_line = Some(first_line.to_string()); + } + } + + let version = match version_line { + Some(line) => extract_gdb_version(&line), + None => return (None, None, false), + }; + + let gdb_native_rust = version.map_or(false, |v| v >= MIN_GDB_WITH_RUST); + + (Some(gdb), version, gdb_native_rust) +} + +fn extract_gdb_version(full_version_line: &str) -> Option<u32> { + let full_version_line = full_version_line.trim(); + + // GDB versions look like this: "major.minor.patch?.yyyymmdd?", with both + // of the ? sections being optional + + // We will parse up to 3 digits for each component, ignoring the date + + // We skip text in parentheses. This avoids accidentally parsing + // the openSUSE version, which looks like: + // GNU gdb (GDB; openSUSE Leap 15.0) 8.1 + // This particular form is documented in the GNU coding standards: + // https://www.gnu.org/prep/standards/html_node/_002d_002dversion.html#g_t_002d_002dversion + + let unbracketed_part = full_version_line.split('[').next().unwrap(); + let mut splits = unbracketed_part.trim_end().rsplit(' '); + let version_string = splits.next().unwrap(); + + let mut splits = version_string.split('.'); + let major = splits.next().unwrap(); + let minor = splits.next().unwrap(); + let patch = splits.next(); + + let major: u32 = major.parse().unwrap(); + let (minor, patch): (u32, u32) = match minor.find(not_a_digit) { + None => { + let minor = minor.parse().unwrap(); + let patch: u32 = match patch { + Some(patch) => match patch.find(not_a_digit) { + None => patch.parse().unwrap(), + Some(idx) if idx > 3 => 0, + Some(idx) => patch[..idx].parse().unwrap(), + }, + None => 0, + }; + (minor, patch) + } + // There is no patch version after minor-date (e.g. "4-2012"). + Some(idx) => { + let minor = minor[..idx].parse().unwrap(); + (minor, 0) + } + }; + + Some(((major * 1000) + minor) * 1000 + patch) +} + +/// Returns (LLDB version, LLDB is rust-enabled) +fn extract_lldb_version(full_version_line: &str) -> Option<(u32, bool)> { + // Extract the major LLDB version from the given version string. + // LLDB version strings are different for Apple and non-Apple platforms. + // The Apple variant looks like this: + // + // LLDB-179.5 (older versions) + // lldb-300.2.51 (new versions) + // + // We are only interested in the major version number, so this function + // will return `Some(179)` and `Some(300)` respectively. + // + // Upstream versions look like: + // lldb version 6.0.1 + // + // There doesn't seem to be a way to correlate the Apple version + // with the upstream version, and since the tests were originally + // written against Apple versions, we make a fake Apple version by + // multiplying the first number by 100. This is a hack, but + // normally fine because the only non-Apple version we test is + // rust-enabled. + + let full_version_line = full_version_line.trim(); + + if let Some(apple_ver) = + full_version_line.strip_prefix("LLDB-").or_else(|| full_version_line.strip_prefix("lldb-")) + { + if let Some(idx) = apple_ver.find(not_a_digit) { + let version: u32 = apple_ver[..idx].parse().unwrap(); + return Some((version, full_version_line.contains("rust-enabled"))); + } + } else if let Some(lldb_ver) = full_version_line.strip_prefix("lldb version ") { + if let Some(idx) = lldb_ver.find(not_a_digit) { + let version: u32 = lldb_ver[..idx].parse().ok()?; + return Some((version * 100, full_version_line.contains("rust-enabled"))); + } + } + None +} + +fn not_a_digit(c: char) -> bool { + !c.is_digit(10) +} + +fn check_overlapping_tests(found_paths: &BTreeSet<PathBuf>) { + let mut collisions = Vec::new(); + for path in found_paths { + for ancestor in path.ancestors().skip(1) { + if found_paths.contains(ancestor) { + collisions.push((path, ancestor.clone())); + } + } + } + if !collisions.is_empty() { + let collisions: String = collisions + .into_iter() + .map(|(path, check_parent)| format!("test {path:?} clashes with {check_parent:?}\n")) + .collect(); + panic!( + "{collisions}\n\ + Tests cannot have overlapping names. Make sure they use unique prefixes." + ); + } +} diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index c4bef998f31..34d48559c37 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -1,45 +1,6 @@ -#![crate_name = "compiletest"] -// The `test` crate is the only unstable feature -// allowed here, just to share similar code. -#![feature(test)] +use std::{env, sync::Arc}; -extern crate test; - -use crate::common::{expected_output_path, output_base_dir, output_relative_path, UI_EXTENSIONS}; -use crate::common::{Config, Debugger, Mode, PassMode, TestPaths}; -use crate::util::logv; -use build_helper::git::{get_git_modified_files, get_git_untracked_files}; -use core::panic; -use getopts::Options; -use lazycell::AtomicLazyCell; -use std::collections::BTreeSet; -use std::ffi::OsString; -use std::fs; -use std::io::{self, ErrorKind}; -use std::path::{Path, PathBuf}; -use std::process::{Command, Stdio}; -use std::time::SystemTime; -use std::{env, vec}; -use test::ColorConfig; -use tracing::*; -use walkdir::WalkDir; - -use self::header::{make_test_description, EarlyProps}; -use crate::header::HeadersCache; -use std::sync::Arc; - -#[cfg(test)] -mod tests; - -pub mod common; -pub mod compute_diff; -pub mod errors; -pub mod header; -mod json; -mod raise_fd_limit; -mod read2; -pub mod runtest; -pub mod util; +use compiletest::{common::Mode, log_config, parse_config, run_tests}; fn main() { tracing_subscriber::fmt::init(); @@ -57,1097 +18,3 @@ fn main() { log_config(&config); run_tests(config); } - -pub fn parse_config(args: Vec<String>) -> Config { - let mut opts = Options::new(); - opts.reqopt("", "compile-lib-path", "path to host shared libraries", "PATH") - .reqopt("", "run-lib-path", "path to target shared libraries", "PATH") - .reqopt("", "rustc-path", "path to rustc to use for compiling", "PATH") - .optopt("", "rustdoc-path", "path to rustdoc to use for compiling", "PATH") - .optopt("", "rust-demangler-path", "path to rust-demangler to use in tests", "PATH") - .reqopt("", "python", "path to python to use for doc tests", "PATH") - .optopt("", "jsondocck-path", "path to jsondocck to use for doc tests", "PATH") - .optopt("", "jsondoclint-path", "path to jsondoclint to use for doc tests", "PATH") - .optopt("", "valgrind-path", "path to Valgrind executable for Valgrind tests", "PROGRAM") - .optflag("", "force-valgrind", "fail if Valgrind tests cannot be run under Valgrind") - .optopt("", "run-clang-based-tests-with", "path to Clang executable", "PATH") - .optopt("", "llvm-filecheck", "path to LLVM's FileCheck binary", "DIR") - .reqopt("", "src-base", "directory to scan for test files", "PATH") - .reqopt("", "build-base", "directory to deposit test outputs", "PATH") - .reqopt("", "sysroot-base", "directory containing the compiler sysroot", "PATH") - .reqopt("", "stage-id", "the target-stage identifier", "stageN-TARGET") - .reqopt( - "", - "mode", - "which sort of compile tests to run", - "run-pass-valgrind | pretty | debug-info | codegen | rustdoc \ - | rustdoc-json | codegen-units | incremental | run-make | ui | js-doc-test | mir-opt | assembly", - ) - .reqopt( - "", - "suite", - "which suite of compile tests to run. used for nicer error reporting.", - "SUITE", - ) - .optopt( - "", - "pass", - "force {check,build,run}-pass tests to this mode.", - "check | build | run", - ) - .optopt("", "run", "whether to execute run-* tests", "auto | always | never") - .optflag("", "ignored", "run tests marked as ignored") - .optmulti("", "skip", "skip tests matching SUBSTRING. Can be passed multiple times", "SUBSTRING") - .optflag("", "exact", "filters match exactly") - .optopt( - "", - "runtool", - "supervisor program to run tests under \ - (eg. emulator, valgrind)", - "PROGRAM", - ) - .optmulti("", "host-rustcflags", "flags to pass to rustc for host", "FLAGS") - .optmulti("", "target-rustcflags", "flags to pass to rustc for target", "FLAGS") - .optflag("", "optimize-tests", "run tests with optimizations enabled") - .optflag("", "verbose", "run tests verbosely, showing all output") - .optflag( - "", - "bless", - "overwrite stderr/stdout files instead of complaining about a mismatch", - ) - .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") - .optopt("", "gdb", "path to GDB to use for GDB debuginfo tests", "PATH") - .optopt("", "lldb-version", "the version of LLDB used", "VERSION STRING") - .optopt("", "llvm-version", "the version of LLVM used", "VERSION STRING") - .optflag("", "system-llvm", "is LLVM the system LLVM") - .optopt("", "android-cross-path", "Android NDK standalone path", "PATH") - .optopt("", "adb-path", "path to the android debugger", "PATH") - .optopt("", "adb-test-dir", "path to tests for the android debugger", "PATH") - .optopt("", "lldb-python-dir", "directory containing LLDB's python module", "PATH") - .reqopt("", "cc", "path to a C compiler", "PATH") - .reqopt("", "cxx", "path to a C++ compiler", "PATH") - .reqopt("", "cflags", "flags for the C compiler", "FLAGS") - .reqopt("", "cxxflags", "flags for the CXX compiler", "FLAGS") - .optopt("", "ar", "path to an archiver", "PATH") - .optopt("", "target-linker", "path to a linker for the target", "PATH") - .optopt("", "host-linker", "path to a linker for the host", "PATH") - .reqopt("", "llvm-components", "list of LLVM components built in", "LIST") - .optopt("", "llvm-bin-dir", "Path to LLVM's `bin` directory", "PATH") - .optopt("", "nodejs", "the name of nodejs", "PATH") - .optopt("", "npm", "the name of npm", "PATH") - .optopt("", "remote-test-client", "path to the remote test client", "PATH") - .optopt( - "", - "compare-mode", - "mode describing what file the actual ui output will be compared to", - "COMPARE MODE", - ) - .optflag( - "", - "rustfix-coverage", - "enable this to generate a Rustfix coverage file, which is saved in \ - `./<build_base>/rustfix_missing_coverage.txt`", - ) - .optflag("", "force-rerun", "rerun tests even if the inputs are unchanged") - .optflag("", "only-modified", "only run tests that result been modified") - .optflag("", "nocapture", "") - .optflag("h", "help", "show this message") - .reqopt("", "channel", "current Rust channel", "CHANNEL") - .optflag("", "git-hash", "run tests which rely on commit version being compiled into the binaries") - .optopt("", "edition", "default Rust edition", "EDITION"); - - let (argv0, args_) = args.split_first().unwrap(); - if args.len() == 1 || args[1] == "-h" || args[1] == "--help" { - let message = format!("Usage: {} [OPTIONS] [TESTNAME...]", argv0); - println!("{}", opts.usage(&message)); - println!(); - panic!() - } - - let matches = &match opts.parse(args_) { - Ok(m) => m, - Err(f) => panic!("{:?}", f), - }; - - if matches.opt_present("h") || matches.opt_present("help") { - let message = format!("Usage: {} [OPTIONS] [TESTNAME...]", argv0); - println!("{}", opts.usage(&message)); - println!(); - 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: PathBuf) -> PathBuf { - if path.is_relative() { env::current_dir().unwrap().join(path) } else { path } - } - - let target = opt_str2(matches.opt_str("target")); - let android_cross_path = opt_path(matches, "android-cross-path"); - let (cdb, cdb_version) = analyze_cdb(matches.opt_str("cdb"), &target); - let (gdb, gdb_version, gdb_native_rust) = - analyze_gdb(matches.opt_str("gdb"), &target, &android_cross_path); - let (lldb_version, lldb_native_rust) = matches - .opt_str("lldb-version") - .as_deref() - .and_then(extract_lldb_version) - .map(|(v, b)| (Some(v), b)) - .unwrap_or((None, false)); - let color = match matches.opt_str("color").as_deref() { - Some("auto") | None => ColorConfig::AutoColor, - Some("always") => ColorConfig::AlwaysColor, - Some("never") => ColorConfig::NeverColor, - Some(x) => panic!("argument for --color must be auto, always, or never, but found `{}`", x), - }; - let llvm_version = - matches.opt_str("llvm-version").as_deref().and_then(header::extract_llvm_version).or_else( - || header::extract_llvm_version_from_binary(&matches.opt_str("llvm-filecheck")?), - ); - - let src_base = opt_path(matches, "src-base"); - let run_ignored = matches.opt_present("ignored"); - let mode = matches.opt_str("mode").unwrap().parse().expect("invalid mode"); - let has_tidy = if mode == Mode::Rustdoc { - Command::new("tidy") - .arg("--version") - .stdout(Stdio::null()) - .status() - .map_or(false, |status| status.success()) - } else { - // Avoid spawning an external command when we know tidy won't be used. - false - }; - Config { - bless: matches.opt_present("bless"), - 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"), - rustdoc_path: matches.opt_str("rustdoc-path").map(PathBuf::from), - rust_demangler_path: matches.opt_str("rust-demangler-path").map(PathBuf::from), - python: matches.opt_str("python").unwrap(), - jsondocck_path: matches.opt_str("jsondocck-path"), - jsondoclint_path: matches.opt_str("jsondoclint-path"), - valgrind_path: matches.opt_str("valgrind-path"), - force_valgrind: matches.opt_present("force-valgrind"), - 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), - src_base, - build_base: opt_path(matches, "build-base"), - sysroot_base: opt_path(matches, "sysroot-base"), - stage_id: matches.opt_str("stage-id").unwrap(), - mode, - suite: matches.opt_str("suite").unwrap(), - debugger: None, - run_ignored, - filters: matches.free.clone(), - skip: matches.opt_strs("skip"), - filter_exact: matches.opt_present("exact"), - force_pass_mode: matches.opt_str("pass").map(|mode| { - mode.parse::<PassMode>() - .unwrap_or_else(|_| panic!("unknown `--pass` option `{}` given", mode)) - }), - run: matches.opt_str("run").and_then(|mode| match mode.as_str() { - "auto" => None, - "always" => Some(true), - "never" => Some(false), - _ => panic!("unknown `--run` option `{}` given", mode), - }), - logfile: matches.opt_str("logfile").map(|s| PathBuf::from(&s)), - runtool: matches.opt_str("runtool"), - host_rustcflags: matches.opt_strs("host-rustcflags"), - target_rustcflags: matches.opt_strs("target-rustcflags"), - optimize_tests: matches.opt_present("optimize-tests"), - target, - host: opt_str2(matches.opt_str("host")), - cdb, - cdb_version, - gdb, - gdb_version, - gdb_native_rust, - lldb_version, - lldb_native_rust, - llvm_version, - system_llvm: matches.opt_present("system-llvm"), - android_cross_path, - adb_path: opt_str2(matches.opt_str("adb-path")), - adb_test_dir: opt_str2(matches.opt_str("adb-test-dir")), - adb_device_status: opt_str2(matches.opt_str("target")).contains("android") - && "(none)" != opt_str2(matches.opt_str("adb-test-dir")) - && !opt_str2(matches.opt_str("adb-test-dir")).is_empty(), - lldb_python_dir: matches.opt_str("lldb-python-dir"), - verbose: matches.opt_present("verbose"), - format: match (matches.opt_present("quiet"), matches.opt_present("json")) { - (true, true) => panic!("--quiet and --json are incompatible"), - (true, false) => test::OutputFormat::Terse, - (false, true) => test::OutputFormat::Json, - (false, false) => test::OutputFormat::Pretty, - }, - only_modified: matches.opt_present("only-modified"), - color, - remote_test_client: matches.opt_str("remote-test-client").map(PathBuf::from), - compare_mode: matches - .opt_str("compare-mode") - .map(|s| s.parse().expect("invalid --compare-mode provided")), - rustfix_coverage: matches.opt_present("rustfix-coverage"), - has_tidy, - channel: matches.opt_str("channel").unwrap(), - git_hash: matches.opt_present("git-hash"), - edition: matches.opt_str("edition"), - - cc: matches.opt_str("cc").unwrap(), - cxx: matches.opt_str("cxx").unwrap(), - cflags: matches.opt_str("cflags").unwrap(), - cxxflags: matches.opt_str("cxxflags").unwrap(), - ar: matches.opt_str("ar").unwrap_or_else(|| String::from("ar")), - target_linker: matches.opt_str("target-linker"), - host_linker: matches.opt_str("host-linker"), - llvm_components: matches.opt_str("llvm-components").unwrap(), - nodejs: matches.opt_str("nodejs"), - npm: matches.opt_str("npm"), - - force_rerun: matches.opt_present("force-rerun"), - - target_cfgs: AtomicLazyCell::new(), - - nocapture: matches.opt_present("nocapture"), - } -} - -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!("rustdoc_path: {:?}", config.rustdoc_path)); - logv(c, format!("rust_demangler_path: {:?}", config.rust_demangler_path)); - logv(c, format!("src_base: {:?}", config.src_base.display())); - logv(c, format!("build_base: {:?}", config.build_base.display())); - logv(c, format!("stage_id: {}", config.stage_id)); - logv(c, format!("mode: {}", config.mode)); - logv(c, format!("run_ignored: {}", config.run_ignored)); - logv(c, format!("filters: {:?}", config.filters)); - logv(c, format!("skip: {:?}", config.skip)); - logv(c, format!("filter_exact: {}", config.filter_exact)); - logv( - c, - format!("force_pass_mode: {}", opt_str(&config.force_pass_mode.map(|m| format!("{}", m))),), - ); - logv(c, format!("runtool: {}", opt_str(&config.runtool))); - logv(c, format!("host-rustcflags: {:?}", config.host_rustcflags)); - 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!("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, "\n".to_string()); -} - -pub fn opt_str(maybestr: &Option<String>) -> &str { - match *maybestr { - None => "(none)", - Some(ref s) => s, - } -} - -pub fn opt_str2(maybestr: Option<String>) -> String { - match maybestr { - None => "(none)".to_owned(), - Some(s) => s, - } -} - -pub fn run_tests(config: Arc<Config>) { - // If we want to collect rustfix coverage information, - // we first make sure that the coverage file does not exist. - // It will be created later on. - if config.rustfix_coverage { - let mut coverage_file_path = config.build_base.clone(); - 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) - } - } - } - - // sadly osx needs some file descriptor limits raised for running tests in - // parallel (especially when we have lots and lots of child processes). - // For context, see #8904 - unsafe { - raise_fd_limit::raise_fd_limit(); - } - // 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"); - - // Let tests know which target they're running as - env::set_var("TARGET", &config.target); - - let opts = test_opts(&config); - - let mut configs = Vec::new(); - if let Mode::DebugInfo = config.mode { - // Debugging emscripten code doesn't make sense today - if !config.target.contains("emscripten") { - configs.extend(configure_cdb(&config)); - configs.extend(configure_gdb(&config)); - configs.extend(configure_lldb(&config)); - } - } else { - configs.push(config.clone()); - }; - - let mut tests = Vec::new(); - for c in configs { - let mut found_paths = BTreeSet::new(); - make_tests(c, &mut tests, &mut found_paths); - check_overlapping_tests(&found_paths); - } - - tests.sort_by(|a, b| a.desc.name.as_slice().cmp(&b.desc.name.as_slice())); - - let res = test::run_tests_console(&opts, tests); - match res { - Ok(true) => {} - Ok(false) => { - // We want to report that the tests failed, but we also want to give - // some indication of just what tests we were running. Especially on - // CI, where there can be cross-compiled tests for a lot of - // architectures, without this critical information it can be quite - // easy to miss which tests failed, and as such fail to reproduce - // the failure locally. - - println!( - "Some tests failed in compiletest suite={}{} mode={} host={} target={}", - config.suite, - config - .compare_mode - .as_ref() - .map(|c| format!(" compare_mode={:?}", c)) - .unwrap_or_default(), - config.mode, - config.host, - config.target - ); - - std::process::exit(1); - } - Err(e) => { - // We don't know if tests passed or not, but if there was an error - // during testing we don't want to just succeed (we may not have - // tested something), so fail. - // - // This should realistically "never" happen, so don't try to make - // this a pretty error message. - panic!("I/O failure during tests: {:?}", e); - } - } -} - -fn configure_cdb(config: &Config) -> Option<Arc<Config>> { - config.cdb.as_ref()?; - - Some(Arc::new(Config { debugger: Some(Debugger::Cdb), ..config.clone() })) -} - -fn configure_gdb(config: &Config) -> Option<Arc<Config>> { - config.gdb_version?; - - if config.matches_env("msvc") { - return None; - } - - if config.remote_test_client.is_some() && !config.target.contains("android") { - println!( - "WARNING: debuginfo tests are not available when \ - testing with remote" - ); - return None; - } - - if config.target.contains("android") { - println!( - "{} debug-info test uses tcp 5039 port.\ - please reserve it", - config.target - ); - - // android debug-info test uses remote debugger so, we test 1 thread - // at once as they're all sharing the same TCP port to communicate - // over. - // - // we should figure out how to lift this restriction! (run them all - // on different ports allocated dynamically). - env::set_var("RUST_TEST_THREADS", "1"); - } - - Some(Arc::new(Config { debugger: Some(Debugger::Gdb), ..config.clone() })) -} - -fn configure_lldb(config: &Config) -> Option<Arc<Config>> { - config.lldb_python_dir.as_ref()?; - - if let Some(350) = config.lldb_version { - println!( - "WARNING: The used version of LLDB (350) has a \ - known issue that breaks debuginfo tests. See \ - issue #32520 for more information. Skipping all \ - LLDB-based tests!", - ); - return None; - } - - Some(Arc::new(Config { debugger: Some(Debugger::Lldb), ..config.clone() })) -} - -pub fn test_opts(config: &Config) -> test::TestOpts { - if env::var("RUST_TEST_NOCAPTURE").is_ok() { - eprintln!( - "WARNING: RUST_TEST_NOCAPTURE is no longer used. \ - Use the `--nocapture` flag instead." - ); - } - - 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, - logfile: config.logfile.clone(), - run_tests: true, - bench_benchmarks: true, - nocapture: config.nocapture, - color: config.color, - 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: std::env::var_os("RUSTC_TEST_FAIL_FAST").is_some(), - } -} - -pub fn make_tests( - config: Arc<Config>, - tests: &mut Vec<test::TestDescAndFn>, - found_paths: &mut BTreeSet<PathBuf>, -) { - debug!("making tests from {:?}", config.src_base.display()); - let inputs = common_inputs_stamp(&config); - let modified_tests = modified_tests(&config, &config.src_base).unwrap_or_else(|err| { - panic!("modified_tests got error from dir: {}, error: {}", config.src_base.display(), err) - }); - - let cache = HeadersCache::load(&config); - let mut poisoned = false; - collect_tests_from_dir( - config.clone(), - &cache, - &config.src_base, - &PathBuf::new(), - &inputs, - tests, - found_paths, - &modified_tests, - &mut poisoned, - ) - .unwrap_or_else(|_| panic!("Could not read tests from {}", config.src_base.display())); - - if poisoned { - eprintln!(); - panic!("there are errors in tests"); - } -} - -/// Returns a stamp constructed from input files common to all test cases. -fn common_inputs_stamp(config: &Config) -> Stamp { - let rust_src_dir = config.find_rust_src_root().expect("Could not find Rust source root"); - - let mut stamp = Stamp::from_path(&config.rustc_path); - - // Relevant pretty printer files - let pretty_printer_files = [ - "src/etc/rust_types.py", - "src/etc/gdb_load_rust_pretty_printers.py", - "src/etc/gdb_lookup.py", - "src/etc/gdb_providers.py", - "src/etc/lldb_batchmode.py", - "src/etc/lldb_lookup.py", - "src/etc/lldb_providers.py", - ]; - for file in &pretty_printer_files { - let path = rust_src_dir.join(file); - stamp.add_path(&path); - } - - stamp.add_dir(&rust_src_dir.join("src/etc/natvis")); - - stamp.add_dir(&config.run_lib_path); - - if let Some(ref rustdoc_path) = config.rustdoc_path { - stamp.add_path(&rustdoc_path); - stamp.add_path(&rust_src_dir.join("src/etc/htmldocck.py")); - } - - // Compiletest itself. - stamp.add_dir(&rust_src_dir.join("src/tools/compiletest/")); - - stamp -} - -fn modified_tests(config: &Config, dir: &Path) -> Result<Vec<PathBuf>, String> { - if !config.only_modified { - return Ok(vec![]); - } - let files = - get_git_modified_files(Some(dir), &vec!["rs", "stderr", "fixed"])?.unwrap_or(vec![]); - // Add new test cases to the list, it will be convenient in daily development. - let untracked_files = get_git_untracked_files(None)?.unwrap_or(vec![]); - - let all_paths = [&files[..], &untracked_files[..]].concat(); - let full_paths = { - let mut full_paths: Vec<PathBuf> = 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 }) - .collect(); - full_paths.dedup(); - full_paths.sort_unstable(); - full_paths - }; - Ok(full_paths) -} - -fn collect_tests_from_dir( - config: Arc<Config>, - cache: &HeadersCache, - dir: &Path, - relative_dir_path: &Path, - inputs: &Stamp, - tests: &mut Vec<test::TestDescAndFn>, - found_paths: &mut BTreeSet<PathBuf>, - modified_tests: &Vec<PathBuf>, - poisoned: &mut bool, -) -> io::Result<()> { - // Ignore directories that contain a file named `compiletest-ignore-dir`. - if dir.join("compiletest-ignore-dir").exists() { - return Ok(()); - } - - if config.mode == Mode::RunMake && dir.join("Makefile").exists() { - let paths = TestPaths { - file: dir.to_path_buf(), - relative_dir: relative_dir_path.parent().unwrap().to_path_buf(), - }; - tests.extend(make_test(config, cache, &paths, inputs, poisoned)); - return Ok(()); - } - - // If we find a test foo/bar.rs, we have to build the - // output directory `$build/foo` so we can write - // `$build/foo/bar` into it. We do this *now* in this - // sequential loop because otherwise, if we do it in the - // tests themselves, they race for the privilege of - // creating the directories and sometimes fail randomly. - let build_dir = output_relative_path(&config, relative_dir_path); - fs::create_dir_all(&build_dir).unwrap(); - - // Add each `.rs` file as a test, and recurse further on any - // subdirectories we find, except for `aux` directories. - for file in fs::read_dir(dir)? { - let file = file?; - let file_path = file.path(); - let file_name = file.file_name(); - if is_test(&file_name) && (!config.only_modified || modified_tests.contains(&file_path)) { - debug!("found test file: {:?}", file_path.display()); - let rel_test_path = relative_dir_path.join(file_path.file_stem().unwrap()); - found_paths.insert(rel_test_path); - let paths = - TestPaths { file: file_path, relative_dir: relative_dir_path.to_path_buf() }; - - tests.extend(make_test(config.clone(), cache, &paths, inputs, poisoned)) - } else if file_path.is_dir() { - let relative_file_path = relative_dir_path.join(file.file_name()); - if &file_name != "auxiliary" { - debug!("found directory: {:?}", file_path.display()); - collect_tests_from_dir( - config.clone(), - cache, - &file_path, - &relative_file_path, - inputs, - tests, - found_paths, - modified_tests, - poisoned, - )?; - } - } else { - debug!("found other file/directory: {:?}", file_path.display()); - } - } - 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(); - - if !file_name.ends_with(".rs") { - return false; - } - - // `.`, `#`, and `~` are common temp-file prefixes. - let invalid_prefixes = &[".", "#", "~"]; - !invalid_prefixes.iter().any(|p| file_name.starts_with(p)) -} - -fn make_test( - config: Arc<Config>, - cache: &HeadersCache, - testpaths: &TestPaths, - inputs: &Stamp, - poisoned: &mut bool, -) -> Vec<test::TestDescAndFn> { - let test_path = if config.mode == Mode::RunMake { - // Parse directives in the Makefile - testpaths.file.join("Makefile") - } else { - PathBuf::from(&testpaths.file) - }; - let early_props = EarlyProps::from_file(&config, &test_path); - - // Incremental tests are special, they inherently cannot be run in parallel. - // `runtest::run` will be responsible for iterating over revisions. - let revisions = if early_props.revisions.is_empty() || config.mode == Mode::Incremental { - vec![None] - } else { - early_props.revisions.iter().map(Some).collect() - }; - - revisions - .into_iter() - .map(|revision| { - let src_file = - std::fs::File::open(&test_path).expect("open test file to parse ignores"); - let cfg = revision.map(|v| &**v); - let test_name = crate::make_test_name(&config, testpaths, revision); - let mut desc = make_test_description( - &config, cache, test_name, &test_path, src_file, cfg, poisoned, - ); - // Ignore tests that already run and are up to date with respect to inputs. - if !config.force_rerun { - desc.ignore |= is_up_to_date( - &config, - testpaths, - &early_props, - revision.map(|s| s.as_str()), - inputs, - ); - } - test::TestDescAndFn { - desc, - testfn: make_test_closure(config.clone(), testpaths, revision), - } - }) - .collect() -} - -fn stamp(config: &Config, testpaths: &TestPaths, revision: Option<&str>) -> PathBuf { - output_base_dir(config, testpaths, revision).join("stamp") -} - -fn files_related_to_test( - config: &Config, - testpaths: &TestPaths, - props: &EarlyProps, - revision: Option<&str>, -) -> Vec<PathBuf> { - let mut related = vec![]; - - if testpaths.file.is_dir() { - // run-make tests use their individual directory - for entry in WalkDir::new(&testpaths.file) { - let path = entry.unwrap().into_path(); - if path.is_file() { - related.push(path); - } - } - } else { - related.push(testpaths.file.clone()); - } - - for aux in &props.aux { - let path = testpaths.file.parent().unwrap().join("auxiliary").join(aux); - related.push(path); - } - - // UI test files. - for extension in UI_EXTENSIONS { - let path = expected_output_path(testpaths, revision, &config.compare_mode, extension); - related.push(path); - } - - related -} - -fn is_up_to_date( - config: &Config, - testpaths: &TestPaths, - props: &EarlyProps, - revision: Option<&str>, - inputs: &Stamp, -) -> bool { - let stamp_name = stamp(config, testpaths, revision); - // Check hash. - let contents = match fs::read_to_string(&stamp_name) { - Ok(f) => f, - Err(ref e) if e.kind() == ErrorKind::InvalidData => panic!("Can't read stamp contents"), - Err(_) => return false, - }; - let expected_hash = runtest::compute_stamp_hash(config); - if contents != expected_hash { - return false; - } - - // Check timestamps. - let mut inputs = inputs.clone(); - for path in files_related_to_test(config, testpaths, props, revision) { - inputs.add_path(&path); - } - - inputs < Stamp::from_path(&stamp_name) -} - -#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] -struct Stamp { - time: SystemTime, -} - -impl Stamp { - fn from_path(path: &Path) -> Self { - let mut stamp = Stamp { time: SystemTime::UNIX_EPOCH }; - stamp.add_path(path); - stamp - } - - fn add_path(&mut self, path: &Path) { - let modified = fs::metadata(path) - .and_then(|metadata| metadata.modified()) - .unwrap_or(SystemTime::UNIX_EPOCH); - self.time = self.time.max(modified); - } - - fn add_dir(&mut self, path: &Path) { - for entry in WalkDir::new(path) { - let entry = entry.unwrap(); - if entry.file_type().is_file() { - let modified = entry - .metadata() - .ok() - .and_then(|metadata| metadata.modified().ok()) - .unwrap_or(SystemTime::UNIX_EPOCH); - self.time = self.time.max(modified); - } - } - } -} - -fn make_test_name( - config: &Config, - testpaths: &TestPaths, - revision: Option<&String>, -) -> test::TestName { - // Print the name of the file, relative to the repository root. - // `src_base` looks like `/path/to/rust/tests/ui` - let root_directory = config.src_base.parent().unwrap().parent().unwrap(); - let path = testpaths.file.strip_prefix(root_directory).unwrap(); - let debugger = match config.debugger { - Some(d) => format!("-{}", d), - None => String::new(), - }; - let mode_suffix = match config.compare_mode { - Some(ref mode) => format!(" ({})", mode.to_str()), - None => String::new(), - }; - - test::DynTestName(format!( - "[{}{}{}] {}{}", - config.mode, - debugger, - mode_suffix, - path.display(), - revision.map_or("".to_string(), |rev| format!("#{}", rev)) - )) -} - -fn make_test_closure( - config: Arc<Config>, - testpaths: &TestPaths, - revision: Option<&String>, -) -> test::TestFn { - let config = config.clone(); - let testpaths = testpaths.clone(); - let revision = revision.cloned(); - test::DynTestFn(Box::new(move || { - runtest::run(config, &testpaths, revision.as_deref()); - Ok(()) - })) -} - -/// Returns `true` if the given target is an Android target for the -/// purposes of GDB testing. -fn is_android_gdb_target(target: &str) -> bool { - matches!( - &target[..], - "arm-linux-androideabi" | "armv7-linux-androideabi" | "aarch64-linux-android" - ) -} - -/// Returns `true` if the given target is a MSVC target for the purpouses of CDB testing. -fn is_pc_windows_msvc_target(target: &str) -> bool { - target.ends_with("-pc-windows-msvc") -} - -fn find_cdb(target: &str) -> Option<OsString> { - 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 cdb_arch = if cfg!(target_arch = "x86") { - "x86" - } else if cfg!(target_arch = "x86_64") { - "x64" - } else if cfg!(target_arch = "aarch64") { - "arm64" - } else if cfg!(target_arch = "arm") { - "arm" - } else { - return None; // No compatible CDB.exe in the Windows 10 SDK - }; - - let mut path = PathBuf::new(); - path.push(pf86); - path.push(r"Windows Kits\10\Debuggers"); // We could check 8.1 etc. too? - path.push(cdb_arch); - path.push(r"cdb.exe"); - - if !path.exists() { - return None; - } - - Some(path.into_os_string()) -} - -/// Returns Path to CDB -fn analyze_cdb(cdb: Option<String>, target: &str) -> (Option<OsString>, Option<[u16; 4]>) { - let cdb = cdb.map(OsString::from).or_else(|| find_cdb(target)); - - let mut version = None; - if let Some(cdb) = cdb.as_ref() { - if let Ok(output) = Command::new(cdb).arg("/version").output() { - if let Some(first_line) = String::from_utf8_lossy(&output.stdout).lines().next() { - version = extract_cdb_version(&first_line); - } - } - } - - (cdb, version) -} - -fn extract_cdb_version(full_version_line: &str) -> Option<[u16; 4]> { - // Example full_version_line: "cdb version 10.0.18362.1" - let version = full_version_line.rsplit(' ').next()?; - let mut components = version.split('.'); - let major: u16 = components.next().unwrap().parse().unwrap(); - let minor: u16 = components.next().unwrap().parse().unwrap(); - let patch: u16 = components.next().unwrap_or("0").parse().unwrap(); - let build: u16 = components.next().unwrap_or("0").parse().unwrap(); - Some([major, minor, patch, build]) -} - -/// Returns (Path to GDB, GDB Version, GDB has Rust Support) -fn analyze_gdb( - gdb: Option<String>, - target: &str, - android_cross_path: &PathBuf, -) -> (Option<String>, Option<u32>, bool) { - #[cfg(not(windows))] - const GDB_FALLBACK: &str = "gdb"; - #[cfg(windows)] - const GDB_FALLBACK: &str = "gdb.exe"; - - const MIN_GDB_WITH_RUST: u32 = 7011010; - - 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"), - }; - gdb_path.push_str("/bin/gdb"); - gdb_path - } else { - GDB_FALLBACK.to_owned() - } - }; - - let gdb = match gdb { - None => fallback_gdb(), - Some(ref s) if s.is_empty() => fallback_gdb(), // may be empty if configure found no gdb - Some(ref s) => s.to_owned(), - }; - - let mut version_line = None; - if let Ok(output) = Command::new(&gdb).arg("--version").output() { - if let Some(first_line) = String::from_utf8_lossy(&output.stdout).lines().next() { - version_line = Some(first_line.to_string()); - } - } - - let version = match version_line { - Some(line) => extract_gdb_version(&line), - None => return (None, None, false), - }; - - let gdb_native_rust = version.map_or(false, |v| v >= MIN_GDB_WITH_RUST); - - (Some(gdb), version, gdb_native_rust) -} - -fn extract_gdb_version(full_version_line: &str) -> Option<u32> { - let full_version_line = full_version_line.trim(); - - // GDB versions look like this: "major.minor.patch?.yyyymmdd?", with both - // of the ? sections being optional - - // We will parse up to 3 digits for each component, ignoring the date - - // We skip text in parentheses. This avoids accidentally parsing - // the openSUSE version, which looks like: - // GNU gdb (GDB; openSUSE Leap 15.0) 8.1 - // This particular form is documented in the GNU coding standards: - // https://www.gnu.org/prep/standards/html_node/_002d_002dversion.html#g_t_002d_002dversion - - let unbracketed_part = full_version_line.split('[').next().unwrap(); - let mut splits = unbracketed_part.trim_end().rsplit(' '); - let version_string = splits.next().unwrap(); - - let mut splits = version_string.split('.'); - let major = splits.next().unwrap(); - let minor = splits.next().unwrap(); - let patch = splits.next(); - - let major: u32 = major.parse().unwrap(); - let (minor, patch): (u32, u32) = match minor.find(not_a_digit) { - None => { - let minor = minor.parse().unwrap(); - let patch: u32 = match patch { - Some(patch) => match patch.find(not_a_digit) { - None => patch.parse().unwrap(), - Some(idx) if idx > 3 => 0, - Some(idx) => patch[..idx].parse().unwrap(), - }, - None => 0, - }; - (minor, patch) - } - // There is no patch version after minor-date (e.g. "4-2012"). - Some(idx) => { - let minor = minor[..idx].parse().unwrap(); - (minor, 0) - } - }; - - Some(((major * 1000) + minor) * 1000 + patch) -} - -/// Returns (LLDB version, LLDB is rust-enabled) -fn extract_lldb_version(full_version_line: &str) -> Option<(u32, bool)> { - // Extract the major LLDB version from the given version string. - // LLDB version strings are different for Apple and non-Apple platforms. - // The Apple variant looks like this: - // - // LLDB-179.5 (older versions) - // lldb-300.2.51 (new versions) - // - // We are only interested in the major version number, so this function - // will return `Some(179)` and `Some(300)` respectively. - // - // Upstream versions look like: - // lldb version 6.0.1 - // - // There doesn't seem to be a way to correlate the Apple version - // with the upstream version, and since the tests were originally - // written against Apple versions, we make a fake Apple version by - // multiplying the first number by 100. This is a hack, but - // normally fine because the only non-Apple version we test is - // rust-enabled. - - let full_version_line = full_version_line.trim(); - - if let Some(apple_ver) = - full_version_line.strip_prefix("LLDB-").or_else(|| full_version_line.strip_prefix("lldb-")) - { - if let Some(idx) = apple_ver.find(not_a_digit) { - let version: u32 = apple_ver[..idx].parse().unwrap(); - return Some((version, full_version_line.contains("rust-enabled"))); - } - } else if let Some(lldb_ver) = full_version_line.strip_prefix("lldb version ") { - if let Some(idx) = lldb_ver.find(not_a_digit) { - let version: u32 = lldb_ver[..idx].parse().ok()?; - return Some((version * 100, full_version_line.contains("rust-enabled"))); - } - } - None -} - -fn not_a_digit(c: char) -> bool { - !c.is_digit(10) -} - -fn check_overlapping_tests(found_paths: &BTreeSet<PathBuf>) { - let mut collisions = Vec::new(); - for path in found_paths { - for ancestor in path.ancestors().skip(1) { - if found_paths.contains(ancestor) { - collisions.push((path, ancestor.clone())); - } - } - } - if !collisions.is_empty() { - let collisions: String = collisions - .into_iter() - .map(|(path, check_parent)| format!("test {path:?} clashes with {check_parent:?}\n")) - .collect(); - panic!( - "{collisions}\n\ - Tests cannot have overlapping names. Make sure they use unique prefixes." - ); - } -} diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 5bc4d164265..923b2e63f2e 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -1939,6 +1939,17 @@ impl<'test> TestCx<'test> { // Use a single thread for efficiency and a deterministic error message order rustc.arg("-Zthreads=1"); + // Hide libstd sources from ui tests to make sure we generate the stderr + // output that users will see. + // Without this, we may be producing good diagnostics in-tree but users + // will not see half the information. + // + // This also has the benefit of more effectively normalizing output between different + // compilers, so that we don't have to know the `/rustc/$sha` output to normalize after the + // fact. + rustc.arg("-Zsimulate-remapped-rust-src-base=/rustc/FAKE_PREFIX"); + rustc.arg("-Ztranslate-remapped-path-to-local-path=no"); + // Optionally prevent default --sysroot if specified in test compile-flags. if !self.props.compile_flags.iter().any(|flag| flag.starts_with("--sysroot")) { // In stage 0, make sure we use `stage0-sysroot` instead of the bootstrap sysroot. @@ -2014,13 +2025,6 @@ impl<'test> TestCx<'test> { rustc.arg("-Ccodegen-units=1"); // Hide line numbers to reduce churn rustc.arg("-Zui-testing"); - // Hide libstd sources from ui tests to make sure we generate the stderr - // output that users will see. - // Without this, we may be producing good diagnostics in-tree but users - // will not see half the information. - rustc.arg("-Zsimulate-remapped-rust-src-base=/rustc/FAKE_PREFIX"); - rustc.arg("-Ztranslate-remapped-path-to-local-path=no"); - rustc.arg("-Zdeduplicate-diagnostics=no"); // FIXME: use this for other modes too, for perf? rustc.arg("-Cstrip=debuginfo"); @@ -2045,7 +2049,10 @@ impl<'test> TestCx<'test> { if let Some(pass) = &self.props.mir_unit_test { rustc.args(&["-Zmir-opt-level=0", &format!("-Zmir-enable-passes=+{}", pass)]); } else { - rustc.arg("-Zmir-opt-level=4"); + rustc.args(&[ + "-Zmir-opt-level=4", + "-Zmir-enable-passes=+ReorderBasicBlocks,+ReorderLocals", + ]); } let mir_dump_dir = self.get_mir_dump_dir(); @@ -3729,28 +3736,13 @@ impl<'test> TestCx<'test> { normalize_path(&remapped_parent_dir, "$DIR"); } - let source_bases = &[ - // Source base on the current filesystem (calculated as parent of `tests/$suite`): - Some(self.config.src_base.parent().unwrap().parent().unwrap().into()), - // Source base on the sysroot (from the src components downloaded by `download-rustc`): - Some(self.config.sysroot_base.join("lib").join("rustlib").join("src").join("rust")), - // Virtual `/rustc/$sha` remapped paths (if `remap-debuginfo` is enabled): - option_env!("CFG_VIRTUAL_RUST_SOURCE_BASE_DIR").map(PathBuf::from), - // Virtual `/rustc/$sha` coming from download-rustc: - std::env::var_os("FAKE_DOWNLOAD_RUSTC_PREFIX").map(PathBuf::from), - // Tests using -Zsimulate-remapped-rust-src-base should use this fake path - Some("/rustc/FAKE_PREFIX".into()), - ]; - for base_dir in source_bases { - if let Some(base_dir) = base_dir { - // 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 - // `rustc_macros` - // eg. /home/user/rust/compiler - normalize_path(&base_dir.join("compiler"), "$COMPILER_DIR"); - } - } + let base_dir = Path::new("/rustc/FAKE_PREFIX"); + // 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 + // `rustc_macros` + // eg. /home/user/rust/compiler + normalize_path(&base_dir.join("compiler"), "$COMPILER_DIR"); // Paths into the build directory let test_build_dir = &self.config.build_base; diff --git a/src/tools/compiletest/src/util.rs b/src/tools/compiletest/src/util.rs index 748240cc94b..17bed38b65e 100644 --- a/src/tools/compiletest/src/util.rs +++ b/src/tools/compiletest/src/util.rs @@ -104,6 +104,8 @@ pub const XRAY_SUPPORTED_TARGETS: &[&str] = &[ "x86_64-unknown-openbsd", ]; +pub const SAFESTACK_SUPPORTED_TARGETS: &[&str] = &["x86_64-unknown-linux-gnu"]; + pub fn make_new_path(path: &str) -> String { assert!(cfg!(windows)); // Windows just uses PATH as the library search path, so we have to diff --git a/src/tools/miri/src/concurrency/thread.rs b/src/tools/miri/src/concurrency/thread.rs index d85cac7bcbb..25c8df43ee2 100644 --- a/src/tools/miri/src/concurrency/thread.rs +++ b/src/tools/miri/src/concurrency/thread.rs @@ -133,10 +133,15 @@ pub struct Thread<'mir, 'tcx> { /// The join status. join_status: ThreadJoinStatus, - /// The temporary used for storing the argument of - /// the call to `miri_start_panic` (the panic payload) when unwinding. + /// Stack of active panic payloads for the current thread. Used for storing + /// the argument of the call to `miri_start_panic` (the panic payload) when unwinding. /// This is pointer-sized, and matches the `Payload` type in `src/libpanic_unwind/miri.rs`. - pub(crate) panic_payload: Option<Scalar<Provenance>>, + /// + /// In real unwinding, the payload gets passed as an argument to the landing pad, + /// which then forwards it to 'Resume'. However this argument is implicit in MIR, + /// so we have to store it out-of-band. When there are multiple active unwinds, + /// the innermost one is always caught first, so we can store them as a stack. + pub(crate) panic_payloads: Vec<Scalar<Provenance>>, /// Last OS error location in memory. It is a 32-bit integer. pub(crate) last_error: Option<MPlaceTy<'tcx, Provenance>>, @@ -206,7 +211,7 @@ impl<'mir, 'tcx> Thread<'mir, 'tcx> { stack: Vec::new(), top_user_relevant_frame: None, join_status: ThreadJoinStatus::Joinable, - panic_payload: None, + panic_payloads: Vec::new(), last_error: None, on_stack_empty, } @@ -216,7 +221,7 @@ impl<'mir, 'tcx> Thread<'mir, 'tcx> { impl VisitTags for Thread<'_, '_> { fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) { let Thread { - panic_payload, + panic_payloads: panic_payload, last_error, stack, top_user_relevant_frame: _, @@ -226,7 +231,9 @@ impl VisitTags for Thread<'_, '_> { on_stack_empty: _, // we assume the closure captures no GC-relevant state } = self; - panic_payload.visit_tags(visit); + for payload in panic_payload { + payload.visit_tags(visit); + } last_error.visit_tags(visit); for frame in stack { frame.visit_tags(visit) diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs index e3f81a78eea..14931baaadf 100644 --- a/src/tools/miri/src/diagnostics.rs +++ b/src/tools/miri/src/diagnostics.rs @@ -306,7 +306,7 @@ pub fn report_error<'tcx, 'mir>( msg.insert(0, e.to_string()); report_msg( DiagLevel::Error, - &if let Some(title) = title { format!("{title}: {}", msg[0]) } else { msg[0].clone() }, + if let Some(title) = title { format!("{title}: {}", msg[0]) } else { msg[0].clone() }, msg, vec![], helps, @@ -359,7 +359,7 @@ pub fn report_leaks<'mir, 'tcx>( any_pruned |= pruned; report_msg( DiagLevel::Error, - &format!( + format!( "memory leaked: {id:?} ({}, size: {:?}, align: {:?}), allocated here:", kind, alloc.size().bytes(), @@ -386,7 +386,7 @@ pub fn report_leaks<'mir, 'tcx>( /// additional `span_label` or `note` call. pub fn report_msg<'tcx>( diag_level: DiagLevel, - title: &str, + title: String, span_msg: Vec<String>, notes: Vec<(Option<SpanData>, String)>, helps: Vec<(Option<SpanData>, String)>, @@ -463,15 +463,16 @@ impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> { let (stacktrace, _was_pruned) = prune_stacktrace(stacktrace, self); let (title, diag_level) = match &e { - RejectedIsolatedOp(_) => ("operation rejected by isolation", DiagLevel::Warning), - Int2Ptr { .. } => ("integer-to-pointer cast", DiagLevel::Warning), + RejectedIsolatedOp(_) => + ("operation rejected by isolation".to_string(), DiagLevel::Warning), + Int2Ptr { .. } => ("integer-to-pointer cast".to_string(), DiagLevel::Warning), CreatedPointerTag(..) | PoppedPointerTag(..) | CreatedCallId(..) | CreatedAlloc(..) | FreedAlloc(..) | ProgressReport { .. } - | WeakMemoryOutdatedLoad => ("tracking was triggered", DiagLevel::Note), + | WeakMemoryOutdatedLoad => ("tracking was triggered".to_string(), DiagLevel::Note), }; let msg = match &e { @@ -571,7 +572,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let stacktrace = this.generate_stacktrace(); report_msg( DiagLevel::Note, - "the place in the program where the ICE was triggered", + "the place in the program where the ICE was triggered".to_string(), vec![], vec![], vec![], diff --git a/src/tools/miri/src/shims/panic.rs b/src/tools/miri/src/shims/panic.rs index 18ae01a19f9..7aefdfcb976 100644 --- a/src/tools/miri/src/shims/panic.rs +++ b/src/tools/miri/src/shims/panic.rs @@ -63,8 +63,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let [payload] = this.check_shim(abi, Abi::Rust, link_name, args)?; let payload = this.read_scalar(payload)?; let thread = this.active_thread_mut(); - assert!(thread.panic_payload.is_none(), "the panic runtime should avoid double-panics"); - thread.panic_payload = Some(payload); + thread.panic_payloads.push(payload); // Jump to the unwind block to begin unwinding. this.unwind_to_block(unwind)?; @@ -146,7 +145,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // The Thread's `panic_payload` holds what was passed to `miri_start_panic`. // This is exactly the second argument we need to pass to `catch_fn`. - let payload = this.active_thread_mut().panic_payload.take().unwrap(); + let payload = this.active_thread_mut().panic_payloads.pop().unwrap(); // Push the `catch_fn` stackframe. let f_instance = this.get_ptr_fn(catch_unwind.catch_fn)?.as_instance()?; diff --git a/src/tools/miri/tests/fail/panic/double_panic.rs b/src/tools/miri/tests/fail/panic/double_panic.rs index 9378adb8609..adb30714269 100644 --- a/src/tools/miri/tests/fail/panic/double_panic.rs +++ b/src/tools/miri/tests/fail/panic/double_panic.rs @@ -1,6 +1,4 @@ -//@error-in-other-file: the program aborted //@normalize-stderr-test: "\| +\^+" -> "| ^" -//@normalize-stderr-test: "unsafe \{ libc::abort\(\) \}|crate::intrinsics::abort\(\);" -> "ABORT();" //@normalize-stderr-test: "\n +[0-9]+:[^\n]+" -> "$1" //@normalize-stderr-test: "\n at [^\n]+" -> "$1" @@ -11,6 +9,7 @@ impl Drop for Foo { } } fn main() { + //~^ERROR: panic in a function that cannot unwind let _foo = Foo; panic!("first"); } diff --git a/src/tools/miri/tests/fail/panic/double_panic.stderr b/src/tools/miri/tests/fail/panic/double_panic.stderr index 77d5fc5d7ce..b6ac56f15d4 100644 --- a/src/tools/miri/tests/fail/panic/double_panic.stderr +++ b/src/tools/miri/tests/fail/panic/double_panic.stderr @@ -2,30 +2,17 @@ thread 'main' panicked at 'first', $DIR/double_panic.rs:LL:CC note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace thread 'main' panicked at 'second', $DIR/double_panic.rs:LL:CC stack backtrace: -thread panicked while panicking. aborting. -error: abnormal termination: the program aborted execution - --> RUSTLIB/std/src/sys/PLATFORM/mod.rs:LL:CC - | -LL | ABORT(); - | ^ the program aborted execution - | - = note: inside `std::sys::PLATFORM::abort_internal` at RUSTLIB/std/src/sys/PLATFORM/mod.rs:LL:CC - = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside `std::sys_common::backtrace::__rust_end_short_backtrace::<[closure@std::panicking::begin_panic_handler::{closure#0}], !>` at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC - = note: inside `std::panicking::begin_panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC -note: inside `<Foo as std::ops::Drop>::drop` +error: abnormal termination: panic in a function that cannot unwind --> $DIR/double_panic.rs:LL:CC | -LL | panic!("second"); - | ^ - = note: inside `std::ptr::drop_in_place::<Foo> - shim(Some(Foo))` at RUSTLIB/core/src/ptr/mod.rs:LL:CC -note: inside `main` - --> $DIR/double_panic.rs:LL:CC +LL | / fn main() { +LL | | +LL | | let _foo = Foo; +LL | | panic!("first"); +LL | | } + | |_^ panic in a function that cannot unwind | -LL | } - | ^ - = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: inside `main` at $DIR/double_panic.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/pass/panic/nested_panic_caught.rs b/src/tools/miri/tests/pass/panic/nested_panic_caught.rs new file mode 100644 index 00000000000..884813150ad --- /dev/null +++ b/src/tools/miri/tests/pass/panic/nested_panic_caught.rs @@ -0,0 +1,25 @@ +//@normalize-stderr-test: "\| +\^+" -> "| ^" +//@normalize-stderr-test: "\n +[0-9]+:[^\n]+" -> "$1" +//@normalize-stderr-test: "\n at [^\n]+" -> "$1" + +// Checks that nested panics work correctly. + +use std::panic::catch_unwind; + +fn double() { + struct Double; + + impl Drop for Double { + fn drop(&mut self) { + let _ = catch_unwind(|| panic!("twice")); + } + } + + let _d = Double; + + panic!("once"); +} + +fn main() { + assert!(catch_unwind(|| double()).is_err()); +} diff --git a/src/tools/miri/tests/pass/panic/nested_panic_caught.stderr b/src/tools/miri/tests/pass/panic/nested_panic_caught.stderr new file mode 100644 index 00000000000..4e2593242df --- /dev/null +++ b/src/tools/miri/tests/pass/panic/nested_panic_caught.stderr @@ -0,0 +1,4 @@ +thread 'main' panicked at 'once', $DIR/nested_panic_caught.rs:LL:CC +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace +thread 'main' panicked at 'twice', $DIR/nested_panic_caught.rs:LL:CC +stack backtrace: diff --git a/src/tools/miri/tests/pass/shims/time-with-isolation2.stdout b/src/tools/miri/tests/pass/shims/time-with-isolation2.stdout index 641e469f50c..c68b40b744b 100644 --- a/src/tools/miri/tests/pass/shims/time-with-isolation2.stdout +++ b/src/tools/miri/tests/pass/shims/time-with-isolation2.stdout @@ -1 +1 @@ -The loop took around 13s +The loop took around 7s diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/version.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/version.rs index cf637ec359a..13f67a0128a 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-api/src/version.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-api/src/version.rs @@ -122,7 +122,7 @@ pub fn read_version(dylib_path: &AbsPath) -> io::Result<String> { // https://github.com/rust-lang/rust/commit/0696e79f2740ad89309269b460579e548a5cd632 let snappy_portion = match version { 5 | 6 => &dot_rustc[8..], - 7 => { + 7 | 8 => { let len_bytes = &dot_rustc[8..12]; let data_len = u32::from_be_bytes(len_bytes.try_into().unwrap()) as usize; &dot_rustc[12..data_len + 12] diff --git a/src/tools/rustdoc-gui-test/Cargo.toml b/src/tools/rustdoc-gui-test/Cargo.toml new file mode 100644 index 00000000000..4cb200ebc7c --- /dev/null +++ b/src/tools/rustdoc-gui-test/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "rustdoc-gui-test" +version = "0.1.0" +edition = "2021" + +[dependencies] +build_helper = { path = "../build_helper" } +compiletest = { path = "../compiletest" } +getopts = "0.2" +walkdir = "2" diff --git a/src/tools/rustdoc-gui-test/src/config.rs b/src/tools/rustdoc-gui-test/src/config.rs new file mode 100644 index 00000000000..dc4c56a5e7a --- /dev/null +++ b/src/tools/rustdoc-gui-test/src/config.rs @@ -0,0 +1,62 @@ +use getopts::Options; +use std::{env, path::PathBuf}; + +pub(crate) struct Config { + pub(crate) nodejs: PathBuf, + pub(crate) npm: PathBuf, + pub(crate) rust_src: PathBuf, + pub(crate) out_dir: PathBuf, + pub(crate) initial_cargo: PathBuf, + pub(crate) jobs: String, + pub(crate) test_args: Vec<PathBuf>, + pub(crate) goml_files: Vec<PathBuf>, + pub(crate) rustc: PathBuf, + pub(crate) rustdoc: PathBuf, + pub(crate) verbose: bool, +} + +impl Config { + pub(crate) fn from_args(args: Vec<String>) -> Self { + let mut opts = Options::new(); + opts.reqopt("", "nodejs", "absolute path of nodejs", "PATH") + .reqopt("", "npm", "absolute path of npm", "PATH") + .reqopt("", "out-dir", "output path of doc compilation", "PATH") + .reqopt("", "rust-src", "root source of the rust source", "PATH") + .reqopt( + "", + "initial-cargo", + "path to cargo to use for compiling tests/rustdoc-gui/src/*", + "PATH", + ) + .reqopt("", "jobs", "jobs arg of browser-ui-test", "JOBS") + .optflag("", "verbose", "run tests verbosely, showing all output") + .optmulti("", "test-arg", "args for browser-ui-test", "FLAGS") + .optmulti("", "goml-file", "goml files for testing with browser-ui-test", "LIST"); + + let (argv0, args_) = args.split_first().unwrap(); + if args.len() == 1 || args[1] == "-h" || args[1] == "--help" { + let message = format!("Usage: {} [OPTIONS] [TESTNAME...]", argv0); + println!("{}", opts.usage(&message)); + std::process::exit(1); + } + + let matches = &match opts.parse(args_) { + Ok(m) => m, + Err(f) => panic!("{:?}", f), + }; + + Self { + nodejs: matches.opt_str("nodejs").map(PathBuf::from).expect("nodejs isn't available"), + npm: matches.opt_str("npm").map(PathBuf::from).expect("npm isn't available"), + rust_src: matches.opt_str("rust-src").map(PathBuf::from).unwrap(), + out_dir: matches.opt_str("out-dir").map(PathBuf::from).unwrap(), + initial_cargo: matches.opt_str("initial-cargo").map(PathBuf::from).unwrap(), + jobs: matches.opt_str("jobs").unwrap(), + goml_files: matches.opt_strs("goml-file").iter().map(PathBuf::from).collect(), + test_args: matches.opt_strs("test-arg").iter().map(PathBuf::from).collect(), + rustc: env::var("RUSTC").map(PathBuf::from).unwrap(), + rustdoc: env::var("RUSTDOC").map(PathBuf::from).unwrap(), + verbose: matches.opt_present("verbose"), + } + } +} diff --git a/src/tools/rustdoc-gui-test/src/main.rs b/src/tools/rustdoc-gui-test/src/main.rs new file mode 100644 index 00000000000..3f60a90f87a --- /dev/null +++ b/src/tools/rustdoc-gui-test/src/main.rs @@ -0,0 +1,156 @@ +use build_helper::util::try_run; +use compiletest::header::TestProps; +use config::Config; +use std::path::{Path, PathBuf}; +use std::process::Command; +use std::sync::Arc; +use std::{env, fs}; + +mod config; + +fn get_browser_ui_test_version_inner(npm: &Path, global: bool) -> Option<String> { + let mut command = Command::new(&npm); + command.arg("list").arg("--parseable").arg("--long").arg("--depth=0"); + if global { + command.arg("--global"); + } + let lines = command + .output() + .map(|output| String::from_utf8_lossy(&output.stdout).into_owned()) + .unwrap_or(String::new()); + lines + .lines() + .find_map(|l| l.split(':').nth(1)?.strip_prefix("browser-ui-test@")) + .map(|v| v.to_owned()) +} + +fn get_browser_ui_test_version(npm: &Path) -> Option<String> { + get_browser_ui_test_version_inner(npm, false) + .or_else(|| get_browser_ui_test_version_inner(npm, true)) +} + +fn compare_browser_ui_test_version(installed_version: &str, src: &Path) { + match fs::read_to_string( + src.join("src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version"), + ) { + Ok(v) => { + if v.trim() != installed_version { + eprintln!( + "⚠️ Installed version of browser-ui-test (`{}`) is different than the \ + one used in the CI (`{}`)", + installed_version, v + ); + eprintln!( + "You can install this version using `npm update browser-ui-test` or by using \ + `npm install browser-ui-test@{}`", + v, + ); + } + } + Err(e) => eprintln!("Couldn't find the CI browser-ui-test version: {:?}", e), + } +} + +fn find_librs<P: AsRef<Path>>(path: P) -> Option<PathBuf> { + for entry in walkdir::WalkDir::new(path) { + let entry = entry.ok()?; + if entry.file_type().is_file() && entry.file_name() == "lib.rs" { + return Some(entry.path().to_path_buf()); + } + } + None +} + +fn main() { + let config = Arc::new(Config::from_args(env::args().collect())); + + // The goal here is to check if the necessary packages are installed, and if not, we + // panic. + match get_browser_ui_test_version(&config.npm) { + Some(version) => { + // We also check the version currently used in CI and emit a warning if it's not the + // same one. + compare_browser_ui_test_version(&version, &config.rust_src); + } + None => { + eprintln!( + r#" +error: rustdoc-gui test suite cannot be run because npm `browser-ui-test` dependency is missing. + +If you want to install the `browser-ui-test` dependency, run `npm install browser-ui-test` +"#, + ); + + panic!("Cannot run rustdoc-gui tests"); + } + } + + let src_path = config.rust_src.join("tests/rustdoc-gui/src"); + for entry in src_path.read_dir().expect("read_dir call failed") { + if let Ok(entry) = entry { + let path = entry.path(); + + if !path.is_dir() { + continue; + } + + let mut cargo = Command::new(&config.initial_cargo); + cargo + .arg("doc") + .arg("--target-dir") + .arg(&config.out_dir) + .env("RUSTC_BOOTSTRAP", "1") + .env("RUSTDOC", &config.rustdoc) + .env("RUSTC", &config.rustc) + .current_dir(path); + + if let Some(librs) = find_librs(entry.path()) { + let compiletest_c = compiletest::common::Config { + edition: None, + mode: compiletest::common::Mode::Rustdoc, + ..Default::default() + }; + + let test_props = TestProps::from_file(&librs, None, &compiletest_c); + + if !test_props.compile_flags.is_empty() { + cargo.env("RUSTDOCFLAGS", test_props.compile_flags.join(" ")); + } + + if let Some(flags) = &test_props.run_flags { + cargo.arg(flags); + } + } + + try_run(&mut cargo, config.verbose); + } + } + + let mut command = Command::new(&config.nodejs); + + if let Ok(current_dir) = env::current_dir() { + let local_node_modules = current_dir.join("node_modules"); + if local_node_modules.exists() { + // Link the local node_modules if exists. + // This is useful when we run rustdoc-gui-test from outside of the source root. + env::set_var("NODE_PATH", local_node_modules); + } + } + + command + .arg(config.rust_src.join("src/tools/rustdoc-gui/tester.js")) + .arg("--jobs") + .arg(&config.jobs) + .arg("--doc-folder") + .arg(config.out_dir.join("doc")) + .arg("--tests-folder") + .arg(config.rust_src.join("tests/rustdoc-gui")); + + for file in &config.goml_files { + command.arg("--file").arg(file); + } + + command.args(&config.test_args); + + try_run(&mut command, config.verbose); +} diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 2e778110931..db2b7910b71 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -38,7 +38,6 @@ const LICENSES: &[&str] = &[ const EXCEPTIONS: &[(&str, &str)] = &[ // tidy-alphabetical-start ("ar_archive_writer", "Apache-2.0 WITH LLVM-exception"), // rustc - ("codespan-reporting", "Apache-2.0"), // cxx via iana-time-zone-haiku via time, only on haiku ("colored", "MPL-2.0"), // rustfmt ("dissimilar", "Apache-2.0"), // rustdoc, rustc_lexer (few tests) via expect-test, (dev deps) ("fluent-langneg", "Apache-2.0"), // rustc (fluent translations) diff --git a/src/tools/tidy/src/fluent_alphabetical.rs b/src/tools/tidy/src/fluent_alphabetical.rs new file mode 100644 index 00000000000..5f8eaebf531 --- /dev/null +++ b/src/tools/tidy/src/fluent_alphabetical.rs @@ -0,0 +1,72 @@ +//! Checks that all Flunt files have messages in alphabetical order + +use crate::walk::{filter_dirs, walk}; +use std::{fs::OpenOptions, io::Write, path::Path}; + +use regex::Regex; + +lazy_static::lazy_static! { + static ref MESSAGE: Regex = Regex::new(r#"(?m)^([a-zA-Z0-9_]+)\s*=\s*"#).unwrap(); +} + +fn filter_fluent(path: &Path) -> bool { + if let Some(ext) = path.extension() { ext.to_str() != Some("ftl") } else { true } +} + +fn check_alphabetic(filename: &str, fluent: &str, bad: &mut bool) { + let mut matches = MESSAGE.captures_iter(fluent).peekable(); + while let Some(m) = matches.next() { + if let Some(next) = matches.peek() { + let name = m.get(1).unwrap(); + let next = next.get(1).unwrap(); + if name.as_str() > next.as_str() { + tidy_error!( + bad, + "{filename}: message `{}` appears before `{}`, but is alphabetically later than it +run tidy with `--bless` to sort the file correctly", + name.as_str(), + next.as_str() + ); + } + } else { + break; + } + } +} + +fn sort_messages(fluent: &str) -> String { + let mut chunks = vec![]; + let mut cur = String::new(); + for line in fluent.lines() { + if MESSAGE.is_match(line) { + chunks.push(std::mem::take(&mut cur)); + } + cur += line; + cur.push('\n'); + } + chunks.push(cur); + chunks.sort(); + let mut out = chunks.join(""); + out = out.trim().to_string(); + out.push('\n'); + out +} + +pub fn check(path: &Path, bless: bool, bad: &mut bool) { + walk( + path, + |path, is_dir| filter_dirs(path) || (!is_dir && filter_fluent(path)), + &mut |ent, contents| { + if bless { + let sorted = sort_messages(contents); + if sorted != contents { + let mut f = + OpenOptions::new().write(true).truncate(true).open(ent.path()).unwrap(); + f.write(sorted.as_bytes()).unwrap(); + } + } else { + check_alphabetic(ent.path().to_str().unwrap(), contents, bad); + } + }, + ); +} diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs index 35000320d1a..e467514a7a3 100644 --- a/src/tools/tidy/src/lib.rs +++ b/src/tools/tidy/src/lib.rs @@ -59,6 +59,7 @@ pub mod edition; pub mod error_codes; pub mod extdeps; pub mod features; +pub mod fluent_alphabetical; pub mod mir_opt_tests; pub mod pal; pub mod primitive_docs; diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs index f59406c404b..1c4d96c321c 100644 --- a/src/tools/tidy/src/main.rs +++ b/src/tools/tidy/src/main.rs @@ -96,6 +96,7 @@ fn main() { // Checks that only make sense for the compiler. check!(error_codes, &root_path, &[&compiler_path, &librustdoc_path], verbose); + check!(fluent_alphabetical, &compiler_path, bless); // Checks that only make sense for the std libs. check!(pal, &library_path); diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs index be3a5d3aa0f..01ef4abd3dc 100644 --- a/src/tools/tidy/src/ui_tests.rs +++ b/src/tools/tidy/src/ui_tests.rs @@ -10,8 +10,8 @@ use std::path::{Path, PathBuf}; const ENTRY_LIMIT: usize = 900; // FIXME: The following limits should be reduced eventually. -const ISSUES_ENTRY_LIMIT: usize = 1920; -const ROOT_ENTRY_LIMIT: usize = 896; +const ISSUES_ENTRY_LIMIT: usize = 1898; +const ROOT_ENTRY_LIMIT: usize = 891; const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[ "rs", // test source files diff --git a/src/version b/src/version index df484cbb1d9..0834888f558 100644 --- a/src/version +++ b/src/version @@ -1 +1 @@ -1.71.0 +1.72.0 diff --git a/tests/assembly/asm/mips-types.rs b/tests/assembly/asm/mips-types.rs index 6aa28b062db..27469b22980 100644 --- a/tests/assembly/asm/mips-types.rs +++ b/tests/assembly/asm/mips-types.rs @@ -72,7 +72,7 @@ macro_rules! check_reg { ($func:ident, $ty:ty, $reg:tt, $mov:literal) => { // mips32-LABEL: sym_static_32: // mips32: #APP -// mips32: lw $3, %got(extern_static) +// mips32: lw $3, %got(extern_static)($gp) // mips32: #NO_APP #[cfg(mips32)] #[no_mangle] @@ -82,7 +82,7 @@ pub unsafe fn sym_static_32() { // mips32-LABEL: sym_fn_32: // mips32: #APP -// mips32: lw $3, %got(extern_func) +// mips32: lw $3, %got(extern_func)($gp) // mips32: #NO_APP #[cfg(mips32)] #[no_mangle] @@ -92,7 +92,9 @@ pub unsafe fn sym_fn_32() { // mips64-LABEL: sym_static_64: // mips64: #APP -// mips64: ld $3, %got_disp(extern_static) +// mips64: lui $3, %got_hi(extern_static) +// mips64: daddu $3, $3, $gp +// mips64: ld $3, %got_lo(extern_static)($3) // mips64: #NO_APP #[cfg(mips64)] #[no_mangle] @@ -102,7 +104,9 @@ pub unsafe fn sym_static_64() { // mips64-LABEL: sym_fn_64: // mips64: #APP -// mips64: ld $3, %got_disp(extern_func) +// mips64: lui $3, %got_hi(extern_func) +// mips64: daddu $3, $3, $gp +// mips64: ld $3, %got_lo(extern_func)($3) // mips64: #NO_APP #[cfg(mips64)] #[no_mangle] diff --git a/tests/codegen/array-map.rs b/tests/codegen/array-map.rs index 3706ddf99fd..24f3f43d078 100644 --- a/tests/codegen/array-map.rs +++ b/tests/codegen/array-map.rs @@ -4,7 +4,6 @@ // ignore-debug (the extra assertions get in the way) #![crate_type = "lib"] -#![feature(array_zip)] // CHECK-LABEL: @short_integer_map #[no_mangle] @@ -16,16 +15,6 @@ pub fn short_integer_map(x: [u32; 8]) -> [u32; 8] { x.map(|x| 2 * x + 1) } -// CHECK-LABEL: @short_integer_zip_map -#[no_mangle] -pub fn short_integer_zip_map(x: [u32; 8], y: [u32; 8]) -> [u32; 8] { - // CHECK: %[[A:.+]] = load <8 x i32> - // CHECK: %[[B:.+]] = load <8 x i32> - // CHECK: sub <8 x i32> %[[B]], %[[A]] - // CHECK: store <8 x i32> - x.zip(y).map(|(x, y)| x - y) -} - // This test is checking that LLVM can SRoA away a bunch of the overhead, // like fully moving the iterators to registers. Notably, previous implementations // of `map` ended up `alloca`ing the whole `array::IntoIterator`, meaning both a diff --git a/tests/codegen/autovectorize-f32x4.rs b/tests/codegen/autovectorize-f32x4.rs index 9ecea53f1c0..54392be707f 100644 --- a/tests/codegen/autovectorize-f32x4.rs +++ b/tests/codegen/autovectorize-f32x4.rs @@ -1,7 +1,6 @@ // compile-flags: -C opt-level=3 -Z merge-functions=disabled // only-x86_64 #![crate_type = "lib"] -#![feature(array_zip)] // CHECK-LABEL: @auto_vectorize_direct #[no_mangle] @@ -32,12 +31,12 @@ pub fn auto_vectorize_loop(a: [f32; 4], b: [f32; 4]) -> [f32; 4] { c } -// CHECK-LABEL: @auto_vectorize_array_zip_map +// CHECK-LABEL: @auto_vectorize_array_from_fn #[no_mangle] -pub fn auto_vectorize_array_zip_map(a: [f32; 4], b: [f32; 4]) -> [f32; 4] { +pub fn auto_vectorize_array_from_fn(a: [f32; 4], b: [f32; 4]) -> [f32; 4] { // CHECK: load <4 x float> // CHECK: load <4 x float> // CHECK: fadd <4 x float> // CHECK: store <4 x float> - a.zip(b).map(|(a, b)| a + b) + std::array::from_fn(|i| a[i] + b[i]) } diff --git a/tests/codegen/const_scalar_pair.rs b/tests/codegen/const_scalar_pair.rs new file mode 100644 index 00000000000..8f32c50b798 --- /dev/null +++ b/tests/codegen/const_scalar_pair.rs @@ -0,0 +1,8 @@ +// compile-flags: --crate-type=lib -Copt-level=0 -Zmir-opt-level=0 -C debuginfo=2 + +#![feature(inline_const)] + +pub fn foo() -> (i32, i32) { + // CHECK: ret { i32, i32 } { i32 1, i32 2 } + const { (1, 2) } +} diff --git a/tests/codegen/sanitizer-safestack-attr-check.rs b/tests/codegen/sanitizer-safestack-attr-check.rs new file mode 100644 index 00000000000..b73ed00e730 --- /dev/null +++ b/tests/codegen/sanitizer-safestack-attr-check.rs @@ -0,0 +1,11 @@ +// This tests that the safestack attribute is applied when enabling the safe-stack sanitizer. +// +// needs-sanitizer-safestack +// compile-flags: -Zsanitizer=safestack + +#![crate_type = "lib"] + +// CHECK: ; Function Attrs:{{.*}}safestack +pub fn tagged() {} + +// CHECK: attributes #0 = {{.*}}safestack diff --git a/tests/incremental/issue-110457-same-span-closures/auxiliary/egui_inspect_derive.rs b/tests/incremental/issue-110457-same-span-closures/auxiliary/egui_inspect_derive.rs new file mode 100644 index 00000000000..e7d91235e73 --- /dev/null +++ b/tests/incremental/issue-110457-same-span-closures/auxiliary/egui_inspect_derive.rs @@ -0,0 +1,90 @@ +// force-host +// no-prefer-dynamic +#![crate_type = "proc-macro"] + +extern crate proc_macro; + +use proc_macro::{Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree}; + +#[proc_macro] +pub fn expand(_: TokenStream) -> TokenStream { + // Hand expansion/rewriting of + // ``` + // quote! { + // output_mut(|o| o.copied_text = "".into()); + // output_mut(|o| o.copied_text = format!("{:?}", self.tile_db)); + // }.into() + // ``` + stream([ + ident("output_mut"), + group( + Delimiter::Parenthesis, + [ + or(), + ident("o"), + or(), + ident("o"), + dot(), + ident("copied_text"), + eq(), + string(""), + dot(), + ident("into"), + group(Delimiter::Parenthesis, []), + ], + ), + semi(), + ident("output_mut"), + group( + Delimiter::Parenthesis, + [ + or(), + ident("o"), + or(), + ident("o"), + dot(), + ident("copied_text"), + eq(), + ident("format"), + bang(), + group( + Delimiter::Parenthesis, + [string("{:?}"), comma(), ident("self"), dot(), ident("tile_db")], + ), + ], + ), + semi(), + ]) +} + +fn stream(s: impl IntoIterator<Item = TokenTree>) -> TokenStream { + s.into_iter().collect() +} + +fn ident(i: &str) -> TokenTree { + TokenTree::Ident(Ident::new(i, Span::call_site())) +} +fn group(d: Delimiter, s: impl IntoIterator<Item = TokenTree>) -> TokenTree { + TokenTree::Group(Group::new(d, s.into_iter().collect())) +} +fn semi() -> TokenTree { + TokenTree::Punct(Punct::new(';', Spacing::Alone)) +} +fn or() -> TokenTree { + TokenTree::Punct(Punct::new('|', Spacing::Alone)) +} +fn dot() -> TokenTree { + TokenTree::Punct(Punct::new('.', Spacing::Alone)) +} +fn eq() -> TokenTree { + TokenTree::Punct(Punct::new('=', Spacing::Alone)) +} +fn bang() -> TokenTree { + TokenTree::Punct(Punct::new('!', Spacing::Alone)) +} +fn comma() -> TokenTree { + TokenTree::Punct(Punct::new(',', Spacing::Alone)) +} +fn string(s: &str) -> TokenTree { + TokenTree::Literal(Literal::string(s)) +} diff --git a/tests/incremental/issue-110457-same-span-closures/main.rs b/tests/incremental/issue-110457-same-span-closures/main.rs new file mode 100644 index 00000000000..b44fda3d36a --- /dev/null +++ b/tests/incremental/issue-110457-same-span-closures/main.rs @@ -0,0 +1,47 @@ +// aux-build: egui_inspect_derive.rs +// revisions: cpass1 cpass2 + +extern crate egui_inspect_derive; + +pub struct TileDef { + pub layer: (), + #[cfg(cpass2)] + pub blend_graphic: String, +} + +pub(crate) struct GameState { + pub(crate) tile_db: TileDb, +} + +impl GameState { + fn inspect_mut(&mut self) { + egui_inspect_derive::expand! {} + } +} + +fn new() -> GameState { + loop {} +} + +fn main() { + let mut app = new(); + app.inspect_mut(); +} +// this is actually used +pub struct TileDb { + unknown_bg: TileDef, +} + +impl std::fmt::Debug for TileDb { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + loop {} + } +} + +pub struct PlatformOutput { + pub copied_text: String, +} + +pub fn output_mut<R>(writer: impl FnOnce(&mut PlatformOutput) -> R) -> R { + loop {} +} diff --git a/tests/mir-opt/deref-patterns/string.foo.PreCodegen.after.mir b/tests/mir-opt/deref-patterns/string.foo.PreCodegen.after.mir index 97826ed19a2..bcdb12011bc 100644 --- a/tests/mir-opt/deref-patterns/string.foo.PreCodegen.after.mir +++ b/tests/mir-opt/deref-patterns/string.foo.PreCodegen.after.mir @@ -3,41 +3,33 @@ fn foo(_1: Option<String>) -> i32 { debug s => _1; // in scope 0 at $DIR/string.rs:+0:12: +0:13 let mut _0: i32; // return place in scope 0 at $DIR/string.rs:+0:34: +0:37 - let mut _2: &std::string::String; // in scope 0 at $DIR/string.rs:+2:14: +2:17 - let mut _3: &str; // in scope 0 at $DIR/string.rs:+2:14: +2:17 - let mut _4: bool; // in scope 0 at $DIR/string.rs:+2:14: +2:17 - let mut _5: isize; // in scope 0 at $DIR/string.rs:+2:9: +2:18 - let _6: std::option::Option<std::string::String>; // in scope 0 at $DIR/string.rs:+3:9: +3:10 - let mut _7: bool; // in scope 0 at $DIR/string.rs:+5:1: +5:2 + let mut _2: bool; // in scope 0 at $DIR/string.rs:+5:1: +5:2 + let mut _3: isize; // in scope 0 at $DIR/string.rs:+2:9: +2:18 + let mut _4: &std::string::String; // in scope 0 at $DIR/string.rs:+2:14: +2:17 + let mut _5: &str; // in scope 0 at $DIR/string.rs:+2:14: +2:17 + let mut _6: bool; // in scope 0 at $DIR/string.rs:+2:14: +2:17 + let _7: std::option::Option<std::string::String>; // in scope 0 at $DIR/string.rs:+3:9: +3:10 scope 1 { - debug s => _6; // in scope 1 at $DIR/string.rs:+3:9: +3:10 + debug s => _7; // in scope 1 at $DIR/string.rs:+3:9: +3:10 } bb0: { - _7 = const false; // scope 0 at $DIR/string.rs:+1:11: +1:12 - _7 = const true; // scope 0 at $DIR/string.rs:+1:11: +1:12 - _5 = discriminant(_1); // scope 0 at $DIR/string.rs:+1:11: +1:12 - switchInt(move _5) -> [1: bb2, otherwise: bb1]; // scope 0 at $DIR/string.rs:+1:5: +1:12 + _2 = const false; // scope 0 at $DIR/string.rs:+1:11: +1:12 + _2 = const true; // scope 0 at $DIR/string.rs:+1:11: +1:12 + _3 = discriminant(_1); // scope 0 at $DIR/string.rs:+1:11: +1:12 + switchInt(move _3) -> [1: bb1, otherwise: bb5]; // scope 0 at $DIR/string.rs:+1:5: +1:12 } bb1: { - StorageLive(_6); // scope 0 at $DIR/string.rs:+3:9: +3:10 - _7 = const false; // scope 0 at $DIR/string.rs:+3:9: +3:10 - _6 = move _1; // scope 0 at $DIR/string.rs:+3:9: +3:10 - _0 = const 4321_i32; // scope 1 at $DIR/string.rs:+3:14: +3:18 - drop(_6) -> [return: bb6, unwind unreachable]; // scope 0 at $DIR/string.rs:+3:17: +3:18 - } - - bb2: { - _2 = &((_1 as Some).0: std::string::String); // scope 0 at $DIR/string.rs:+2:14: +2:17 - _3 = <String as Deref>::deref(move _2) -> [return: bb3, unwind unreachable]; // scope 0 at $DIR/string.rs:+2:14: +2:17 + _4 = &((_1 as Some).0: std::string::String); // scope 0 at $DIR/string.rs:+2:14: +2:17 + _5 = <String as Deref>::deref(move _4) -> [return: bb2, unwind unreachable]; // scope 0 at $DIR/string.rs:+2:14: +2:17 // mir::Constant // + span: $DIR/string.rs:9:14: 9:17 // + literal: Const { ty: for<'a> fn(&'a String) -> &'a <String as Deref>::Target {<String as Deref>::deref}, val: Value(<ZST>) } } - bb3: { - _4 = <str as PartialEq>::eq(_3, const "a") -> [return: bb4, unwind unreachable]; // scope 0 at $DIR/string.rs:+2:14: +2:17 + bb2: { + _6 = <str as PartialEq>::eq(_5, const "a") -> [return: bb3, unwind unreachable]; // scope 0 at $DIR/string.rs:+2:14: +2:17 // mir::Constant // + span: $DIR/string.rs:9:14: 9:17 // + literal: Const { ty: for<'a, 'b> fn(&'a str, &'b str) -> bool {<str as PartialEq>::eq}, val: Value(<ZST>) } @@ -46,29 +38,37 @@ fn foo(_1: Option<String>) -> i32 { // + literal: Const { ty: &str, val: Value(Slice(..)) } } + bb3: { + switchInt(move _6) -> [0: bb5, otherwise: bb4]; // scope 0 at $DIR/string.rs:+2:14: +2:17 + } + bb4: { - switchInt(move _4) -> [0: bb1, otherwise: bb5]; // scope 0 at $DIR/string.rs:+2:14: +2:17 + _0 = const 1234_i32; // scope 0 at $DIR/string.rs:+2:22: +2:26 + goto -> bb7; // scope 0 at $DIR/string.rs:+2:22: +2:26 } bb5: { - _0 = const 1234_i32; // scope 0 at $DIR/string.rs:+2:22: +2:26 - goto -> bb9; // scope 0 at $DIR/string.rs:+2:22: +2:26 + StorageLive(_7); // scope 0 at $DIR/string.rs:+3:9: +3:10 + _2 = const false; // scope 0 at $DIR/string.rs:+3:9: +3:10 + _7 = move _1; // scope 0 at $DIR/string.rs:+3:9: +3:10 + _0 = const 4321_i32; // scope 1 at $DIR/string.rs:+3:14: +3:18 + drop(_7) -> [return: bb6, unwind unreachable]; // scope 0 at $DIR/string.rs:+3:17: +3:18 } bb6: { - StorageDead(_6); // scope 0 at $DIR/string.rs:+3:17: +3:18 - goto -> bb9; // scope 0 at $DIR/string.rs:+3:17: +3:18 + StorageDead(_7); // scope 0 at $DIR/string.rs:+3:17: +3:18 + goto -> bb7; // scope 0 at $DIR/string.rs:+3:17: +3:18 } bb7: { - return; // scope 0 at $DIR/string.rs:+5:2: +5:2 + switchInt(_2) -> [0: bb9, otherwise: bb8]; // scope 0 at $DIR/string.rs:+5:1: +5:2 } bb8: { - drop(_1) -> [return: bb7, unwind unreachable]; // scope 0 at $DIR/string.rs:+5:1: +5:2 + drop(_1) -> [return: bb9, unwind unreachable]; // scope 0 at $DIR/string.rs:+5:1: +5:2 } bb9: { - switchInt(_7) -> [0: bb7, otherwise: bb8]; // scope 0 at $DIR/string.rs:+5:1: +5:2 + return; // scope 0 at $DIR/string.rs:+5:2: +5:2 } } diff --git a/tests/mir-opt/inline/cycle.g.Inline.diff b/tests/mir-opt/inline/cycle.g.Inline.diff index 1e6e30f9e9b..53bf14a0ab6 100644 --- a/tests/mir-opt/inline/cycle.g.Inline.diff +++ b/tests/mir-opt/inline/cycle.g.Inline.diff @@ -8,8 +8,8 @@ + let mut _5: (); // in scope 0 at $DIR/cycle.rs:6:5: 6:8 + scope 1 (inlined f::<fn() {main}>) { // at $DIR/cycle.rs:12:5: 12:12 + debug g => _2; // in scope 1 at $DIR/cycle.rs:5:6: 5:7 -+ let _3: (); // in scope 1 at $DIR/cycle.rs:6:5: 6:8 -+ let mut _4: &fn() {main}; // in scope 1 at $DIR/cycle.rs:6:5: 6:6 ++ let mut _3: &fn() {main}; // in scope 1 at $DIR/cycle.rs:6:5: 6:6 ++ let _4: (); // in scope 1 at $DIR/cycle.rs:6:5: 6:8 + scope 2 (inlined <fn() {main} as Fn<()>>::call - shim(fn() {main})) { // at $DIR/cycle.rs:6:5: 6:8 + } + } @@ -25,16 +25,16 @@ - // mir::Constant // + span: $DIR/cycle.rs:12:7: 12:11 // + literal: Const { ty: fn() {main}, val: Value(<ZST>) } -+ StorageLive(_3); // scope 0 at $DIR/cycle.rs:+1:5: +1:12 -+ StorageLive(_4); // scope 1 at $DIR/cycle.rs:6:5: 6:6 -+ _4 = &_2; // scope 1 at $DIR/cycle.rs:6:5: 6:6 ++ StorageLive(_4); // scope 0 at $DIR/cycle.rs:+1:5: +1:12 ++ StorageLive(_3); // scope 1 at $DIR/cycle.rs:6:5: 6:6 ++ _3 = &_2; // scope 1 at $DIR/cycle.rs:6:5: 6:6 + StorageLive(_5); // scope 1 at $DIR/cycle.rs:6:5: 6:8 + _5 = const (); // scope 1 at $DIR/cycle.rs:6:5: 6:8 -+ _3 = move (*_4)() -> [return: bb4, unwind: bb2]; // scope 2 at $SRC_DIR/core/src/ops/function.rs:LL:COL ++ _4 = move (*_3)() -> [return: bb4, unwind: bb2]; // scope 2 at $SRC_DIR/core/src/ops/function.rs:LL:COL } bb1: { -+ StorageDead(_3); // scope 0 at $DIR/cycle.rs:+1:5: +1:12 ++ StorageDead(_4); // scope 0 at $DIR/cycle.rs:+1:5: +1:12 + StorageDead(_2); // scope 0 at $DIR/cycle.rs:+1:5: +1:12 StorageDead(_1); // scope 0 at $DIR/cycle.rs:+1:12: +1:13 _0 = const (); // scope 0 at $DIR/cycle.rs:+0:8: +2:2 @@ -51,7 +51,7 @@ + + bb4: { + StorageDead(_5); // scope 1 at $DIR/cycle.rs:6:5: 6:8 -+ StorageDead(_4); // scope 1 at $DIR/cycle.rs:6:7: 6:8 ++ StorageDead(_3); // scope 1 at $DIR/cycle.rs:6:7: 6:8 + drop(_2) -> bb1; // scope 1 at $DIR/cycle.rs:7:1: 7:2 } } diff --git a/tests/mir-opt/inline/cycle.main.Inline.diff b/tests/mir-opt/inline/cycle.main.Inline.diff index 315634945e4..fdf6337a9be 100644 --- a/tests/mir-opt/inline/cycle.main.Inline.diff +++ b/tests/mir-opt/inline/cycle.main.Inline.diff @@ -8,8 +8,8 @@ + let mut _5: (); // in scope 0 at $DIR/cycle.rs:6:5: 6:8 + scope 1 (inlined f::<fn() {g}>) { // at $DIR/cycle.rs:17:5: 17:9 + debug g => _2; // in scope 1 at $DIR/cycle.rs:5:6: 5:7 -+ let _3: (); // in scope 1 at $DIR/cycle.rs:6:5: 6:8 -+ let mut _4: &fn() {g}; // in scope 1 at $DIR/cycle.rs:6:5: 6:6 ++ let mut _3: &fn() {g}; // in scope 1 at $DIR/cycle.rs:6:5: 6:6 ++ let _4: (); // in scope 1 at $DIR/cycle.rs:6:5: 6:8 + scope 2 (inlined <fn() {g} as Fn<()>>::call - shim(fn() {g})) { // at $DIR/cycle.rs:6:5: 6:8 + } + } @@ -25,16 +25,16 @@ - // mir::Constant // + span: $DIR/cycle.rs:17:7: 17:8 // + literal: Const { ty: fn() {g}, val: Value(<ZST>) } -+ StorageLive(_3); // scope 0 at $DIR/cycle.rs:+1:5: +1:9 -+ StorageLive(_4); // scope 1 at $DIR/cycle.rs:6:5: 6:6 -+ _4 = &_2; // scope 1 at $DIR/cycle.rs:6:5: 6:6 ++ StorageLive(_4); // scope 0 at $DIR/cycle.rs:+1:5: +1:9 ++ StorageLive(_3); // scope 1 at $DIR/cycle.rs:6:5: 6:6 ++ _3 = &_2; // scope 1 at $DIR/cycle.rs:6:5: 6:6 + StorageLive(_5); // scope 1 at $DIR/cycle.rs:6:5: 6:8 + _5 = const (); // scope 1 at $DIR/cycle.rs:6:5: 6:8 -+ _3 = move (*_4)() -> [return: bb4, unwind: bb2]; // scope 2 at $SRC_DIR/core/src/ops/function.rs:LL:COL ++ _4 = move (*_3)() -> [return: bb4, unwind: bb2]; // scope 2 at $SRC_DIR/core/src/ops/function.rs:LL:COL } bb1: { -+ StorageDead(_3); // scope 0 at $DIR/cycle.rs:+1:5: +1:9 ++ StorageDead(_4); // scope 0 at $DIR/cycle.rs:+1:5: +1:9 + StorageDead(_2); // scope 0 at $DIR/cycle.rs:+1:5: +1:9 StorageDead(_1); // scope 0 at $DIR/cycle.rs:+1:9: +1:10 _0 = const (); // scope 0 at $DIR/cycle.rs:+0:11: +2:2 @@ -51,7 +51,7 @@ + + bb4: { + StorageDead(_5); // scope 1 at $DIR/cycle.rs:6:5: 6:8 -+ StorageDead(_4); // scope 1 at $DIR/cycle.rs:6:7: 6:8 ++ StorageDead(_3); // scope 1 at $DIR/cycle.rs:6:7: 6:8 + drop(_2) -> bb1; // scope 1 at $DIR/cycle.rs:7:1: 7:2 } } diff --git a/tests/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir b/tests/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir index b36711f82f4..33bf3b73b23 100644 --- a/tests/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir +++ b/tests/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir @@ -17,10 +17,10 @@ fn foo(_1: T, _2: i32) -> (i32, T) { debug _q => _9; // in scope 2 at $DIR/inline_closure_captures.rs:+1:14: +1:16 debug q => (*((*_6).0: &i32)); // in scope 2 at $DIR/inline_closure_captures.rs:+0:23: +0:24 debug t => (*((*_6).1: &T)); // in scope 2 at $DIR/inline_closure_captures.rs:+0:17: +0:18 - let mut _10: i32; // in scope 2 at $DIR/inline_closure_captures.rs:+1:19: +1:20 - let mut _11: T; // in scope 2 at $DIR/inline_closure_captures.rs:+1:22: +1:23 - let mut _12: &i32; // in scope 2 at $DIR/inline_closure_captures.rs:+1:13: +1:24 - let mut _13: &T; // in scope 2 at $DIR/inline_closure_captures.rs:+1:13: +1:24 + let mut _10: &i32; // in scope 2 at $DIR/inline_closure_captures.rs:+1:13: +1:24 + let mut _11: i32; // in scope 2 at $DIR/inline_closure_captures.rs:+1:19: +1:20 + let mut _12: &T; // in scope 2 at $DIR/inline_closure_captures.rs:+1:13: +1:24 + let mut _13: T; // in scope 2 at $DIR/inline_closure_captures.rs:+1:22: +1:23 } } @@ -49,15 +49,15 @@ fn foo(_1: T, _2: i32) -> (i32, T) { _7 = (move _8,); // scope 1 at $DIR/inline_closure_captures.rs:+2:5: +2:9 StorageLive(_9); // scope 1 at $DIR/inline_closure_captures.rs:+2:5: +2:9 _9 = move (_7.0: i32); // scope 1 at $DIR/inline_closure_captures.rs:+2:5: +2:9 - StorageLive(_10); // scope 2 at $DIR/inline_closure_captures.rs:+1:19: +1:20 - _12 = deref_copy ((*_6).0: &i32); // scope 2 at $DIR/inline_closure_captures.rs:+1:19: +1:20 - _10 = (*_12); // scope 2 at $DIR/inline_closure_captures.rs:+1:19: +1:20 - StorageLive(_11); // scope 2 at $DIR/inline_closure_captures.rs:+1:22: +1:23 - _13 = deref_copy ((*_6).1: &T); // scope 2 at $DIR/inline_closure_captures.rs:+1:22: +1:23 - _11 = (*_13); // scope 2 at $DIR/inline_closure_captures.rs:+1:22: +1:23 - _0 = (move _10, move _11); // scope 2 at $DIR/inline_closure_captures.rs:+1:18: +1:24 + StorageLive(_11); // scope 2 at $DIR/inline_closure_captures.rs:+1:19: +1:20 + _10 = deref_copy ((*_6).0: &i32); // scope 2 at $DIR/inline_closure_captures.rs:+1:19: +1:20 + _11 = (*_10); // scope 2 at $DIR/inline_closure_captures.rs:+1:19: +1:20 + StorageLive(_13); // scope 2 at $DIR/inline_closure_captures.rs:+1:22: +1:23 + _12 = deref_copy ((*_6).1: &T); // scope 2 at $DIR/inline_closure_captures.rs:+1:22: +1:23 + _13 = (*_12); // scope 2 at $DIR/inline_closure_captures.rs:+1:22: +1:23 + _0 = (move _11, move _13); // scope 2 at $DIR/inline_closure_captures.rs:+1:18: +1:24 + StorageDead(_13); // scope 2 at $DIR/inline_closure_captures.rs:+1:23: +1:24 StorageDead(_11); // scope 2 at $DIR/inline_closure_captures.rs:+1:23: +1:24 - StorageDead(_10); // scope 2 at $DIR/inline_closure_captures.rs:+1:23: +1:24 StorageDead(_9); // scope 1 at $DIR/inline_closure_captures.rs:+2:5: +2:9 StorageDead(_8); // scope 1 at $DIR/inline_closure_captures.rs:+2:8: +2:9 StorageDead(_7); // scope 1 at $DIR/inline_closure_captures.rs:+2:8: +2:9 diff --git a/tests/mir-opt/inline/inline_diverging.h.Inline.diff b/tests/mir-opt/inline/inline_diverging.h.Inline.diff index d501b6ca8d2..255451e8670 100644 --- a/tests/mir-opt/inline/inline_diverging.h.Inline.diff +++ b/tests/mir-opt/inline/inline_diverging.h.Inline.diff @@ -8,15 +8,15 @@ + let mut _8: (); // in scope 0 at $DIR/inline_diverging.rs:27:13: 27:16 + scope 1 (inlined call_twice::<!, fn() -> ! {sleep}>) { // at $DIR/inline_diverging.rs:22:5: 22:22 + debug f => _2; // in scope 1 at $DIR/inline_diverging.rs:26:36: 26:37 -+ let _3: !; // in scope 1 at $DIR/inline_diverging.rs:27:9: 27:10 -+ let mut _4: &fn() -> ! {sleep}; // in scope 1 at $DIR/inline_diverging.rs:27:13: 27:14 ++ let mut _3: &fn() -> ! {sleep}; // in scope 1 at $DIR/inline_diverging.rs:27:13: 27:14 ++ let _4: !; // in scope 1 at $DIR/inline_diverging.rs:27:9: 27:10 + let mut _5: &fn() -> ! {sleep}; // in scope 1 at $DIR/inline_diverging.rs:28:13: 28:14 -+ let mut _6: !; // in scope 1 at $DIR/inline_diverging.rs:29:6: 29:7 -+ let mut _7: !; // in scope 1 at $DIR/inline_diverging.rs:29:9: 29:10 ++ let mut _6: !; // in scope 1 at $DIR/inline_diverging.rs:29:9: 29:10 ++ let mut _7: !; // in scope 1 at $DIR/inline_diverging.rs:29:6: 29:7 + scope 2 { -+ debug a => _3; // in scope 2 at $DIR/inline_diverging.rs:27:9: 27:10 ++ debug a => _4; // in scope 2 at $DIR/inline_diverging.rs:27:9: 27:10 + scope 3 { -+ debug b => _7; // in scope 3 at $DIR/inline_diverging.rs:28:9: 28:10 ++ debug b => _6; // in scope 3 at $DIR/inline_diverging.rs:28:9: 28:10 + } + } + scope 4 (inlined <fn() -> ! {sleep} as Fn<()>>::call - shim(fn() -> ! {sleep})) { // at $DIR/inline_diverging.rs:27:13: 27:16 @@ -34,22 +34,22 @@ - // mir::Constant // + span: $DIR/inline_diverging.rs:22:16: 22:21 // + literal: Const { ty: fn() -> ! {sleep}, val: Value(<ZST>) } -+ StorageLive(_7); // scope 0 at $DIR/inline_diverging.rs:+1:5: +1:22 -+ StorageLive(_3); // scope 1 at $DIR/inline_diverging.rs:27:9: 27:10 -+ StorageLive(_4); // scope 1 at $DIR/inline_diverging.rs:27:13: 27:14 -+ _4 = &_2; // scope 1 at $DIR/inline_diverging.rs:27:13: 27:14 ++ StorageLive(_6); // scope 0 at $DIR/inline_diverging.rs:+1:5: +1:22 ++ StorageLive(_4); // scope 1 at $DIR/inline_diverging.rs:27:9: 27:10 ++ StorageLive(_3); // scope 1 at $DIR/inline_diverging.rs:27:13: 27:14 ++ _3 = &_2; // scope 1 at $DIR/inline_diverging.rs:27:13: 27:14 + StorageLive(_8); // scope 1 at $DIR/inline_diverging.rs:27:13: 27:16 + _8 = const (); // scope 1 at $DIR/inline_diverging.rs:27:13: 27:16 -+ _3 = move (*_4)() -> [return: bb6, unwind: bb4]; // scope 4 at $SRC_DIR/core/src/ops/function.rs:LL:COL ++ _4 = move (*_3)() -> [return: bb6, unwind: bb4]; // scope 4 at $SRC_DIR/core/src/ops/function.rs:LL:COL + } + + bb1: { + StorageDead(_5); // scope 2 at $DIR/inline_diverging.rs:28:15: 28:16 -+ StorageLive(_6); // scope 3 at $DIR/inline_diverging.rs:29:6: 29:7 -+ _6 = move _3; // scope 3 at $DIR/inline_diverging.rs:29:6: 29:7 -+ _1 = (move _6, move _7); // scope 3 at $DIR/inline_diverging.rs:29:5: 29:11 -+ StorageDead(_6); // scope 3 at $DIR/inline_diverging.rs:29:10: 29:11 -+ StorageDead(_3); // scope 1 at $DIR/inline_diverging.rs:30:1: 30:2 ++ StorageLive(_7); // scope 3 at $DIR/inline_diverging.rs:29:6: 29:7 ++ _7 = move _4; // scope 3 at $DIR/inline_diverging.rs:29:6: 29:7 ++ _1 = (move _7, move _6); // scope 3 at $DIR/inline_diverging.rs:29:5: 29:11 ++ StorageDead(_7); // scope 3 at $DIR/inline_diverging.rs:29:10: 29:11 ++ StorageDead(_4); // scope 1 at $DIR/inline_diverging.rs:30:1: 30:2 + drop(_2) -> bb2; // scope 1 at $DIR/inline_diverging.rs:30:1: 30:2 + } + @@ -58,7 +58,7 @@ + } + + bb3 (cleanup): { -+ drop(_3) -> [return: bb4, unwind terminate]; // scope 1 at $DIR/inline_diverging.rs:30:1: 30:2 ++ drop(_4) -> [return: bb4, unwind terminate]; // scope 1 at $DIR/inline_diverging.rs:30:1: 30:2 + } + + bb4 (cleanup): { @@ -71,10 +71,10 @@ + + bb6: { + StorageDead(_8); // scope 1 at $DIR/inline_diverging.rs:27:13: 27:16 -+ StorageDead(_4); // scope 1 at $DIR/inline_diverging.rs:27:15: 27:16 ++ StorageDead(_3); // scope 1 at $DIR/inline_diverging.rs:27:15: 27:16 + StorageLive(_5); // scope 2 at $DIR/inline_diverging.rs:28:13: 28:14 + _5 = &_2; // scope 2 at $DIR/inline_diverging.rs:28:13: 28:14 -+ _7 = <fn() -> ! {sleep} as Fn<()>>::call(move _5, const ()) -> [return: bb1, unwind: bb3]; // scope 2 at $DIR/inline_diverging.rs:28:13: 28:16 ++ _6 = <fn() -> ! {sleep} as Fn<()>>::call(move _5, const ()) -> [return: bb1, unwind: bb3]; // scope 2 at $DIR/inline_diverging.rs:28:13: 28:16 + // mir::Constant + // + span: $DIR/inline_diverging.rs:28:13: 28:14 + // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a fn() -> ! {sleep}, ()) -> <fn() -> ! {sleep} as FnOnce<()>>::Output {<fn() -> ! {sleep} as Fn<()>>::call}, val: Value(<ZST>) } diff --git a/tests/mir-opt/inline/inline_generator.main.Inline.diff b/tests/mir-opt/inline/inline_generator.main.Inline.diff index c3ca2d7d42c..0dcae1e4d45 100644 --- a/tests/mir-opt/inline/inline_generator.main.Inline.diff +++ b/tests/mir-opt/inline/inline_generator.main.Inline.diff @@ -23,9 +23,9 @@ + } + scope 6 (inlined g::{closure#0}) { // at $DIR/inline_generator.rs:9:33: 9:46 + debug a => _5; // in scope 6 at $DIR/inline_generator.rs:15:6: 15:7 -+ let mut _6: i32; // in scope 6 at $DIR/inline_generator.rs:15:17: 15:39 ++ let mut _6: &mut [generator@$DIR/inline_generator.rs:15:5: 15:8]; // in scope 6 at $DIR/inline_generator.rs:15:5: 15:41 + let mut _7: u32; // in scope 6 at $DIR/inline_generator.rs:15:5: 15:41 -+ let mut _8: &mut [generator@$DIR/inline_generator.rs:15:5: 15:8]; // in scope 6 at $DIR/inline_generator.rs:15:5: 15:41 ++ let mut _8: i32; // in scope 6 at $DIR/inline_generator.rs:15:17: 15:39 + let mut _9: &mut [generator@$DIR/inline_generator.rs:15:5: 15:8]; // in scope 6 at $DIR/inline_generator.rs:15:5: 15:41 + let mut _10: &mut [generator@$DIR/inline_generator.rs:15:5: 15:8]; // in scope 6 at $DIR/inline_generator.rs:15:5: 15:41 + } @@ -70,9 +70,9 @@ - // + literal: Const { ty: for<'a> fn(Pin<&'a mut [generator@$DIR/inline_generator.rs:15:5: 15:8]>, bool) -> GeneratorState<<[generator@$DIR/inline_generator.rs:15:5: 15:8] as Generator<bool>>::Yield, <[generator@$DIR/inline_generator.rs:15:5: 15:8] as Generator<bool>>::Return> {<[generator@$DIR/inline_generator.rs:15:5: 15:8] as Generator<bool>>::resume}, val: Value(<ZST>) } + StorageLive(_5); // scope 0 at $DIR/inline_generator.rs:+1:33: +1:46 + _5 = const false; // scope 0 at $DIR/inline_generator.rs:+1:33: +1:46 -+ _8 = deref_copy (_2.0: &mut [generator@$DIR/inline_generator.rs:15:5: 15:8]); // scope 6 at $DIR/inline_generator.rs:15:5: 15:41 -+ _7 = discriminant((*_8)); // scope 6 at $DIR/inline_generator.rs:15:5: 15:41 -+ switchInt(move _7) -> [0: bb3, 1: bb8, 3: bb7, otherwise: bb9]; // scope 6 at $DIR/inline_generator.rs:15:5: 15:41 ++ _6 = deref_copy (_2.0: &mut [generator@$DIR/inline_generator.rs:15:5: 15:8]); // scope 6 at $DIR/inline_generator.rs:15:5: 15:41 ++ _7 = discriminant((*_6)); // scope 6 at $DIR/inline_generator.rs:15:5: 15:41 ++ switchInt(move _7) -> [0: bb3, 1: bb7, 3: bb8, otherwise: bb9]; // scope 6 at $DIR/inline_generator.rs:15:5: 15:41 } - bb3: { @@ -91,40 +91,40 @@ + } + + bb3: { -+ StorageLive(_6); // scope 6 at $DIR/inline_generator.rs:15:17: 15:39 -+ switchInt(_5) -> [0: bb5, otherwise: bb4]; // scope 6 at $DIR/inline_generator.rs:15:20: 15:21 ++ StorageLive(_8); // scope 6 at $DIR/inline_generator.rs:15:17: 15:39 ++ switchInt(_5) -> [0: bb4, otherwise: bb5]; // scope 6 at $DIR/inline_generator.rs:15:20: 15:21 + } + + bb4: { -+ _6 = const 7_i32; // scope 6 at $DIR/inline_generator.rs:15:24: 15:25 ++ _8 = const 13_i32; // scope 6 at $DIR/inline_generator.rs:15:35: 15:37 + goto -> bb6; // scope 6 at $DIR/inline_generator.rs:15:17: 15:39 + } + + bb5: { -+ _6 = const 13_i32; // scope 6 at $DIR/inline_generator.rs:15:35: 15:37 ++ _8 = const 7_i32; // scope 6 at $DIR/inline_generator.rs:15:24: 15:25 + goto -> bb6; // scope 6 at $DIR/inline_generator.rs:15:17: 15:39 + } + + bb6: { -+ _1 = GeneratorState::<i32, bool>::Yielded(move _6); // scope 6 at $DIR/inline_generator.rs:15:11: 15:39 ++ _1 = GeneratorState::<i32, bool>::Yielded(move _8); // scope 6 at $DIR/inline_generator.rs:15:11: 15:39 + _9 = deref_copy (_2.0: &mut [generator@$DIR/inline_generator.rs:15:5: 15:8]); // scope 6 at $DIR/inline_generator.rs:15:11: 15:39 + discriminant((*_9)) = 3; // scope 6 at $DIR/inline_generator.rs:15:11: 15:39 + goto -> bb1; // scope 0 at $DIR/inline_generator.rs:15:11: 15:39 + } + + bb7: { -+ StorageLive(_6); // scope 6 at $DIR/inline_generator.rs:15:5: 15:41 -+ StorageDead(_6); // scope 6 at $DIR/inline_generator.rs:15:38: 15:39 ++ assert(const false, "generator resumed after completion") -> [success: bb7, unwind: bb2]; // scope 6 at $DIR/inline_generator.rs:15:5: 15:41 ++ } ++ ++ bb8: { ++ StorageLive(_8); // scope 6 at $DIR/inline_generator.rs:15:5: 15:41 ++ StorageDead(_8); // scope 6 at $DIR/inline_generator.rs:15:38: 15:39 + _1 = GeneratorState::<i32, bool>::Complete(_5); // scope 6 at $DIR/inline_generator.rs:15:41: 15:41 + _10 = deref_copy (_2.0: &mut [generator@$DIR/inline_generator.rs:15:5: 15:8]); // scope 6 at $DIR/inline_generator.rs:15:41: 15:41 + discriminant((*_10)) = 1; // scope 6 at $DIR/inline_generator.rs:15:41: 15:41 + goto -> bb1; // scope 0 at $DIR/inline_generator.rs:15:41: 15:41 + } + -+ bb8: { -+ assert(const false, "generator resumed after completion") -> [success: bb8, unwind: bb2]; // scope 6 at $DIR/inline_generator.rs:15:5: 15:41 -+ } -+ + bb9: { + unreachable; // scope 6 at $DIR/inline_generator.rs:15:5: 15:41 } diff --git a/tests/mir-opt/inline/issue_106141.outer.Inline.diff b/tests/mir-opt/inline/issue_106141.outer.Inline.diff index 3aebfb69e0a..5fed54f83a7 100644 --- a/tests/mir-opt/inline/issue_106141.outer.Inline.diff +++ b/tests/mir-opt/inline/issue_106141.outer.Inline.diff @@ -4,9 +4,9 @@ fn outer() -> usize { let mut _0: usize; // return place in scope 0 at $DIR/issue_106141.rs:+0:19: +0:24 + scope 1 (inlined inner) { // at $DIR/issue_106141.rs:3:5: 3:12 -+ let mut _1: bool; // in scope 1 at $DIR/issue_106141.rs:14:8: 14:21 ++ let mut _1: &[bool; 1]; // in scope 1 at $DIR/issue_106141.rs:12:18: 12:25 + let mut _2: bool; // in scope 1 at $DIR/issue_106141.rs:14:8: 14:21 -+ let mut _3: &[bool; 1]; // in scope 1 at $DIR/issue_106141.rs:12:18: 12:25 ++ let mut _3: bool; // in scope 1 at $DIR/issue_106141.rs:14:8: 14:21 + scope 2 { + debug buffer => const _; // in scope 2 at $DIR/issue_106141.rs:12:9: 12:15 + scope 3 { @@ -17,8 +17,8 @@ bb0: { - _0 = inner() -> bb1; // scope 0 at $DIR/issue_106141.rs:+1:5: +1:12 -+ StorageLive(_3); // scope 0 at $DIR/issue_106141.rs:+1:5: +1:12 -+ _3 = const _; // scope 1 at $DIR/issue_106141.rs:12:18: 12:25 ++ StorageLive(_1); // scope 0 at $DIR/issue_106141.rs:+1:5: +1:12 ++ _1 = const _; // scope 1 at $DIR/issue_106141.rs:12:18: 12:25 // mir::Constant - // + span: $DIR/issue_106141.rs:3:5: 3:10 - // + literal: Const { ty: fn() -> usize {inner}, val: Value(<ZST>) } @@ -31,14 +31,14 @@ } bb1: { -+ StorageLive(_1); // scope 3 at $DIR/issue_106141.rs:14:8: 14:21 ++ StorageLive(_3); // scope 3 at $DIR/issue_106141.rs:14:8: 14:21 + _2 = Lt(_0, const 1_usize); // scope 3 at $DIR/issue_106141.rs:14:8: 14:21 + assert(move _2, "index out of bounds: the length is {} but the index is {}", const 1_usize, _0) -> bb2; // scope 3 at $DIR/issue_106141.rs:14:8: 14:21 + } + + bb2: { -+ _1 = (*_3)[_0]; // scope 3 at $DIR/issue_106141.rs:14:8: 14:21 -+ switchInt(move _1) -> [0: bb3, otherwise: bb4]; // scope 3 at $DIR/issue_106141.rs:14:8: 14:21 ++ _3 = (*_1)[_0]; // scope 3 at $DIR/issue_106141.rs:14:8: 14:21 ++ switchInt(move _3) -> [0: bb3, otherwise: bb4]; // scope 3 at $DIR/issue_106141.rs:14:8: 14:21 + } + + bb3: { @@ -47,8 +47,8 @@ + } + + bb4: { -+ StorageDead(_1); // scope 3 at $DIR/issue_106141.rs:18:5: 18:6 -+ StorageDead(_3); // scope 0 at $DIR/issue_106141.rs:+1:5: +1:12 ++ StorageDead(_3); // scope 3 at $DIR/issue_106141.rs:18:5: 18:6 ++ StorageDead(_1); // scope 0 at $DIR/issue_106141.rs:+1:5: +1:12 return; // scope 0 at $DIR/issue_106141.rs:+2:2: +2:2 } } diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.PreCodegen.after.mir b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.PreCodegen.after.mir index 3c175ed1504..f4b2416eaab 100644 --- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.PreCodegen.after.mir +++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.PreCodegen.after.mir @@ -7,38 +7,38 @@ fn unchecked_shl_unsigned_smaller(_1: u16, _2: u32) -> u16 { scope 1 (inlined core::num::<impl u16>::unchecked_shl) { // at $DIR/unchecked_shifts.rs:11:7: 11:23 debug self => _1; // in scope 1 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL debug rhs => _2; // in scope 1 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL - let mut _3: u16; // in scope 1 at $SRC_DIR/core/src/num/mod.rs:LL:COL - let mut _4: (u32,); // in scope 1 at $SRC_DIR/core/src/num/mod.rs:LL:COL - let mut _5: u32; // in scope 1 at $SRC_DIR/core/src/num/mod.rs:LL:COL + let mut _3: (u32,); // in scope 1 at $SRC_DIR/core/src/num/mod.rs:LL:COL + let mut _4: u32; // in scope 1 at $SRC_DIR/core/src/num/mod.rs:LL:COL + let mut _13: u16; // in scope 1 at $SRC_DIR/core/src/num/mod.rs:LL:COL scope 2 { scope 3 (inlined core::num::<impl u16>::unchecked_shl::conv) { // at $SRC_DIR/core/src/num/mod.rs:LL:COL - debug x => _5; // in scope 3 at $SRC_DIR/core/src/num/mod.rs:LL:COL - let mut _6: std::option::Option<u16>; // in scope 3 at $SRC_DIR/core/src/num/mod.rs:LL:COL - let mut _7: std::result::Result<u16, std::num::TryFromIntError>; // in scope 3 at $SRC_DIR/core/src/num/mod.rs:LL:COL + debug x => _4; // in scope 3 at $SRC_DIR/core/src/num/mod.rs:LL:COL + let mut _8: std::result::Result<u16, std::num::TryFromIntError>; // in scope 3 at $SRC_DIR/core/src/num/mod.rs:LL:COL + let mut _11: std::option::Option<u16>; // in scope 3 at $SRC_DIR/core/src/num/mod.rs:LL:COL scope 4 { scope 5 (inlined <u32 as TryInto<u16>>::try_into) { // at $SRC_DIR/core/src/num/mod.rs:LL:COL - debug self => _5; // in scope 5 at $SRC_DIR/core/src/convert/mod.rs:LL:COL + debug self => _4; // in scope 5 at $SRC_DIR/core/src/convert/mod.rs:LL:COL scope 6 (inlined convert::num::<impl TryFrom<u32> for u16>::try_from) { // at $SRC_DIR/core/src/convert/mod.rs:LL:COL - debug u => _5; // in scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL - let mut _8: bool; // in scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL - let mut _9: u32; // in scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL - let mut _10: u16; // in scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + debug u => _4; // in scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + let mut _5: u32; // in scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + let mut _6: bool; // in scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + let mut _7: u16; // in scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL } } scope 7 (inlined Result::<u16, TryFromIntError>::ok) { // at $SRC_DIR/core/src/num/mod.rs:LL:COL - debug self => _7; // in scope 7 at $SRC_DIR/core/src/result.rs:LL:COL - let mut _11: isize; // in scope 7 at $SRC_DIR/core/src/result.rs:LL:COL - let _12: u16; // in scope 7 at $SRC_DIR/core/src/result.rs:LL:COL + debug self => _8; // in scope 7 at $SRC_DIR/core/src/result.rs:LL:COL + let mut _9: isize; // in scope 7 at $SRC_DIR/core/src/result.rs:LL:COL + let _10: u16; // in scope 7 at $SRC_DIR/core/src/result.rs:LL:COL scope 8 { - debug x => _12; // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL + debug x => _10; // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL } } scope 9 (inlined #[track_caller] Option::<u16>::unwrap_unchecked) { // at $SRC_DIR/core/src/num/mod.rs:LL:COL - debug self => _6; // in scope 9 at $SRC_DIR/core/src/option.rs:LL:COL - let mut _13: &std::option::Option<u16>; // in scope 9 at $SRC_DIR/core/src/option.rs:LL:COL - let mut _14: isize; // in scope 9 at $SRC_DIR/core/src/option.rs:LL:COL + debug self => _11; // in scope 9 at $SRC_DIR/core/src/option.rs:LL:COL + let mut _12: isize; // in scope 9 at $SRC_DIR/core/src/option.rs:LL:COL + let mut _14: &std::option::Option<u16>; // in scope 9 at $SRC_DIR/core/src/option.rs:LL:COL scope 10 { - debug val => _3; // in scope 10 at $SRC_DIR/core/src/option.rs:LL:COL + debug val => _13; // in scope 10 at $SRC_DIR/core/src/option.rs:LL:COL } scope 11 { scope 13 (inlined unreachable_unchecked) { // at $SRC_DIR/core/src/option.rs:LL:COL @@ -49,7 +49,7 @@ fn unchecked_shl_unsigned_smaller(_1: u16, _2: u32) -> u16 { } } scope 12 (inlined Option::<u16>::is_some) { // at $SRC_DIR/core/src/option.rs:LL:COL - debug self => _13; // in scope 12 at $SRC_DIR/core/src/option.rs:LL:COL + debug self => _14; // in scope 12 at $SRC_DIR/core/src/option.rs:LL:COL } } } @@ -58,81 +58,81 @@ fn unchecked_shl_unsigned_smaller(_1: u16, _2: u32) -> u16 { } bb0: { + StorageLive(_13); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL StorageLive(_3); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL + _3 = (_2,); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL StorageLive(_4); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL - _4 = (_2,); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL - StorageLive(_5); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL - _5 = move (_4.0: u32); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL - StorageLive(_6); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL - StorageLive(_7); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL - StorageLive(_8); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL - StorageLive(_9); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL - _9 = const 65535_u32; // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL - _8 = Gt(_5, move _9); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL - StorageDead(_9); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL - switchInt(move _8) -> [0: bb3, otherwise: bb2]; // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + _4 = move (_3.0: u32); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL + StorageLive(_11); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL + StorageLive(_8); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL + StorageLive(_6); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + StorageLive(_5); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + _5 = const 65535_u32; // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + _6 = Gt(_4, move _5); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + StorageDead(_5); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + switchInt(move _6) -> [0: bb1, otherwise: bb2]; // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL } bb1: { - StorageDead(_3); // scope 2 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL - return; // scope 0 at $DIR/unchecked_shifts.rs:+2:2: +2:2 + StorageLive(_7); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + _7 = _4 as u16 (IntToInt); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + _8 = Result::<u16, TryFromIntError>::Ok(move _7); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + StorageDead(_7); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + goto -> bb3; // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL } bb2: { - _7 = Result::<u16, TryFromIntError>::Err(const TryFromIntError(())); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + _8 = Result::<u16, TryFromIntError>::Err(const TryFromIntError(())); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL // mir::Constant // + span: no-location // + literal: Const { ty: TryFromIntError, val: Value(<ZST>) } - goto -> bb4; // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + goto -> bb3; // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL } bb3: { - StorageLive(_10); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL - _10 = _5 as u16 (IntToInt); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL - _7 = Result::<u16, TryFromIntError>::Ok(move _10); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL - StorageDead(_10); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL - goto -> bb4; // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + StorageDead(_6); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + StorageLive(_10); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL + _9 = discriminant(_8); // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL + switchInt(move _9) -> [0: bb4, 1: bb5, otherwise: bb9]; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL } bb4: { - StorageDead(_8); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL - StorageLive(_12); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL - _11 = discriminant(_7); // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL - switchInt(move _11) -> [0: bb7, 1: bb5, otherwise: bb6]; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL + _10 = move ((_8 as Ok).0: u16); // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL + _11 = Option::<u16>::Some(move _10); // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL + goto -> bb6; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL } bb5: { - _6 = Option::<u16>::None; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL - goto -> bb8; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL + _11 = Option::<u16>::None; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL + goto -> bb6; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL } bb6: { - unreachable; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL + StorageDead(_10); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL + StorageDead(_8); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL + StorageLive(_14); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL + _12 = discriminant(_11); // scope 9 at $SRC_DIR/core/src/option.rs:LL:COL + switchInt(move _12) -> [1: bb7, otherwise: bb9]; // scope 9 at $SRC_DIR/core/src/option.rs:LL:COL } bb7: { - _12 = move ((_7 as Ok).0: u16); // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL - _6 = Option::<u16>::Some(move _12); // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL - goto -> bb8; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL + _13 = move ((_11 as Some).0: u16); // scope 9 at $SRC_DIR/core/src/option.rs:LL:COL + StorageDead(_14); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL + StorageDead(_11); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL + StorageDead(_4); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL + StorageDead(_3); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL + _0 = unchecked_shl::<u16>(_1, move _13) -> [return: bb8, unwind unreachable]; // scope 2 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL + // mir::Constant + // + span: $SRC_DIR/core/src/num/uint_macros.rs:LL:COL + // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(u16, u16) -> u16 {unchecked_shl::<u16>}, val: Value(<ZST>) } } bb8: { - StorageDead(_12); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL - StorageDead(_7); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL - StorageLive(_13); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL - _14 = discriminant(_6); // scope 9 at $SRC_DIR/core/src/option.rs:LL:COL - switchInt(move _14) -> [1: bb9, otherwise: bb6]; // scope 9 at $SRC_DIR/core/src/option.rs:LL:COL + StorageDead(_13); // scope 2 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL + return; // scope 0 at $DIR/unchecked_shifts.rs:+2:2: +2:2 } bb9: { - _3 = move ((_6 as Some).0: u16); // scope 9 at $SRC_DIR/core/src/option.rs:LL:COL - StorageDead(_13); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL - StorageDead(_6); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL - StorageDead(_5); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL - StorageDead(_4); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL - _0 = unchecked_shl::<u16>(_1, move _3) -> [return: bb1, unwind unreachable]; // scope 2 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL - // mir::Constant - // + span: $SRC_DIR/core/src/num/uint_macros.rs:LL:COL - // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(u16, u16) -> u16 {unchecked_shl::<u16>}, val: Value(<ZST>) } + unreachable; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL } } diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.PreCodegen.after.mir b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.PreCodegen.after.mir index 724b3c56723..67f0fe8932f 100644 --- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.PreCodegen.after.mir +++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.PreCodegen.after.mir @@ -7,38 +7,38 @@ fn unchecked_shr_signed_smaller(_1: i16, _2: u32) -> i16 { scope 1 (inlined core::num::<impl i16>::unchecked_shr) { // at $DIR/unchecked_shifts.rs:17:7: 17:23 debug self => _1; // in scope 1 at $SRC_DIR/core/src/num/int_macros.rs:LL:COL debug rhs => _2; // in scope 1 at $SRC_DIR/core/src/num/int_macros.rs:LL:COL - let mut _3: i16; // in scope 1 at $SRC_DIR/core/src/num/mod.rs:LL:COL - let mut _4: (u32,); // in scope 1 at $SRC_DIR/core/src/num/mod.rs:LL:COL - let mut _5: u32; // in scope 1 at $SRC_DIR/core/src/num/mod.rs:LL:COL + let mut _3: (u32,); // in scope 1 at $SRC_DIR/core/src/num/mod.rs:LL:COL + let mut _4: u32; // in scope 1 at $SRC_DIR/core/src/num/mod.rs:LL:COL + let mut _13: i16; // in scope 1 at $SRC_DIR/core/src/num/mod.rs:LL:COL scope 2 { scope 3 (inlined core::num::<impl i16>::unchecked_shr::conv) { // at $SRC_DIR/core/src/num/mod.rs:LL:COL - debug x => _5; // in scope 3 at $SRC_DIR/core/src/num/mod.rs:LL:COL - let mut _6: std::option::Option<i16>; // in scope 3 at $SRC_DIR/core/src/num/mod.rs:LL:COL - let mut _7: std::result::Result<i16, std::num::TryFromIntError>; // in scope 3 at $SRC_DIR/core/src/num/mod.rs:LL:COL + debug x => _4; // in scope 3 at $SRC_DIR/core/src/num/mod.rs:LL:COL + let mut _8: std::result::Result<i16, std::num::TryFromIntError>; // in scope 3 at $SRC_DIR/core/src/num/mod.rs:LL:COL + let mut _11: std::option::Option<i16>; // in scope 3 at $SRC_DIR/core/src/num/mod.rs:LL:COL scope 4 { scope 5 (inlined <u32 as TryInto<i16>>::try_into) { // at $SRC_DIR/core/src/num/mod.rs:LL:COL - debug self => _5; // in scope 5 at $SRC_DIR/core/src/convert/mod.rs:LL:COL + debug self => _4; // in scope 5 at $SRC_DIR/core/src/convert/mod.rs:LL:COL scope 6 (inlined convert::num::<impl TryFrom<u32> for i16>::try_from) { // at $SRC_DIR/core/src/convert/mod.rs:LL:COL - debug u => _5; // in scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL - let mut _8: bool; // in scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL - let mut _9: u32; // in scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL - let mut _10: i16; // in scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + debug u => _4; // in scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + let mut _5: u32; // in scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + let mut _6: bool; // in scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + let mut _7: i16; // in scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL } } scope 7 (inlined Result::<i16, TryFromIntError>::ok) { // at $SRC_DIR/core/src/num/mod.rs:LL:COL - debug self => _7; // in scope 7 at $SRC_DIR/core/src/result.rs:LL:COL - let mut _11: isize; // in scope 7 at $SRC_DIR/core/src/result.rs:LL:COL - let _12: i16; // in scope 7 at $SRC_DIR/core/src/result.rs:LL:COL + debug self => _8; // in scope 7 at $SRC_DIR/core/src/result.rs:LL:COL + let mut _9: isize; // in scope 7 at $SRC_DIR/core/src/result.rs:LL:COL + let _10: i16; // in scope 7 at $SRC_DIR/core/src/result.rs:LL:COL scope 8 { - debug x => _12; // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL + debug x => _10; // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL } } scope 9 (inlined #[track_caller] Option::<i16>::unwrap_unchecked) { // at $SRC_DIR/core/src/num/mod.rs:LL:COL - debug self => _6; // in scope 9 at $SRC_DIR/core/src/option.rs:LL:COL - let mut _13: &std::option::Option<i16>; // in scope 9 at $SRC_DIR/core/src/option.rs:LL:COL - let mut _14: isize; // in scope 9 at $SRC_DIR/core/src/option.rs:LL:COL + debug self => _11; // in scope 9 at $SRC_DIR/core/src/option.rs:LL:COL + let mut _12: isize; // in scope 9 at $SRC_DIR/core/src/option.rs:LL:COL + let mut _14: &std::option::Option<i16>; // in scope 9 at $SRC_DIR/core/src/option.rs:LL:COL scope 10 { - debug val => _3; // in scope 10 at $SRC_DIR/core/src/option.rs:LL:COL + debug val => _13; // in scope 10 at $SRC_DIR/core/src/option.rs:LL:COL } scope 11 { scope 13 (inlined unreachable_unchecked) { // at $SRC_DIR/core/src/option.rs:LL:COL @@ -49,7 +49,7 @@ fn unchecked_shr_signed_smaller(_1: i16, _2: u32) -> i16 { } } scope 12 (inlined Option::<i16>::is_some) { // at $SRC_DIR/core/src/option.rs:LL:COL - debug self => _13; // in scope 12 at $SRC_DIR/core/src/option.rs:LL:COL + debug self => _14; // in scope 12 at $SRC_DIR/core/src/option.rs:LL:COL } } } @@ -58,81 +58,81 @@ fn unchecked_shr_signed_smaller(_1: i16, _2: u32) -> i16 { } bb0: { + StorageLive(_13); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL StorageLive(_3); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL + _3 = (_2,); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL StorageLive(_4); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL - _4 = (_2,); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL - StorageLive(_5); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL - _5 = move (_4.0: u32); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL - StorageLive(_6); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL - StorageLive(_7); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL - StorageLive(_8); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL - StorageLive(_9); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL - _9 = const 32767_u32; // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL - _8 = Gt(_5, move _9); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL - StorageDead(_9); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL - switchInt(move _8) -> [0: bb3, otherwise: bb2]; // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + _4 = move (_3.0: u32); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL + StorageLive(_11); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL + StorageLive(_8); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL + StorageLive(_6); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + StorageLive(_5); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + _5 = const 32767_u32; // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + _6 = Gt(_4, move _5); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + StorageDead(_5); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + switchInt(move _6) -> [0: bb1, otherwise: bb2]; // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL } bb1: { - StorageDead(_3); // scope 2 at $SRC_DIR/core/src/num/int_macros.rs:LL:COL - return; // scope 0 at $DIR/unchecked_shifts.rs:+2:2: +2:2 + StorageLive(_7); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + _7 = _4 as i16 (IntToInt); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + _8 = Result::<i16, TryFromIntError>::Ok(move _7); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + StorageDead(_7); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + goto -> bb3; // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL } bb2: { - _7 = Result::<i16, TryFromIntError>::Err(const TryFromIntError(())); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + _8 = Result::<i16, TryFromIntError>::Err(const TryFromIntError(())); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL // mir::Constant // + span: no-location // + literal: Const { ty: TryFromIntError, val: Value(<ZST>) } - goto -> bb4; // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + goto -> bb3; // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL } bb3: { - StorageLive(_10); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL - _10 = _5 as i16 (IntToInt); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL - _7 = Result::<i16, TryFromIntError>::Ok(move _10); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL - StorageDead(_10); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL - goto -> bb4; // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + StorageDead(_6); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + StorageLive(_10); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL + _9 = discriminant(_8); // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL + switchInt(move _9) -> [0: bb4, 1: bb5, otherwise: bb9]; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL } bb4: { - StorageDead(_8); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL - StorageLive(_12); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL - _11 = discriminant(_7); // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL - switchInt(move _11) -> [0: bb7, 1: bb5, otherwise: bb6]; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL + _10 = move ((_8 as Ok).0: i16); // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL + _11 = Option::<i16>::Some(move _10); // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL + goto -> bb6; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL } bb5: { - _6 = Option::<i16>::None; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL - goto -> bb8; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL + _11 = Option::<i16>::None; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL + goto -> bb6; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL } bb6: { - unreachable; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL + StorageDead(_10); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL + StorageDead(_8); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL + StorageLive(_14); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL + _12 = discriminant(_11); // scope 9 at $SRC_DIR/core/src/option.rs:LL:COL + switchInt(move _12) -> [1: bb7, otherwise: bb9]; // scope 9 at $SRC_DIR/core/src/option.rs:LL:COL } bb7: { - _12 = move ((_7 as Ok).0: i16); // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL - _6 = Option::<i16>::Some(move _12); // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL - goto -> bb8; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL + _13 = move ((_11 as Some).0: i16); // scope 9 at $SRC_DIR/core/src/option.rs:LL:COL + StorageDead(_14); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL + StorageDead(_11); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL + StorageDead(_4); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL + StorageDead(_3); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL + _0 = unchecked_shr::<i16>(_1, move _13) -> [return: bb8, unwind unreachable]; // scope 2 at $SRC_DIR/core/src/num/int_macros.rs:LL:COL + // mir::Constant + // + span: $SRC_DIR/core/src/num/int_macros.rs:LL:COL + // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(i16, i16) -> i16 {unchecked_shr::<i16>}, val: Value(<ZST>) } } bb8: { - StorageDead(_12); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL - StorageDead(_7); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL - StorageLive(_13); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL - _14 = discriminant(_6); // scope 9 at $SRC_DIR/core/src/option.rs:LL:COL - switchInt(move _14) -> [1: bb9, otherwise: bb6]; // scope 9 at $SRC_DIR/core/src/option.rs:LL:COL + StorageDead(_13); // scope 2 at $SRC_DIR/core/src/num/int_macros.rs:LL:COL + return; // scope 0 at $DIR/unchecked_shifts.rs:+2:2: +2:2 } bb9: { - _3 = move ((_6 as Some).0: i16); // scope 9 at $SRC_DIR/core/src/option.rs:LL:COL - StorageDead(_13); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL - StorageDead(_6); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL - StorageDead(_5); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL - StorageDead(_4); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL - _0 = unchecked_shr::<i16>(_1, move _3) -> [return: bb1, unwind unreachable]; // scope 2 at $SRC_DIR/core/src/num/int_macros.rs:LL:COL - // mir::Constant - // + span: $SRC_DIR/core/src/num/int_macros.rs:LL:COL - // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(i16, i16) -> i16 {unchecked_shr::<i16>}, val: Value(<ZST>) } + unreachable; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL } } diff --git a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.mir b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.mir index c5e2469fc27..601d83702f4 100644 --- a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.mir +++ b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.mir @@ -5,8 +5,8 @@ fn unwrap_unchecked(_1: Option<T>) -> T { let mut _0: T; // return place in scope 0 at $DIR/unwrap_unchecked.rs:+0:54: +0:55 scope 1 (inlined #[track_caller] Option::<T>::unwrap_unchecked) { // at $DIR/unwrap_unchecked.rs:10:9: 10:27 debug self => _1; // in scope 1 at $SRC_DIR/core/src/option.rs:LL:COL - let mut _2: &std::option::Option<T>; // in scope 1 at $SRC_DIR/core/src/option.rs:LL:COL - let mut _3: isize; // in scope 1 at $SRC_DIR/core/src/option.rs:LL:COL + let mut _2: isize; // in scope 1 at $SRC_DIR/core/src/option.rs:LL:COL + let mut _3: &std::option::Option<T>; // in scope 1 at $SRC_DIR/core/src/option.rs:LL:COL scope 2 { debug val => _0; // in scope 2 at $SRC_DIR/core/src/option.rs:LL:COL } @@ -19,23 +19,23 @@ fn unwrap_unchecked(_1: Option<T>) -> T { } } scope 4 (inlined Option::<T>::is_some) { // at $SRC_DIR/core/src/option.rs:LL:COL - debug self => _2; // in scope 4 at $SRC_DIR/core/src/option.rs:LL:COL + debug self => _3; // in scope 4 at $SRC_DIR/core/src/option.rs:LL:COL } } bb0: { - StorageLive(_2); // scope 0 at $DIR/unwrap_unchecked.rs:+1:9: +1:27 - _3 = discriminant(_1); // scope 1 at $SRC_DIR/core/src/option.rs:LL:COL - switchInt(move _3) -> [1: bb2, otherwise: bb1]; // scope 1 at $SRC_DIR/core/src/option.rs:LL:COL + StorageLive(_3); // scope 0 at $DIR/unwrap_unchecked.rs:+1:9: +1:27 + _2 = discriminant(_1); // scope 1 at $SRC_DIR/core/src/option.rs:LL:COL + switchInt(move _2) -> [1: bb1, otherwise: bb2]; // scope 1 at $SRC_DIR/core/src/option.rs:LL:COL } bb1: { - unreachable; // scope 6 at $SRC_DIR/core/src/intrinsics.rs:LL:COL + _0 = move ((_1 as Some).0: T); // scope 1 at $SRC_DIR/core/src/option.rs:LL:COL + StorageDead(_3); // scope 0 at $DIR/unwrap_unchecked.rs:+1:9: +1:27 + return; // scope 0 at $DIR/unwrap_unchecked.rs:+2:2: +2:2 } bb2: { - _0 = move ((_1 as Some).0: T); // scope 1 at $SRC_DIR/core/src/option.rs:LL:COL - StorageDead(_2); // scope 0 at $DIR/unwrap_unchecked.rs:+1:9: +1:27 - return; // scope 0 at $DIR/unwrap_unchecked.rs:+2:2: +2:2 + unreachable; // scope 6 at $SRC_DIR/core/src/intrinsics.rs:LL:COL } } diff --git a/tests/mir-opt/issue_101973.inner.ConstProp.diff b/tests/mir-opt/issue_101973.inner.ConstProp.diff index d048b9e6513..2f68f65c874 100644 --- a/tests/mir-opt/issue_101973.inner.ConstProp.diff +++ b/tests/mir-opt/issue_101973.inner.ConstProp.diff @@ -18,8 +18,8 @@ let mut _13: bool; // in scope 0 at $DIR/issue_101973.rs:+1:31: +1:57 scope 1 (inlined imm8) { // at $DIR/issue_101973.rs:15:5: 15:17 debug x => _1; // in scope 1 at $DIR/issue_101973.rs:6:13: 6:14 - let mut _14: u32; // in scope 1 at $DIR/issue_101973.rs:8:12: 8:27 - let mut _15: u32; // in scope 1 at $DIR/issue_101973.rs:8:12: 8:20 + let mut _14: u32; // in scope 1 at $DIR/issue_101973.rs:8:12: 8:20 + let mut _15: u32; // in scope 1 at $DIR/issue_101973.rs:8:12: 8:27 scope 2 { debug out => _4; // in scope 2 at $DIR/issue_101973.rs:7:9: 7:16 } @@ -33,13 +33,13 @@ StorageLive(_2); // scope 0 at $DIR/issue_101973.rs:+1:5: +1:65 StorageLive(_3); // scope 0 at $DIR/issue_101973.rs:+1:5: +1:58 StorageLive(_4); // scope 0 at $DIR/issue_101973.rs:+1:5: +1:17 - StorageLive(_14); // scope 2 at $DIR/issue_101973.rs:8:12: 8:27 - StorageLive(_15); // scope 2 at $DIR/issue_101973.rs:8:12: 8:20 - _15 = Shr(_1, const 0_i32); // scope 2 at $DIR/issue_101973.rs:8:12: 8:20 - _14 = BitAnd(move _15, const 255_u32); // scope 2 at $DIR/issue_101973.rs:8:12: 8:27 - StorageDead(_15); // scope 2 at $DIR/issue_101973.rs:8:26: 8:27 - _4 = BitOr(const 0_u32, move _14); // scope 2 at $DIR/issue_101973.rs:8:5: 8:27 + StorageLive(_15); // scope 2 at $DIR/issue_101973.rs:8:12: 8:27 + StorageLive(_14); // scope 2 at $DIR/issue_101973.rs:8:12: 8:20 + _14 = Shr(_1, const 0_i32); // scope 2 at $DIR/issue_101973.rs:8:12: 8:20 + _15 = BitAnd(move _14, const 255_u32); // scope 2 at $DIR/issue_101973.rs:8:12: 8:27 StorageDead(_14); // scope 2 at $DIR/issue_101973.rs:8:26: 8:27 + _4 = BitOr(const 0_u32, move _15); // scope 2 at $DIR/issue_101973.rs:8:5: 8:27 + StorageDead(_15); // scope 2 at $DIR/issue_101973.rs:8:26: 8:27 StorageLive(_6); // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57 StorageLive(_7); // scope 0 at $DIR/issue_101973.rs:+1:31: +1:52 StorageLive(_8); // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45 diff --git a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.mir b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.mir index 9f955b4717b..fac4b8a2d25 100644 --- a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.mir +++ b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.mir @@ -3,19 +3,19 @@ fn num_to_digit(_1: char) -> u32 { debug num => _1; // in scope 0 at $DIR/issue_59352.rs:+0:21: +0:24 let mut _0: u32; // return place in scope 0 at $DIR/issue_59352.rs:+0:35: +0:38 - let mut _2: std::option::Option<u32>; // in scope 0 at $DIR/issue_59352.rs:+2:26: +2:41 + let mut _5: std::option::Option<u32>; // in scope 0 at $DIR/issue_59352.rs:+2:26: +2:41 scope 1 (inlined char::methods::<impl char>::is_digit) { // at $DIR/issue_59352.rs:15:12: 15:23 debug self => _1; // in scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL debug radix => const 8_u32; // in scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL + let _2: std::option::Option<u32>; // in scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL let mut _3: &std::option::Option<u32>; // in scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL - let _4: std::option::Option<u32>; // in scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL scope 2 (inlined Option::<u32>::is_some) { // at $SRC_DIR/core/src/char/methods.rs:LL:COL debug self => _3; // in scope 2 at $SRC_DIR/core/src/option.rs:LL:COL - let mut _5: isize; // in scope 2 at $SRC_DIR/core/src/option.rs:LL:COL + let mut _4: isize; // in scope 2 at $SRC_DIR/core/src/option.rs:LL:COL } } scope 3 (inlined #[track_caller] Option::<u32>::unwrap) { // at $DIR/issue_59352.rs:15:42: 15:50 - debug self => _2; // in scope 3 at $SRC_DIR/core/src/option.rs:LL:COL + debug self => _5; // in scope 3 at $SRC_DIR/core/src/option.rs:LL:COL let mut _6: isize; // in scope 3 at $SRC_DIR/core/src/option.rs:LL:COL let mut _7: !; // in scope 3 at $SRC_DIR/core/src/option.rs:LL:COL scope 4 { @@ -25,44 +25,35 @@ fn num_to_digit(_1: char) -> u32 { bb0: { StorageLive(_3); // scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL - StorageLive(_4); // scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL - _4 = char::methods::<impl char>::to_digit(_1, const 8_u32) -> bb5; // scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL + StorageLive(_2); // scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL + _2 = char::methods::<impl char>::to_digit(_1, const 8_u32) -> bb1; // scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/char/methods.rs:LL:COL // + literal: Const { ty: fn(char, u32) -> Option<u32> {char::methods::<impl char>::to_digit}, val: Value(<ZST>) } } bb1: { - StorageLive(_2); // scope 0 at $DIR/issue_59352.rs:+2:26: +2:41 - _2 = char::methods::<impl char>::to_digit(_1, const 8_u32) -> bb2; // scope 0 at $DIR/issue_59352.rs:+2:26: +2:41 - // mir::Constant - // + span: $DIR/issue_59352.rs:15:30: 15:38 - // + literal: Const { ty: fn(char, u32) -> Option<u32> {char::methods::<impl char>::to_digit}, val: Value(<ZST>) } + _3 = &_2; // scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL + _4 = discriminant((*_3)); // scope 2 at $SRC_DIR/core/src/option.rs:LL:COL + StorageDead(_3); // scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL + StorageDead(_2); // scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL + switchInt(move _4) -> [1: bb2, otherwise: bb7]; // scope 0 at $DIR/issue_59352.rs:+2:8: +2:23 } bb2: { - _6 = discriminant(_2); // scope 3 at $SRC_DIR/core/src/option.rs:LL:COL - switchInt(move _6) -> [0: bb6, 1: bb8, otherwise: bb7]; // scope 3 at $SRC_DIR/core/src/option.rs:LL:COL + StorageLive(_5); // scope 0 at $DIR/issue_59352.rs:+2:26: +2:41 + _5 = char::methods::<impl char>::to_digit(_1, const 8_u32) -> bb3; // scope 0 at $DIR/issue_59352.rs:+2:26: +2:41 + // mir::Constant + // + span: $DIR/issue_59352.rs:15:30: 15:38 + // + literal: Const { ty: fn(char, u32) -> Option<u32> {char::methods::<impl char>::to_digit}, val: Value(<ZST>) } } bb3: { - _0 = const 0_u32; // scope 0 at $DIR/issue_59352.rs:+2:60: +2:61 - goto -> bb4; // scope 0 at $DIR/issue_59352.rs:+2:5: +2:63 + _6 = discriminant(_5); // scope 3 at $SRC_DIR/core/src/option.rs:LL:COL + switchInt(move _6) -> [0: bb4, 1: bb5, otherwise: bb6]; // scope 3 at $SRC_DIR/core/src/option.rs:LL:COL } bb4: { - return; // scope 0 at $DIR/issue_59352.rs:+3:2: +3:2 - } - - bb5: { - _3 = &_4; // scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL - _5 = discriminant((*_3)); // scope 2 at $SRC_DIR/core/src/option.rs:LL:COL - StorageDead(_3); // scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL - StorageDead(_4); // scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL - switchInt(move _5) -> [1: bb1, otherwise: bb3]; // scope 0 at $DIR/issue_59352.rs:+2:8: +2:23 - } - - bb6: { _7 = core::panicking::panic(const "called `Option::unwrap()` on a `None` value"); // scope 3 at $SRC_DIR/core/src/option.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/option.rs:LL:COL @@ -72,13 +63,22 @@ fn num_to_digit(_1: char) -> u32 { // + literal: Const { ty: &str, val: Value(Slice(..)) } } - bb7: { + bb5: { + _0 = move ((_5 as Some).0: u32); // scope 3 at $SRC_DIR/core/src/option.rs:LL:COL + StorageDead(_5); // scope 0 at $DIR/issue_59352.rs:+2:49: +2:50 + goto -> bb8; // scope 0 at $DIR/issue_59352.rs:+2:5: +2:63 + } + + bb6: { unreachable; // scope 3 at $SRC_DIR/core/src/option.rs:LL:COL } + bb7: { + _0 = const 0_u32; // scope 0 at $DIR/issue_59352.rs:+2:60: +2:61 + goto -> bb8; // scope 0 at $DIR/issue_59352.rs:+2:5: +2:63 + } + bb8: { - _0 = move ((_2 as Some).0: u32); // scope 3 at $SRC_DIR/core/src/option.rs:LL:COL - StorageDead(_2); // scope 0 at $DIR/issue_59352.rs:+2:49: +2:50 - goto -> bb4; // scope 0 at $DIR/issue_59352.rs:+2:5: +2:63 + return; // scope 0 at $DIR/issue_59352.rs:+3:2: +3:2 } } diff --git a/tests/mir-opt/pre-codegen/duplicate_switch_targets.ub_if_b.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/duplicate_switch_targets.ub_if_b.PreCodegen.after.mir index 0e885cf94fd..6b805166ba2 100644 --- a/tests/mir-opt/pre-codegen/duplicate_switch_targets.ub_if_b.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/duplicate_switch_targets.ub_if_b.PreCodegen.after.mir @@ -13,15 +13,15 @@ fn ub_if_b(_1: Thing) -> Thing { bb0: { _2 = discriminant(_1); // scope 0 at $DIR/duplicate_switch_targets.rs:+1:11: +1:12 - switchInt(move _2) -> [0: bb2, otherwise: bb1]; // scope 0 at $DIR/duplicate_switch_targets.rs:+1:5: +1:12 + switchInt(move _2) -> [0: bb1, otherwise: bb2]; // scope 0 at $DIR/duplicate_switch_targets.rs:+1:5: +1:12 } bb1: { - unreachable; // scope 2 at $SRC_DIR/core/src/intrinsics.rs:LL:COL + _0 = move _1; // scope 0 at $DIR/duplicate_switch_targets.rs:+2:21: +2:22 + return; // scope 0 at $DIR/duplicate_switch_targets.rs:+5:2: +5:2 } bb2: { - _0 = move _1; // scope 0 at $DIR/duplicate_switch_targets.rs:+2:21: +2:22 - return; // scope 0 at $DIR/duplicate_switch_targets.rs:+5:2: +5:2 + unreachable; // scope 2 at $SRC_DIR/core/src/intrinsics.rs:LL:COL } } diff --git a/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.mir index 343a4a5a6f3..693939e75f4 100644 --- a/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.mir @@ -7,20 +7,33 @@ fn forward_loop(_1: u32, _2: u32, _3: impl Fn(u32)) -> () { let mut _0: (); // return place in scope 0 at $DIR/range_iter.rs:+0:60: +0:60 let mut _4: std::ops::Range<u32>; // in scope 0 at $DIR/range_iter.rs:+1:14: +1:24 let mut _5: std::ops::Range<u32>; // in scope 0 at $DIR/range_iter.rs:+1:14: +1:24 - let _6: (); // in scope 0 at $DIR/range_iter.rs:+1:14: +1:24 - let mut _7: std::option::Option<u32>; // in scope 0 at $DIR/range_iter.rs:+1:14: +1:24 - let mut _8: &mut std::ops::Range<u32>; // in scope 0 at $DIR/range_iter.rs:+1:14: +1:24 - let mut _9: isize; // in scope 0 at $DIR/range_iter.rs:+1:5: +3:6 - let mut _11: &impl Fn(u32); // in scope 0 at $DIR/range_iter.rs:+2:9: +2:10 - let mut _12: (u32,); // in scope 0 at $DIR/range_iter.rs:+2:9: +2:13 + let mut _6: &mut std::ops::Range<u32>; // in scope 0 at $DIR/range_iter.rs:+1:14: +1:24 + let mut _10: std::option::Option<u32>; // in scope 0 at $DIR/range_iter.rs:+1:14: +1:24 + let mut _13: isize; // in scope 0 at $DIR/range_iter.rs:+1:5: +3:6 + let mut _15: &impl Fn(u32); // in scope 0 at $DIR/range_iter.rs:+2:9: +2:10 + let mut _16: (u32,); // in scope 0 at $DIR/range_iter.rs:+2:9: +2:13 + let _17: (); // in scope 0 at $DIR/range_iter.rs:+1:14: +1:24 scope 1 { debug iter => _5; // in scope 1 at $DIR/range_iter.rs:+1:14: +1:24 - let _10: u32; // in scope 1 at $DIR/range_iter.rs:+1:9: +1:10 + let _14: u32; // in scope 1 at $DIR/range_iter.rs:+1:9: +1:10 scope 2 { - debug x => _10; // in scope 2 at $DIR/range_iter.rs:+1:9: +1:10 + debug x => _14; // in scope 2 at $DIR/range_iter.rs:+1:9: +1:10 } scope 4 (inlined iter::range::<impl Iterator for std::ops::Range<u32>>::next) { // at $DIR/range_iter.rs:21:14: 21:24 - debug self => _8; // in scope 4 at $SRC_DIR/core/src/iter/range.rs:LL:COL + debug self => _6; // in scope 4 at $SRC_DIR/core/src/iter/range.rs:LL:COL + scope 5 (inlined <std::ops::Range<u32> as iter::range::RangeIteratorImpl>::spec_next) { // at $SRC_DIR/core/src/iter/range.rs:LL:COL + debug self => _6; // in scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL + let mut _7: &u32; // in scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL + let mut _8: &u32; // in scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL + let mut _9: bool; // in scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL + let _11: u32; // in scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL + let mut _12: u32; // in scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL + scope 6 { + debug old => _11; // in scope 6 at $SRC_DIR/core/src/iter/range.rs:LL:COL + scope 7 { + } + } + } } } scope 3 (inlined <std::ops::Range<u32> as IntoIterator>::into_iter) { // at $DIR/range_iter.rs:21:14: 21:24 @@ -35,57 +48,92 @@ fn forward_loop(_1: u32, _2: u32, _3: impl Fn(u32)) -> () { } bb1: { - StorageLive(_7); // scope 1 at $DIR/range_iter.rs:+1:14: +1:24 - _8 = &mut _5; // scope 1 at $DIR/range_iter.rs:+1:14: +1:24 - _7 = <std::ops::Range<u32> as iter::range::RangeIteratorImpl>::spec_next(_8) -> [return: bb9, unwind: bb7]; // scope 4 at $SRC_DIR/core/src/iter/range.rs:LL:COL + StorageLive(_10); // scope 1 at $DIR/range_iter.rs:+1:14: +1:24 + _6 = &mut _5; // scope 1 at $DIR/range_iter.rs:+1:14: +1:24 + StorageLive(_11); // scope 4 at $SRC_DIR/core/src/iter/range.rs:LL:COL + StorageLive(_9); // scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL + StorageLive(_7); // scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL + _7 = &((*_6).0: u32); // scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL + StorageLive(_8); // scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL + _8 = &((*_6).1: u32); // scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL + _9 = <u32 as PartialOrd>::lt(move _7, move _8) -> [return: bb2, unwind: bb12]; // scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/iter/range.rs:LL:COL - // + literal: Const { ty: for<'a> fn(&'a mut std::ops::Range<u32>) -> Option<<std::ops::Range<u32> as iter::range::RangeIteratorImpl>::Item> {<std::ops::Range<u32> as iter::range::RangeIteratorImpl>::spec_next}, val: Value(<ZST>) } + // + literal: Const { ty: for<'a, 'b> fn(&'a u32, &'b u32) -> bool {<u32 as PartialOrd>::lt}, val: Value(<ZST>) } } bb2: { - _10 = ((_7 as Some).0: u32); // scope 1 at $DIR/range_iter.rs:+1:9: +1:10 - StorageLive(_11); // scope 2 at $DIR/range_iter.rs:+2:9: +2:10 - _11 = &_3; // scope 2 at $DIR/range_iter.rs:+2:9: +2:10 - StorageLive(_12); // scope 2 at $DIR/range_iter.rs:+2:9: +2:13 - _12 = (_10,); // scope 2 at $DIR/range_iter.rs:+2:9: +2:13 - _6 = <impl Fn(u32) as Fn<(u32,)>>::call(move _11, move _12) -> [return: bb5, unwind: bb7]; // scope 2 at $DIR/range_iter.rs:+2:9: +2:13 - // mir::Constant - // + span: $DIR/range_iter.rs:22:9: 22:10 - // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a impl Fn(u32), (u32,)) -> <impl Fn(u32) as FnOnce<(u32,)>>::Output {<impl Fn(u32) as Fn<(u32,)>>::call}, val: Value(<ZST>) } + StorageDead(_8); // scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL + StorageDead(_7); // scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL + switchInt(move _9) -> [0: bb3, otherwise: bb4]; // scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL } bb3: { - unreachable; // scope 1 at $DIR/range_iter.rs:+1:14: +1:24 + _10 = Option::<u32>::None; // scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL + goto -> bb6; // scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL } bb4: { - StorageDead(_7); // scope 1 at $DIR/range_iter.rs:+3:5: +3:6 - StorageDead(_5); // scope 0 at $DIR/range_iter.rs:+3:5: +3:6 - drop(_3) -> bb6; // scope 0 at $DIR/range_iter.rs:+4:1: +4:2 + _11 = ((*_6).0: u32); // scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL + StorageLive(_12); // scope 6 at $SRC_DIR/core/src/iter/range.rs:LL:COL + _12 = <u32 as Step>::forward_unchecked(_11, const 1_usize) -> [return: bb5, unwind: bb12]; // scope 7 at $SRC_DIR/core/src/iter/range.rs:LL:COL + // mir::Constant + // + span: $SRC_DIR/core/src/iter/range.rs:LL:COL + // + literal: Const { ty: unsafe fn(u32, usize) -> u32 {<u32 as Step>::forward_unchecked}, val: Value(<ZST>) } } bb5: { - StorageDead(_12); // scope 2 at $DIR/range_iter.rs:+2:12: +2:13 - StorageDead(_11); // scope 2 at $DIR/range_iter.rs:+2:12: +2:13 - StorageDead(_7); // scope 1 at $DIR/range_iter.rs:+3:5: +3:6 - goto -> bb1; // scope 1 at $DIR/range_iter.rs:+1:5: +3:6 + ((*_6).0: u32) = move _12; // scope 6 at $SRC_DIR/core/src/iter/range.rs:LL:COL + StorageDead(_12); // scope 6 at $SRC_DIR/core/src/iter/range.rs:LL:COL + _10 = Option::<u32>::Some(_11); // scope 6 at $SRC_DIR/core/src/iter/range.rs:LL:COL + goto -> bb6; // scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL } bb6: { - return; // scope 0 at $DIR/range_iter.rs:+4:2: +4:2 + StorageDead(_9); // scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL + StorageDead(_11); // scope 4 at $SRC_DIR/core/src/iter/range.rs:LL:COL + _13 = discriminant(_10); // scope 1 at $DIR/range_iter.rs:+1:14: +1:24 + switchInt(move _13) -> [0: bb7, 1: bb9, otherwise: bb11]; // scope 1 at $DIR/range_iter.rs:+1:14: +1:24 } - bb7 (cleanup): { - drop(_3) -> [return: bb8, unwind terminate]; // scope 0 at $DIR/range_iter.rs:+4:1: +4:2 + bb7: { + StorageDead(_10); // scope 1 at $DIR/range_iter.rs:+3:5: +3:6 + StorageDead(_5); // scope 0 at $DIR/range_iter.rs:+3:5: +3:6 + drop(_3) -> bb8; // scope 0 at $DIR/range_iter.rs:+4:1: +4:2 } - bb8 (cleanup): { - resume; // scope 0 at $DIR/range_iter.rs:+0:1: +4:2 + bb8: { + return; // scope 0 at $DIR/range_iter.rs:+4:2: +4:2 } bb9: { - _9 = discriminant(_7); // scope 1 at $DIR/range_iter.rs:+1:14: +1:24 - switchInt(move _9) -> [0: bb4, 1: bb2, otherwise: bb3]; // scope 1 at $DIR/range_iter.rs:+1:14: +1:24 + _14 = ((_10 as Some).0: u32); // scope 1 at $DIR/range_iter.rs:+1:9: +1:10 + StorageLive(_15); // scope 2 at $DIR/range_iter.rs:+2:9: +2:10 + _15 = &_3; // scope 2 at $DIR/range_iter.rs:+2:9: +2:10 + StorageLive(_16); // scope 2 at $DIR/range_iter.rs:+2:9: +2:13 + _16 = (_14,); // scope 2 at $DIR/range_iter.rs:+2:9: +2:13 + _17 = <impl Fn(u32) as Fn<(u32,)>>::call(move _15, move _16) -> [return: bb10, unwind: bb12]; // scope 2 at $DIR/range_iter.rs:+2:9: +2:13 + // mir::Constant + // + span: $DIR/range_iter.rs:22:9: 22:10 + // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a impl Fn(u32), (u32,)) -> <impl Fn(u32) as FnOnce<(u32,)>>::Output {<impl Fn(u32) as Fn<(u32,)>>::call}, val: Value(<ZST>) } + } + + bb10: { + StorageDead(_16); // scope 2 at $DIR/range_iter.rs:+2:12: +2:13 + StorageDead(_15); // scope 2 at $DIR/range_iter.rs:+2:12: +2:13 + StorageDead(_10); // scope 1 at $DIR/range_iter.rs:+3:5: +3:6 + goto -> bb1; // scope 1 at $DIR/range_iter.rs:+1:5: +3:6 + } + + bb11: { + unreachable; // scope 1 at $DIR/range_iter.rs:+1:14: +1:24 + } + + bb12 (cleanup): { + drop(_3) -> [return: bb13, unwind terminate]; // scope 0 at $DIR/range_iter.rs:+4:1: +4:2 + } + + bb13 (cleanup): { + resume; // scope 0 at $DIR/range_iter.rs:+0:1: +4:2 } } diff --git a/tests/mir-opt/pre-codegen/range_iter.inclusive_loop.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/range_iter.inclusive_loop.PreCodegen.after.mir index f45eabba252..a187d650a77 100644 --- a/tests/mir-opt/pre-codegen/range_iter.inclusive_loop.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/range_iter.inclusive_loop.PreCodegen.after.mir @@ -7,20 +7,20 @@ fn inclusive_loop(_1: u32, _2: u32, _3: impl Fn(u32)) -> () { let mut _0: (); // return place in scope 0 at $DIR/range_iter.rs:+0:62: +0:62 let mut _4: std::ops::RangeInclusive<u32>; // in scope 0 at $DIR/range_iter.rs:+1:14: +1:25 let mut _5: std::ops::RangeInclusive<u32>; // in scope 0 at $DIR/range_iter.rs:+1:14: +1:25 - let _6: (); // in scope 0 at $DIR/range_iter.rs:+1:14: +1:25 + let mut _6: &mut std::ops::RangeInclusive<u32>; // in scope 0 at $DIR/range_iter.rs:+1:14: +1:25 let mut _7: std::option::Option<u32>; // in scope 0 at $DIR/range_iter.rs:+1:14: +1:25 - let mut _8: &mut std::ops::RangeInclusive<u32>; // in scope 0 at $DIR/range_iter.rs:+1:14: +1:25 - let mut _9: isize; // in scope 0 at $DIR/range_iter.rs:+1:5: +3:6 - let mut _11: &impl Fn(u32); // in scope 0 at $DIR/range_iter.rs:+2:9: +2:10 - let mut _12: (u32,); // in scope 0 at $DIR/range_iter.rs:+2:9: +2:13 + let mut _8: isize; // in scope 0 at $DIR/range_iter.rs:+1:5: +3:6 + let mut _10: &impl Fn(u32); // in scope 0 at $DIR/range_iter.rs:+2:9: +2:10 + let mut _11: (u32,); // in scope 0 at $DIR/range_iter.rs:+2:9: +2:13 + let _12: (); // in scope 0 at $DIR/range_iter.rs:+1:14: +1:25 scope 1 { debug iter => _5; // in scope 1 at $DIR/range_iter.rs:+1:14: +1:25 - let _10: u32; // in scope 1 at $DIR/range_iter.rs:+1:9: +1:10 + let _9: u32; // in scope 1 at $DIR/range_iter.rs:+1:9: +1:10 scope 2 { - debug x => _10; // in scope 2 at $DIR/range_iter.rs:+1:9: +1:10 + debug x => _9; // in scope 2 at $DIR/range_iter.rs:+1:9: +1:10 } scope 5 (inlined iter::range::<impl Iterator for RangeInclusive<u32>>::next) { // at $DIR/range_iter.rs:28:14: 28:25 - debug self => _8; // in scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL + debug self => _6; // in scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL } } scope 3 (inlined RangeInclusive::<u32>::new) { // at $DIR/range_iter.rs:28:14: 28:25 @@ -40,56 +40,56 @@ fn inclusive_loop(_1: u32, _2: u32, _3: impl Fn(u32)) -> () { bb1: { StorageLive(_7); // scope 1 at $DIR/range_iter.rs:+1:14: +1:25 - _8 = &mut _5; // scope 1 at $DIR/range_iter.rs:+1:14: +1:25 - _7 = <RangeInclusive<u32> as iter::range::RangeInclusiveIteratorImpl>::spec_next(_8) -> [return: bb9, unwind: bb7]; // scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL + _6 = &mut _5; // scope 1 at $DIR/range_iter.rs:+1:14: +1:25 + _7 = <RangeInclusive<u32> as iter::range::RangeInclusiveIteratorImpl>::spec_next(_6) -> [return: bb2, unwind: bb8]; // scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/iter/range.rs:LL:COL // + literal: Const { ty: for<'a> fn(&'a mut RangeInclusive<u32>) -> Option<<RangeInclusive<u32> as iter::range::RangeInclusiveIteratorImpl>::Item> {<RangeInclusive<u32> as iter::range::RangeInclusiveIteratorImpl>::spec_next}, val: Value(<ZST>) } } bb2: { - _10 = ((_7 as Some).0: u32); // scope 1 at $DIR/range_iter.rs:+1:9: +1:10 - StorageLive(_11); // scope 2 at $DIR/range_iter.rs:+2:9: +2:10 - _11 = &_3; // scope 2 at $DIR/range_iter.rs:+2:9: +2:10 - StorageLive(_12); // scope 2 at $DIR/range_iter.rs:+2:9: +2:13 - _12 = (_10,); // scope 2 at $DIR/range_iter.rs:+2:9: +2:13 - _6 = <impl Fn(u32) as Fn<(u32,)>>::call(move _11, move _12) -> [return: bb5, unwind: bb7]; // scope 2 at $DIR/range_iter.rs:+2:9: +2:13 - // mir::Constant - // + span: $DIR/range_iter.rs:29:9: 29:10 - // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a impl Fn(u32), (u32,)) -> <impl Fn(u32) as FnOnce<(u32,)>>::Output {<impl Fn(u32) as Fn<(u32,)>>::call}, val: Value(<ZST>) } + _8 = discriminant(_7); // scope 1 at $DIR/range_iter.rs:+1:14: +1:25 + switchInt(move _8) -> [0: bb3, 1: bb5, otherwise: bb7]; // scope 1 at $DIR/range_iter.rs:+1:14: +1:25 } bb3: { - unreachable; // scope 1 at $DIR/range_iter.rs:+1:14: +1:25 + StorageDead(_7); // scope 1 at $DIR/range_iter.rs:+3:5: +3:6 + StorageDead(_5); // scope 0 at $DIR/range_iter.rs:+3:5: +3:6 + drop(_3) -> bb4; // scope 0 at $DIR/range_iter.rs:+4:1: +4:2 } bb4: { - StorageDead(_7); // scope 1 at $DIR/range_iter.rs:+3:5: +3:6 - StorageDead(_5); // scope 0 at $DIR/range_iter.rs:+3:5: +3:6 - drop(_3) -> bb6; // scope 0 at $DIR/range_iter.rs:+4:1: +4:2 + return; // scope 0 at $DIR/range_iter.rs:+4:2: +4:2 } bb5: { - StorageDead(_12); // scope 2 at $DIR/range_iter.rs:+2:12: +2:13 - StorageDead(_11); // scope 2 at $DIR/range_iter.rs:+2:12: +2:13 - StorageDead(_7); // scope 1 at $DIR/range_iter.rs:+3:5: +3:6 - goto -> bb1; // scope 1 at $DIR/range_iter.rs:+1:5: +3:6 + _9 = ((_7 as Some).0: u32); // scope 1 at $DIR/range_iter.rs:+1:9: +1:10 + StorageLive(_10); // scope 2 at $DIR/range_iter.rs:+2:9: +2:10 + _10 = &_3; // scope 2 at $DIR/range_iter.rs:+2:9: +2:10 + StorageLive(_11); // scope 2 at $DIR/range_iter.rs:+2:9: +2:13 + _11 = (_9,); // scope 2 at $DIR/range_iter.rs:+2:9: +2:13 + _12 = <impl Fn(u32) as Fn<(u32,)>>::call(move _10, move _11) -> [return: bb6, unwind: bb8]; // scope 2 at $DIR/range_iter.rs:+2:9: +2:13 + // mir::Constant + // + span: $DIR/range_iter.rs:29:9: 29:10 + // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a impl Fn(u32), (u32,)) -> <impl Fn(u32) as FnOnce<(u32,)>>::Output {<impl Fn(u32) as Fn<(u32,)>>::call}, val: Value(<ZST>) } } bb6: { - return; // scope 0 at $DIR/range_iter.rs:+4:2: +4:2 + StorageDead(_11); // scope 2 at $DIR/range_iter.rs:+2:12: +2:13 + StorageDead(_10); // scope 2 at $DIR/range_iter.rs:+2:12: +2:13 + StorageDead(_7); // scope 1 at $DIR/range_iter.rs:+3:5: +3:6 + goto -> bb1; // scope 1 at $DIR/range_iter.rs:+1:5: +3:6 } - bb7 (cleanup): { - drop(_3) -> [return: bb8, unwind terminate]; // scope 0 at $DIR/range_iter.rs:+4:1: +4:2 + bb7: { + unreachable; // scope 1 at $DIR/range_iter.rs:+1:14: +1:25 } bb8 (cleanup): { - resume; // scope 0 at $DIR/range_iter.rs:+0:1: +4:2 + drop(_3) -> [return: bb9, unwind terminate]; // scope 0 at $DIR/range_iter.rs:+4:1: +4:2 } - bb9: { - _9 = discriminant(_7); // scope 1 at $DIR/range_iter.rs:+1:14: +1:25 - switchInt(move _9) -> [0: bb4, 1: bb2, otherwise: bb3]; // scope 1 at $DIR/range_iter.rs:+1:14: +1:25 + bb9 (cleanup): { + resume; // scope 0 at $DIR/range_iter.rs:+0:1: +4:2 } } diff --git a/tests/mir-opt/pre-codegen/range_iter.range_iter_next.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/range_iter.range_iter_next.PreCodegen.after.mir index cae46e2b0bb..668ec31c6c1 100644 --- a/tests/mir-opt/pre-codegen/range_iter.range_iter_next.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/range_iter.range_iter_next.PreCodegen.after.mir @@ -5,16 +5,64 @@ fn range_iter_next(_1: &mut std::ops::Range<u32>) -> Option<u32> { let mut _0: std::option::Option<u32>; // return place in scope 0 at $DIR/range_iter.rs:+0:48: +0:59 scope 1 (inlined iter::range::<impl Iterator for std::ops::Range<u32>>::next) { // at $DIR/range_iter.rs:11:8: 11:14 debug self => _1; // in scope 1 at $SRC_DIR/core/src/iter/range.rs:LL:COL + scope 2 (inlined <std::ops::Range<u32> as iter::range::RangeIteratorImpl>::spec_next) { // at $SRC_DIR/core/src/iter/range.rs:LL:COL + debug self => _1; // in scope 2 at $SRC_DIR/core/src/iter/range.rs:LL:COL + let mut _2: &u32; // in scope 2 at $SRC_DIR/core/src/iter/range.rs:LL:COL + let mut _3: &u32; // in scope 2 at $SRC_DIR/core/src/iter/range.rs:LL:COL + let mut _4: bool; // in scope 2 at $SRC_DIR/core/src/iter/range.rs:LL:COL + let _5: u32; // in scope 2 at $SRC_DIR/core/src/iter/range.rs:LL:COL + let mut _6: u32; // in scope 2 at $SRC_DIR/core/src/iter/range.rs:LL:COL + scope 3 { + debug old => _5; // in scope 3 at $SRC_DIR/core/src/iter/range.rs:LL:COL + scope 4 { + } + } + } } bb0: { - _0 = <std::ops::Range<u32> as iter::range::RangeIteratorImpl>::spec_next(_1) -> bb1; // scope 1 at $SRC_DIR/core/src/iter/range.rs:LL:COL + StorageLive(_5); // scope 1 at $SRC_DIR/core/src/iter/range.rs:LL:COL + StorageLive(_4); // scope 2 at $SRC_DIR/core/src/iter/range.rs:LL:COL + StorageLive(_2); // scope 2 at $SRC_DIR/core/src/iter/range.rs:LL:COL + _2 = &((*_1).0: u32); // scope 2 at $SRC_DIR/core/src/iter/range.rs:LL:COL + StorageLive(_3); // scope 2 at $SRC_DIR/core/src/iter/range.rs:LL:COL + _3 = &((*_1).1: u32); // scope 2 at $SRC_DIR/core/src/iter/range.rs:LL:COL + _4 = <u32 as PartialOrd>::lt(move _2, move _3) -> bb1; // scope 2 at $SRC_DIR/core/src/iter/range.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/iter/range.rs:LL:COL - // + literal: Const { ty: for<'a> fn(&'a mut std::ops::Range<u32>) -> Option<<std::ops::Range<u32> as iter::range::RangeIteratorImpl>::Item> {<std::ops::Range<u32> as iter::range::RangeIteratorImpl>::spec_next}, val: Value(<ZST>) } + // + literal: Const { ty: for<'a, 'b> fn(&'a u32, &'b u32) -> bool {<u32 as PartialOrd>::lt}, val: Value(<ZST>) } } bb1: { + StorageDead(_3); // scope 2 at $SRC_DIR/core/src/iter/range.rs:LL:COL + StorageDead(_2); // scope 2 at $SRC_DIR/core/src/iter/range.rs:LL:COL + switchInt(move _4) -> [0: bb2, otherwise: bb3]; // scope 2 at $SRC_DIR/core/src/iter/range.rs:LL:COL + } + + bb2: { + _0 = Option::<u32>::None; // scope 2 at $SRC_DIR/core/src/iter/range.rs:LL:COL + goto -> bb5; // scope 2 at $SRC_DIR/core/src/iter/range.rs:LL:COL + } + + bb3: { + _5 = ((*_1).0: u32); // scope 2 at $SRC_DIR/core/src/iter/range.rs:LL:COL + StorageLive(_6); // scope 3 at $SRC_DIR/core/src/iter/range.rs:LL:COL + _6 = <u32 as Step>::forward_unchecked(_5, const 1_usize) -> bb4; // scope 4 at $SRC_DIR/core/src/iter/range.rs:LL:COL + // mir::Constant + // + span: $SRC_DIR/core/src/iter/range.rs:LL:COL + // + literal: Const { ty: unsafe fn(u32, usize) -> u32 {<u32 as Step>::forward_unchecked}, val: Value(<ZST>) } + } + + bb4: { + ((*_1).0: u32) = move _6; // scope 3 at $SRC_DIR/core/src/iter/range.rs:LL:COL + StorageDead(_6); // scope 3 at $SRC_DIR/core/src/iter/range.rs:LL:COL + _0 = Option::<u32>::Some(_5); // scope 3 at $SRC_DIR/core/src/iter/range.rs:LL:COL + goto -> bb5; // scope 2 at $SRC_DIR/core/src/iter/range.rs:LL:COL + } + + bb5: { + StorageDead(_4); // scope 2 at $SRC_DIR/core/src/iter/range.rs:LL:COL + StorageDead(_5); // scope 1 at $SRC_DIR/core/src/iter/range.rs:LL:COL return; // scope 0 at $DIR/range_iter.rs:+2:2: +2:2 } } diff --git a/tests/mir-opt/pre-codegen/simple_option_map.ezmap.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/simple_option_map.ezmap.PreCodegen.after.mir index 986ab35886f..089b0c23e2c 100644 --- a/tests/mir-opt/pre-codegen/simple_option_map.ezmap.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/simple_option_map.ezmap.PreCodegen.after.mir @@ -3,18 +3,18 @@ fn ezmap(_1: Option<i32>) -> Option<i32> { debug x => _1; // in scope 0 at $DIR/simple_option_map.rs:+0:14: +0:15 let mut _0: std::option::Option<i32>; // return place in scope 0 at $DIR/simple_option_map.rs:+0:33: +0:44 - let mut _6: i32; // in scope 0 at $DIR/simple_option_map.rs:11:25: 11:29 + let mut _5: i32; // in scope 0 at $DIR/simple_option_map.rs:11:25: 11:29 scope 1 (inlined map::<i32, i32, [closure@$DIR/simple_option_map.rs:18:12: 18:15]>) { // at $DIR/simple_option_map.rs:18:5: 18:22 debug slf => _1; // in scope 1 at $DIR/simple_option_map.rs:6:17: 6:20 debug f => const ZeroSized: [closure@$DIR/simple_option_map.rs:18:12: 18:15]; // in scope 1 at $DIR/simple_option_map.rs:6:33: 6:34 let mut _2: isize; // in scope 1 at $DIR/simple_option_map.rs:11:9: 11:16 let _3: i32; // in scope 1 at $DIR/simple_option_map.rs:11:14: 11:15 - let mut _4: i32; // in scope 1 at $DIR/simple_option_map.rs:11:25: 11:29 - let mut _5: (i32,); // in scope 1 at $DIR/simple_option_map.rs:11:25: 11:29 + let mut _4: (i32,); // in scope 1 at $DIR/simple_option_map.rs:11:25: 11:29 + let mut _6: i32; // in scope 1 at $DIR/simple_option_map.rs:11:25: 11:29 scope 2 { debug x => _3; // in scope 2 at $DIR/simple_option_map.rs:11:14: 11:15 scope 3 (inlined ezmap::{closure#0}) { // at $DIR/simple_option_map.rs:11:25: 11:29 - debug n => _6; // in scope 3 at $DIR/simple_option_map.rs:+1:13: +1:14 + debug n => _5; // in scope 3 at $DIR/simple_option_map.rs:+1:13: +1:14 } } } @@ -22,35 +22,35 @@ fn ezmap(_1: Option<i32>) -> Option<i32> { bb0: { StorageLive(_3); // scope 0 at $DIR/simple_option_map.rs:+1:5: +1:22 _2 = discriminant(_1); // scope 1 at $DIR/simple_option_map.rs:10:11: 10:14 - switchInt(move _2) -> [0: bb1, 1: bb3, otherwise: bb2]; // scope 1 at $DIR/simple_option_map.rs:10:5: 10:14 + switchInt(move _2) -> [0: bb1, 1: bb2, otherwise: bb4]; // scope 1 at $DIR/simple_option_map.rs:10:5: 10:14 } bb1: { _0 = Option::<i32>::None; // scope 1 at $DIR/simple_option_map.rs:12:17: 12:21 - goto -> bb4; // scope 1 at $DIR/simple_option_map.rs:12:17: 12:21 + goto -> bb3; // scope 1 at $DIR/simple_option_map.rs:12:17: 12:21 } bb2: { - unreachable; // scope 1 at $DIR/simple_option_map.rs:10:11: 10:14 - } - - bb3: { _3 = ((_1 as Some).0: i32); // scope 1 at $DIR/simple_option_map.rs:11:14: 11:15 + StorageLive(_6); // scope 2 at $DIR/simple_option_map.rs:11:25: 11:29 StorageLive(_4); // scope 2 at $DIR/simple_option_map.rs:11:25: 11:29 + _4 = (move _3,); // scope 2 at $DIR/simple_option_map.rs:11:25: 11:29 StorageLive(_5); // scope 2 at $DIR/simple_option_map.rs:11:25: 11:29 - _5 = (move _3,); // scope 2 at $DIR/simple_option_map.rs:11:25: 11:29 - StorageLive(_6); // scope 2 at $DIR/simple_option_map.rs:11:25: 11:29 - _6 = move (_5.0: i32); // scope 2 at $DIR/simple_option_map.rs:11:25: 11:29 - _4 = Add(_6, const 1_i32); // scope 3 at $DIR/simple_option_map.rs:+1:16: +1:21 - StorageDead(_6); // scope 2 at $DIR/simple_option_map.rs:11:25: 11:29 - StorageDead(_5); // scope 2 at $DIR/simple_option_map.rs:11:28: 11:29 - _0 = Option::<i32>::Some(move _4); // scope 2 at $DIR/simple_option_map.rs:11:20: 11:30 - StorageDead(_4); // scope 2 at $DIR/simple_option_map.rs:11:29: 11:30 - goto -> bb4; // scope 1 at $DIR/simple_option_map.rs:14:1: 14:2 + _5 = move (_4.0: i32); // scope 2 at $DIR/simple_option_map.rs:11:25: 11:29 + _6 = Add(_5, const 1_i32); // scope 3 at $DIR/simple_option_map.rs:+1:16: +1:21 + StorageDead(_5); // scope 2 at $DIR/simple_option_map.rs:11:25: 11:29 + StorageDead(_4); // scope 2 at $DIR/simple_option_map.rs:11:28: 11:29 + _0 = Option::<i32>::Some(move _6); // scope 2 at $DIR/simple_option_map.rs:11:20: 11:30 + StorageDead(_6); // scope 2 at $DIR/simple_option_map.rs:11:29: 11:30 + goto -> bb3; // scope 1 at $DIR/simple_option_map.rs:14:1: 14:2 } - bb4: { + bb3: { StorageDead(_3); // scope 0 at $DIR/simple_option_map.rs:+1:5: +1:22 return; // scope 0 at $DIR/simple_option_map.rs:+2:2: +2:2 } + + bb4: { + unreachable; // scope 1 at $DIR/simple_option_map.rs:10:11: 10:14 + } } diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.mir index 715a1e3fcd4..b05d44f4d60 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.mir @@ -10,17 +10,17 @@ fn slice_get_mut_usize(_1: &mut [u32], _2: usize) -> Option<&mut u32> { scope 2 (inlined <usize as SliceIndex<[u32]>>::get_mut) { // at $SRC_DIR/core/src/slice/mod.rs:LL:COL debug self => _2; // in scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL debug slice => _1; // in scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL - let mut _3: bool; // in scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL + let mut _3: &[u32]; // in scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL let mut _4: usize; // in scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL - let mut _5: &[u32]; // in scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL - let mut _6: &mut u32; // in scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL - let mut _7: *mut u32; // in scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL - let mut _8: *mut [u32]; // in scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL + let mut _5: bool; // in scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL + let mut _6: *mut [u32]; // in scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL + let mut _8: *mut u32; // in scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL + let mut _9: &mut u32; // in scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL scope 3 { scope 4 (inlined <usize as SliceIndex<[u32]>>::get_unchecked_mut) { // at $SRC_DIR/core/src/slice/index.rs:LL:COL debug self => _2; // in scope 4 at $SRC_DIR/core/src/slice/index.rs:LL:COL - debug slice => _8; // in scope 4 at $SRC_DIR/core/src/slice/index.rs:LL:COL - let mut _9: *mut u32; // in scope 4 at $SRC_DIR/core/src/slice/index.rs:LL:COL + debug slice => _6; // in scope 4 at $SRC_DIR/core/src/slice/index.rs:LL:COL + let mut _7: *mut u32; // in scope 4 at $SRC_DIR/core/src/slice/index.rs:LL:COL let mut _10: usize; // in scope 4 at $SRC_DIR/core/src/intrinsics.rs:LL:COL let mut _11: *mut [u32]; // in scope 4 at $SRC_DIR/core/src/intrinsics.rs:LL:COL scope 5 { @@ -40,10 +40,10 @@ fn slice_get_mut_usize(_1: &mut [u32], _2: usize) -> Option<&mut u32> { } } scope 11 (inlined ptr::mut_ptr::<impl *mut [u32]>::as_mut_ptr) { // at $SRC_DIR/core/src/slice/index.rs:LL:COL - debug self => _8; // in scope 11 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL + debug self => _6; // in scope 11 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL } scope 12 (inlined ptr::mut_ptr::<impl *mut u32>::add) { // at $SRC_DIR/core/src/slice/index.rs:LL:COL - debug self => _9; // in scope 12 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL + debug self => _7; // in scope 12 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL debug count => _2; // in scope 12 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL scope 13 { } @@ -56,50 +56,50 @@ fn slice_get_mut_usize(_1: &mut [u32], _2: usize) -> Option<&mut u32> { } bb0: { - StorageLive(_6); // scope 1 at $SRC_DIR/core/src/slice/mod.rs:LL:COL - StorageLive(_3); // scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL - StorageLive(_4); // scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL + StorageLive(_9); // scope 1 at $SRC_DIR/core/src/slice/mod.rs:LL:COL StorageLive(_5); // scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL - _5 = &(*_1); // scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL - _4 = Len((*_5)); // scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL - StorageDead(_5); // scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL - _3 = Lt(_2, move _4); // scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL + StorageLive(_4); // scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL + StorageLive(_3); // scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL + _3 = &(*_1); // scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL + _4 = Len((*_3)); // scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL + StorageDead(_3); // scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL + _5 = Lt(_2, move _4); // scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL StorageDead(_4); // scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL - switchInt(move _3) -> [0: bb2, otherwise: bb1]; // scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL + switchInt(move _5) -> [0: bb1, otherwise: bb2]; // scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL } bb1: { - StorageLive(_7); // scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL + _0 = const Option::<&mut u32>::None; // scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL + // mir::Constant + // + span: no-location + // + literal: Const { ty: Option<&mut u32>, val: Value(Scalar(0x0000000000000000)) } + goto -> bb3; // scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL + } + + bb2: { StorageLive(_8); // scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL - _8 = &raw mut (*_1); // scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL + StorageLive(_6); // scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL + _6 = &raw mut (*_1); // scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL StorageLive(_10); // scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL StorageLive(_11); // scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL StorageLive(_12); // scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL - StorageLive(_9); // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL - _9 = _8 as *mut u32 (PtrToPtr); // scope 11 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL - _7 = Offset(_9, _2); // scope 13 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL - StorageDead(_9); // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL + StorageLive(_7); // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL + _7 = _6 as *mut u32 (PtrToPtr); // scope 11 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL + _8 = Offset(_7, _2); // scope 13 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL + StorageDead(_7); // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL StorageDead(_12); // scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL StorageDead(_11); // scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL StorageDead(_10); // scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL - StorageDead(_8); // scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL - _6 = &mut (*_7); // scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL - _0 = Option::<&mut u32>::Some(_6); // scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL - StorageDead(_7); // scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL - goto -> bb3; // scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL - } - - bb2: { - _0 = const Option::<&mut u32>::None; // scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL - // mir::Constant - // + span: no-location - // + literal: Const { ty: Option<&mut u32>, val: Value(Scalar(0x0000000000000000)) } + StorageDead(_6); // scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL + _9 = &mut (*_8); // scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL + _0 = Option::<&mut u32>::Some(_9); // scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL + StorageDead(_8); // scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL goto -> bb3; // scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL } bb3: { - StorageDead(_3); // scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL - StorageDead(_6); // scope 1 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + StorageDead(_5); // scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL + StorageDead(_9); // scope 1 at $SRC_DIR/core/src/slice/mod.rs:LL:COL return; // scope 0 at $DIR/slice_index.rs:+2:2: +2:2 } } diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.mir index 7a10b929ebd..6d9ec5d9a27 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.mir @@ -8,61 +8,61 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range<usize>) -> debug self => _1; // in scope 1 at $SRC_DIR/core/src/slice/mod.rs:LL:COL debug index => _2; // in scope 1 at $SRC_DIR/core/src/slice/mod.rs:LL:COL let mut _3: *mut [u32]; // in scope 1 at $SRC_DIR/core/src/slice/mod.rs:LL:COL - let mut _4: *mut [u32]; // in scope 1 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + let mut _15: *mut [u32]; // in scope 1 at $SRC_DIR/core/src/slice/mod.rs:LL:COL scope 2 { scope 3 (inlined <std::ops::Range<usize> as SliceIndex<[u32]>>::get_unchecked_mut) { // at $SRC_DIR/core/src/slice/mod.rs:LL:COL debug self => _2; // in scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL - debug slice => _4; // in scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL - let _5: std::ops::Range<usize>; // in scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL - let mut _7: usize; // in scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL + debug slice => _3; // in scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL + let mut _4: usize; // in scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL + let mut _5: usize; // in scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL + let mut _7: *mut u32; // in scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL let mut _8: usize; // in scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL let mut _9: *mut u32; // in scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL - let mut _10: *mut u32; // in scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL - let mut _11: usize; // in scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL - let mut _12: usize; // in scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL - let mut _13: std::ops::Range<usize>; // in scope 3 at $SRC_DIR/core/src/intrinsics.rs:LL:COL - let mut _14: *mut [u32]; // in scope 3 at $SRC_DIR/core/src/intrinsics.rs:LL:COL + let mut _10: usize; // in scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL + let _16: std::ops::Range<usize>; // in scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL + let mut _17: std::ops::Range<usize>; // in scope 3 at $SRC_DIR/core/src/intrinsics.rs:LL:COL + let mut _18: *mut [u32]; // in scope 3 at $SRC_DIR/core/src/intrinsics.rs:LL:COL scope 4 { - debug this => _5; // in scope 4 at $SRC_DIR/core/src/slice/index.rs:LL:COL + debug this => _16; // in scope 4 at $SRC_DIR/core/src/slice/index.rs:LL:COL scope 5 { let _6: usize; // in scope 5 at $SRC_DIR/core/src/slice/index.rs:LL:COL scope 6 { debug new_len => _6; // in scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL scope 11 (inlined ptr::mut_ptr::<impl *mut [u32]>::as_mut_ptr) { // at $SRC_DIR/core/src/slice/index.rs:LL:COL - debug self => _4; // in scope 11 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL + debug self => _3; // in scope 11 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL } scope 12 (inlined ptr::mut_ptr::<impl *mut u32>::add) { // at $SRC_DIR/core/src/slice/index.rs:LL:COL - debug self => _10; // in scope 12 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL - debug count => _11; // in scope 12 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL + debug self => _7; // in scope 12 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL + debug count => _8; // in scope 12 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL scope 13 { } } scope 14 (inlined slice_from_raw_parts_mut::<u32>) { // at $SRC_DIR/core/src/slice/index.rs:LL:COL debug data => _9; // in scope 14 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL - debug len => _12; // in scope 14 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL - let mut _16: *mut (); // in scope 14 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + debug len => _10; // in scope 14 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + let mut _11: *mut (); // in scope 14 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL scope 15 (inlined ptr::mut_ptr::<impl *mut u32>::cast::<()>) { // at $SRC_DIR/core/src/ptr/mod.rs:LL:COL debug self => _9; // in scope 15 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL } scope 16 (inlined std::ptr::from_raw_parts_mut::<[u32]>) { // at $SRC_DIR/core/src/ptr/mod.rs:LL:COL - debug data_address => _16; // in scope 16 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL - debug metadata => _12; // in scope 16 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL - let mut _17: std::ptr::metadata::PtrRepr<[u32]>; // in scope 16 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL - let mut _18: std::ptr::metadata::PtrComponents<[u32]>; // in scope 16 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL - let mut _19: *const (); // in scope 16 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL + debug data_address => _11; // in scope 16 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL + debug metadata => _10; // in scope 16 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL + let mut _12: *const (); // in scope 16 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL + let mut _13: std::ptr::metadata::PtrComponents<[u32]>; // in scope 16 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL + let mut _14: std::ptr::metadata::PtrRepr<[u32]>; // in scope 16 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL scope 17 { } } } } scope 7 (inlined <std::ops::Range<usize> as SliceIndex<[T]>>::get_unchecked_mut::runtime::<u32>) { // at $SRC_DIR/core/src/intrinsics.rs:LL:COL - debug this => _13; // in scope 7 at $SRC_DIR/core/src/intrinsics.rs:LL:COL - debug slice => _14; // in scope 7 at $SRC_DIR/core/src/intrinsics.rs:LL:COL + debug this => _17; // in scope 7 at $SRC_DIR/core/src/intrinsics.rs:LL:COL + debug slice => _18; // in scope 7 at $SRC_DIR/core/src/intrinsics.rs:LL:COL scope 8 (inlined ptr::mut_ptr::<impl *mut [u32]>::len) { // at $SRC_DIR/core/src/slice/index.rs:LL:COL - debug self => _14; // in scope 8 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL - let mut _15: *const [u32]; // in scope 8 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL + debug self => _18; // in scope 8 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL + let mut _19: *const [u32]; // in scope 8 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL scope 9 (inlined std::ptr::metadata::<[u32]>) { // at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL - debug ptr => _15; // in scope 9 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL + debug ptr => _19; // in scope 9 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL scope 10 { } } @@ -75,60 +75,60 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range<usize>) -> } bb0: { - StorageLive(_3); // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL - StorageLive(_4); // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL - _4 = &raw mut (*_1); // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL - StorageLive(_5); // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL - StorageLive(_13); // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL - StorageLive(_14); // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL StorageLive(_15); // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + StorageLive(_3); // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + _3 = &raw mut (*_1); // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + StorageLive(_16); // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + StorageLive(_17); // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + StorageLive(_18); // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + StorageLive(_19); // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL StorageLive(_6); // scope 5 at $SRC_DIR/core/src/slice/index.rs:LL:COL - StorageLive(_7); // scope 5 at $SRC_DIR/core/src/slice/index.rs:LL:COL - _7 = (_2.1: usize); // scope 5 at $SRC_DIR/core/src/slice/index.rs:LL:COL - StorageLive(_8); // scope 5 at $SRC_DIR/core/src/slice/index.rs:LL:COL - _8 = (_2.0: usize); // scope 5 at $SRC_DIR/core/src/slice/index.rs:LL:COL - _6 = unchecked_sub::<usize>(move _7, move _8) -> [return: bb1, unwind unreachable]; // scope 5 at $SRC_DIR/core/src/slice/index.rs:LL:COL + StorageLive(_4); // scope 5 at $SRC_DIR/core/src/slice/index.rs:LL:COL + _4 = (_2.1: usize); // scope 5 at $SRC_DIR/core/src/slice/index.rs:LL:COL + StorageLive(_5); // scope 5 at $SRC_DIR/core/src/slice/index.rs:LL:COL + _5 = (_2.0: usize); // scope 5 at $SRC_DIR/core/src/slice/index.rs:LL:COL + _6 = unchecked_sub::<usize>(move _4, move _5) -> [return: bb1, unwind unreachable]; // scope 5 at $SRC_DIR/core/src/slice/index.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/slice/index.rs:LL:COL // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(usize, usize) -> usize {unchecked_sub::<usize>}, val: Value(<ZST>) } } bb1: { - StorageDead(_8); // scope 5 at $SRC_DIR/core/src/slice/index.rs:LL:COL - StorageDead(_7); // scope 5 at $SRC_DIR/core/src/slice/index.rs:LL:COL + StorageDead(_5); // scope 5 at $SRC_DIR/core/src/slice/index.rs:LL:COL + StorageDead(_4); // scope 5 at $SRC_DIR/core/src/slice/index.rs:LL:COL StorageLive(_9); // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL + StorageLive(_7); // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL + _7 = _3 as *mut u32 (PtrToPtr); // scope 11 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL + StorageLive(_8); // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL + _8 = (_2.0: usize); // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL + _9 = Offset(_7, _8); // scope 13 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL + StorageDead(_8); // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL + StorageDead(_7); // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL StorageLive(_10); // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL - _10 = _4 as *mut u32 (PtrToPtr); // scope 11 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL - StorageLive(_11); // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL - _11 = (_2.0: usize); // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL - _9 = Offset(_10, _11); // scope 13 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL - StorageDead(_11); // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL + _10 = _6; // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL + StorageLive(_11); // scope 14 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + _11 = _9 as *mut () (PtrToPtr); // scope 15 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL + StorageLive(_14); // scope 17 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL + StorageLive(_13); // scope 17 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL + StorageLive(_12); // scope 17 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL + _12 = _11 as *const () (Pointer(MutToConstPointer)); // scope 17 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL + _13 = ptr::metadata::PtrComponents::<[u32]> { data_address: move _12, metadata: _10 }; // scope 17 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL + StorageDead(_12); // scope 17 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL + _14 = ptr::metadata::PtrRepr::<[u32]> { const_ptr: move _13 }; // scope 17 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL + StorageDead(_13); // scope 17 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL + _15 = (_14.1: *mut [u32]); // scope 17 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL + StorageDead(_14); // scope 16 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL + StorageDead(_11); // scope 14 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL StorageDead(_10); // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL - StorageLive(_12); // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL - _12 = _6; // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL - StorageLive(_16); // scope 14 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL - _16 = _9 as *mut () (PtrToPtr); // scope 15 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL - StorageLive(_17); // scope 17 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL - StorageLive(_18); // scope 17 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL - StorageLive(_19); // scope 17 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL - _19 = _16 as *const () (Pointer(MutToConstPointer)); // scope 17 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL - _18 = ptr::metadata::PtrComponents::<[u32]> { data_address: move _19, metadata: _12 }; // scope 17 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL - StorageDead(_19); // scope 17 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL - _17 = ptr::metadata::PtrRepr::<[u32]> { const_ptr: move _18 }; // scope 17 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL - StorageDead(_18); // scope 17 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL - _3 = (_17.1: *mut [u32]); // scope 17 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL - StorageDead(_17); // scope 16 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL - StorageDead(_16); // scope 14 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL - StorageDead(_12); // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL StorageDead(_9); // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL StorageDead(_6); // scope 5 at $SRC_DIR/core/src/slice/index.rs:LL:COL - StorageDead(_15); // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL - StorageDead(_14); // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL - StorageDead(_13); // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL - StorageDead(_5); // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL - StorageDead(_4); // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL - _0 = &mut (*_3); // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL - StorageDead(_3); // scope 1 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + StorageDead(_19); // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + StorageDead(_18); // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + StorageDead(_17); // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + StorageDead(_16); // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + StorageDead(_3); // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + _0 = &mut (*_15); // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + StorageDead(_15); // scope 1 at $SRC_DIR/core/src/slice/mod.rs:LL:COL return; // scope 0 at $DIR/slice_index.rs:+2:2: +2:2 } } diff --git a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.mir index 0da7e5536ae..0cf1d68d18a 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.mir @@ -4,41 +4,41 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { debug slice => _1; // in scope 0 at $DIR/slice_iter.rs:+0:28: +0:33 debug f => _2; // in scope 0 at $DIR/slice_iter.rs:+0:44: +0:45 let mut _0: (); // return place in scope 0 at $DIR/slice_iter.rs:+0:60: +0:60 - let mut _3: std::slice::Iter<'_, T>; // in scope 0 at $DIR/slice_iter.rs:+1:14: +1:26 - let mut _4: std::slice::Iter<'_, T>; // in scope 0 at $DIR/slice_iter.rs:+1:14: +1:26 - let _5: (); // in scope 0 at $DIR/slice_iter.rs:+1:14: +1:26 - let mut _6: std::option::Option<&T>; // in scope 0 at $DIR/slice_iter.rs:+1:14: +1:26 - let mut _7: &mut std::slice::Iter<'_, T>; // in scope 0 at $DIR/slice_iter.rs:+1:14: +1:26 - let mut _8: isize; // in scope 0 at $DIR/slice_iter.rs:+1:5: +3:6 - let mut _10: &impl Fn(&T); // in scope 0 at $DIR/slice_iter.rs:+2:9: +2:10 - let mut _11: (&T,); // in scope 0 at $DIR/slice_iter.rs:+2:9: +2:13 + let mut _13: std::slice::Iter<'_, T>; // in scope 0 at $DIR/slice_iter.rs:+1:14: +1:26 + let mut _14: std::slice::Iter<'_, T>; // in scope 0 at $DIR/slice_iter.rs:+1:14: +1:26 + let mut _15: &mut std::slice::Iter<'_, T>; // in scope 0 at $DIR/slice_iter.rs:+1:14: +1:26 + let mut _16: std::option::Option<&T>; // in scope 0 at $DIR/slice_iter.rs:+1:14: +1:26 + let mut _17: isize; // in scope 0 at $DIR/slice_iter.rs:+1:5: +3:6 + let mut _19: &impl Fn(&T); // in scope 0 at $DIR/slice_iter.rs:+2:9: +2:10 + let mut _20: (&T,); // in scope 0 at $DIR/slice_iter.rs:+2:9: +2:13 + let _21: (); // in scope 0 at $DIR/slice_iter.rs:+1:14: +1:26 scope 1 { - debug iter => _4; // in scope 1 at $DIR/slice_iter.rs:+1:14: +1:26 - let _9: &T; // in scope 1 at $DIR/slice_iter.rs:+1:9: +1:10 + debug iter => _14; // in scope 1 at $DIR/slice_iter.rs:+1:14: +1:26 + let _18: &T; // in scope 1 at $DIR/slice_iter.rs:+1:9: +1:10 scope 2 { - debug x => _9; // in scope 2 at $DIR/slice_iter.rs:+1:9: +1:10 + debug x => _18; // in scope 2 at $DIR/slice_iter.rs:+1:9: +1:10 } } scope 3 (inlined core::slice::<impl [T]>::iter) { // at $DIR/slice_iter.rs:28:20: 28:26 debug self => _1; // in scope 3 at $SRC_DIR/core/src/slice/mod.rs:LL:COL scope 4 (inlined std::slice::Iter::<'_, T>::new) { // at $SRC_DIR/core/src/slice/mod.rs:LL:COL debug slice => _1; // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - let _12: *const T; // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - let mut _14: bool; // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - let mut _15: usize; // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - let mut _16: usize; // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - let mut _17: std::ptr::NonNull<T>; // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - let mut _18: *mut T; // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - let mut _19: *const T; // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + let _4: *const T; // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + let mut _5: bool; // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + let mut _6: usize; // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + let mut _8: usize; // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + let mut _9: *mut T; // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + let mut _11: std::ptr::NonNull<T>; // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + let mut _12: *const T; // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL scope 5 { - debug ptr => _12; // in scope 5 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + debug ptr => _4; // in scope 5 at $SRC_DIR/core/src/slice/iter.rs:LL:COL scope 6 { - let _13: *const T; // in scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + let _7: *const T; // in scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL scope 7 { - debug end => _13; // in scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + debug end => _7; // in scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL scope 13 (inlined NonNull::<T>::new_unchecked) { // at $SRC_DIR/core/src/slice/iter.rs:LL:COL - debug ptr => _18; // in scope 13 at $SRC_DIR/core/src/ptr/non_null.rs:LL:COL - let mut _21: *const T; // in scope 13 at $SRC_DIR/core/src/ptr/non_null.rs:LL:COL + debug ptr => _9; // in scope 13 at $SRC_DIR/core/src/ptr/non_null.rs:LL:COL + let mut _10: *const T; // in scope 13 at $SRC_DIR/core/src/ptr/non_null.rs:LL:COL let mut _22: *mut T; // in scope 13 at $SRC_DIR/core/src/intrinsics.rs:LL:COL scope 14 { scope 15 (inlined NonNull::<T>::new_unchecked::runtime::<T>) { // at $SRC_DIR/core/src/intrinsics.rs:LL:COL @@ -65,13 +65,13 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { } } scope 9 (inlined invalid::<T>) { // at $SRC_DIR/core/src/slice/iter.rs:LL:COL - debug addr => _15; // in scope 9 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + debug addr => _8; // in scope 9 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL scope 10 { } } scope 11 (inlined ptr::const_ptr::<impl *const T>::add) { // at $SRC_DIR/core/src/slice/iter.rs:LL:COL - debug self => _12; // in scope 11 at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL - debug count => _16; // in scope 11 at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + debug self => _4; // in scope 11 at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + debug count => _6; // in scope 11 at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL scope 12 { } } @@ -79,125 +79,125 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { } scope 8 (inlined core::slice::<impl [T]>::as_ptr) { // at $SRC_DIR/core/src/slice/iter.rs:LL:COL debug self => _1; // in scope 8 at $SRC_DIR/core/src/slice/mod.rs:LL:COL - let mut _20: *const [T]; // in scope 8 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + let mut _3: *const [T]; // in scope 8 at $SRC_DIR/core/src/slice/mod.rs:LL:COL } } } scope 22 (inlined <std::slice::Iter<'_, T> as IntoIterator>::into_iter) { // at $DIR/slice_iter.rs:28:14: 28:26 - debug self => _3; // in scope 22 at $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL + debug self => _13; // in scope 22 at $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL } bb0: { - StorageLive(_12); // scope 3 at $SRC_DIR/core/src/slice/mod.rs:LL:COL - StorageLive(_20); // scope 8 at $SRC_DIR/core/src/slice/mod.rs:LL:COL - _20 = &raw const (*_1); // scope 8 at $SRC_DIR/core/src/slice/mod.rs:LL:COL - _12 = move _20 as *const T (PtrToPtr); // scope 8 at $SRC_DIR/core/src/slice/mod.rs:LL:COL - StorageDead(_20); // scope 8 at $SRC_DIR/core/src/slice/mod.rs:LL:COL - StorageLive(_13); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - StorageLive(_14); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - _14 = const _; // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - switchInt(move _14) -> [0: bb11, otherwise: bb10]; // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageLive(_4); // scope 3 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + StorageLive(_3); // scope 8 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + _3 = &raw const (*_1); // scope 8 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + _4 = move _3 as *const T (PtrToPtr); // scope 8 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + StorageDead(_3); // scope 8 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + StorageLive(_7); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageLive(_5); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + _5 = const _; // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + switchInt(move _5) -> [0: bb1, otherwise: bb2]; // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL } bb1: { - StorageLive(_6); // scope 1 at $DIR/slice_iter.rs:+1:14: +1:26 - _7 = &mut _4; // scope 1 at $DIR/slice_iter.rs:+1:14: +1:26 - _6 = <std::slice::Iter<'_, T> as Iterator>::next(_7) -> [return: bb2, unwind: bb8]; // scope 1 at $DIR/slice_iter.rs:+1:14: +1:26 - // mir::Constant - // + span: $DIR/slice_iter.rs:28:14: 28:26 - // + literal: Const { ty: for<'a> fn(&'a mut std::slice::Iter<'_, T>) -> Option<<std::slice::Iter<'_, T> as Iterator>::Item> {<std::slice::Iter<'_, T> as Iterator>::next}, val: Value(<ZST>) } + StorageLive(_6); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + _6 = Len((*_1)); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + _7 = Offset(_4, _6); // scope 12 at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + StorageDead(_6); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + goto -> bb3; // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL } bb2: { - _8 = discriminant(_6); // scope 1 at $DIR/slice_iter.rs:+1:14: +1:26 - switchInt(move _8) -> [0: bb5, 1: bb3, otherwise: bb4]; // scope 1 at $DIR/slice_iter.rs:+1:14: +1:26 + StorageLive(_8); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + _8 = Len((*_1)); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + _7 = _8 as *const T (Transmute); // scope 10 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + StorageDead(_8); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + goto -> bb3; // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL } bb3: { - _9 = ((_6 as Some).0: &T); // scope 1 at $DIR/slice_iter.rs:+1:9: +1:10 - StorageLive(_10); // scope 2 at $DIR/slice_iter.rs:+2:9: +2:10 - _10 = &_2; // scope 2 at $DIR/slice_iter.rs:+2:9: +2:10 - StorageLive(_11); // scope 2 at $DIR/slice_iter.rs:+2:9: +2:13 - _11 = (_9,); // scope 2 at $DIR/slice_iter.rs:+2:9: +2:13 - _5 = <impl Fn(&T) as Fn<(&T,)>>::call(move _10, move _11) -> [return: bb6, unwind: bb8]; // scope 2 at $DIR/slice_iter.rs:+2:9: +2:13 + StorageDead(_5); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageLive(_11); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageLive(_9); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + _9 = _4 as *mut T (PtrToPtr); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageLive(_10); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageLive(_22); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageLive(_23); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + _10 = _9 as *const T (Pointer(MutToConstPointer)); // scope 14 at $SRC_DIR/core/src/ptr/non_null.rs:LL:COL + _11 = NonNull::<T> { pointer: _10 }; // scope 14 at $SRC_DIR/core/src/ptr/non_null.rs:LL:COL + StorageDead(_23); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageDead(_22); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageDead(_10); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageDead(_9); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageLive(_12); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + _12 = _7; // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + _13 = std::slice::Iter::<'_, T> { ptr: move _11, end: move _12, _marker: const ZeroSized: PhantomData<&T> }; // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL // mir::Constant - // + span: $DIR/slice_iter.rs:29:9: 29:10 - // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a impl Fn(&T), (&T,)) -> <impl Fn(&T) as FnOnce<(&T,)>>::Output {<impl Fn(&T) as Fn<(&T,)>>::call}, val: Value(<ZST>) } + // + span: no-location + // + literal: Const { ty: PhantomData<&T>, val: Value(<ZST>) } + // adt + // + user_ty: UserType(1) + StorageDead(_12); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageDead(_11); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageDead(_7); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageDead(_4); // scope 3 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + StorageLive(_14); // scope 0 at $DIR/slice_iter.rs:+1:14: +1:26 + _14 = move _13; // scope 0 at $DIR/slice_iter.rs:+1:14: +1:26 + goto -> bb4; // scope 1 at $DIR/slice_iter.rs:+1:5: +3:6 } bb4: { - unreachable; // scope 1 at $DIR/slice_iter.rs:+1:14: +1:26 + StorageLive(_16); // scope 1 at $DIR/slice_iter.rs:+1:14: +1:26 + _15 = &mut _14; // scope 1 at $DIR/slice_iter.rs:+1:14: +1:26 + _16 = <std::slice::Iter<'_, T> as Iterator>::next(_15) -> [return: bb5, unwind: bb11]; // scope 1 at $DIR/slice_iter.rs:+1:14: +1:26 + // mir::Constant + // + span: $DIR/slice_iter.rs:28:14: 28:26 + // + literal: Const { ty: for<'a> fn(&'a mut std::slice::Iter<'_, T>) -> Option<<std::slice::Iter<'_, T> as Iterator>::Item> {<std::slice::Iter<'_, T> as Iterator>::next}, val: Value(<ZST>) } } bb5: { - StorageDead(_6); // scope 1 at $DIR/slice_iter.rs:+3:5: +3:6 - StorageDead(_4); // scope 0 at $DIR/slice_iter.rs:+3:5: +3:6 - drop(_2) -> bb7; // scope 0 at $DIR/slice_iter.rs:+4:1: +4:2 + _17 = discriminant(_16); // scope 1 at $DIR/slice_iter.rs:+1:14: +1:26 + switchInt(move _17) -> [0: bb6, 1: bb8, otherwise: bb10]; // scope 1 at $DIR/slice_iter.rs:+1:14: +1:26 } bb6: { - StorageDead(_11); // scope 2 at $DIR/slice_iter.rs:+2:12: +2:13 - StorageDead(_10); // scope 2 at $DIR/slice_iter.rs:+2:12: +2:13 - StorageDead(_6); // scope 1 at $DIR/slice_iter.rs:+3:5: +3:6 - goto -> bb1; // scope 1 at $DIR/slice_iter.rs:+1:5: +3:6 + StorageDead(_16); // scope 1 at $DIR/slice_iter.rs:+3:5: +3:6 + StorageDead(_14); // scope 0 at $DIR/slice_iter.rs:+3:5: +3:6 + drop(_2) -> bb7; // scope 0 at $DIR/slice_iter.rs:+4:1: +4:2 } bb7: { return; // scope 0 at $DIR/slice_iter.rs:+4:2: +4:2 } - bb8 (cleanup): { - drop(_2) -> [return: bb9, unwind terminate]; // scope 0 at $DIR/slice_iter.rs:+4:1: +4:2 + bb8: { + _18 = ((_16 as Some).0: &T); // scope 1 at $DIR/slice_iter.rs:+1:9: +1:10 + StorageLive(_19); // scope 2 at $DIR/slice_iter.rs:+2:9: +2:10 + _19 = &_2; // scope 2 at $DIR/slice_iter.rs:+2:9: +2:10 + StorageLive(_20); // scope 2 at $DIR/slice_iter.rs:+2:9: +2:13 + _20 = (_18,); // scope 2 at $DIR/slice_iter.rs:+2:9: +2:13 + _21 = <impl Fn(&T) as Fn<(&T,)>>::call(move _19, move _20) -> [return: bb9, unwind: bb11]; // scope 2 at $DIR/slice_iter.rs:+2:9: +2:13 + // mir::Constant + // + span: $DIR/slice_iter.rs:29:9: 29:10 + // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a impl Fn(&T), (&T,)) -> <impl Fn(&T) as FnOnce<(&T,)>>::Output {<impl Fn(&T) as Fn<(&T,)>>::call}, val: Value(<ZST>) } } - bb9 (cleanup): { - resume; // scope 0 at $DIR/slice_iter.rs:+0:1: +4:2 + bb9: { + StorageDead(_20); // scope 2 at $DIR/slice_iter.rs:+2:12: +2:13 + StorageDead(_19); // scope 2 at $DIR/slice_iter.rs:+2:12: +2:13 + StorageDead(_16); // scope 1 at $DIR/slice_iter.rs:+3:5: +3:6 + goto -> bb4; // scope 1 at $DIR/slice_iter.rs:+1:5: +3:6 } bb10: { - StorageLive(_15); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - _15 = Len((*_1)); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - _13 = _15 as *const T (Transmute); // scope 10 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL - StorageDead(_15); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - goto -> bb12; // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + unreachable; // scope 1 at $DIR/slice_iter.rs:+1:14: +1:26 } - bb11: { - StorageLive(_16); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - _16 = Len((*_1)); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - _13 = Offset(_12, _16); // scope 12 at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL - StorageDead(_16); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - goto -> bb12; // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + bb11 (cleanup): { + drop(_2) -> [return: bb12, unwind terminate]; // scope 0 at $DIR/slice_iter.rs:+4:1: +4:2 } - bb12: { - StorageDead(_14); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - StorageLive(_17); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - StorageLive(_18); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - _18 = _12 as *mut T (PtrToPtr); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - StorageLive(_21); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - StorageLive(_22); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - StorageLive(_23); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - _21 = _18 as *const T (Pointer(MutToConstPointer)); // scope 14 at $SRC_DIR/core/src/ptr/non_null.rs:LL:COL - _17 = NonNull::<T> { pointer: _21 }; // scope 14 at $SRC_DIR/core/src/ptr/non_null.rs:LL:COL - StorageDead(_23); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - StorageDead(_22); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - StorageDead(_21); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - StorageDead(_18); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - StorageLive(_19); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - _19 = _13; // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - _3 = std::slice::Iter::<'_, T> { ptr: move _17, end: move _19, _marker: const ZeroSized: PhantomData<&T> }; // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - // mir::Constant - // + span: no-location - // + literal: Const { ty: PhantomData<&T>, val: Value(<ZST>) } - // adt - // + user_ty: UserType(1) - StorageDead(_19); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - StorageDead(_17); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - StorageDead(_13); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - StorageDead(_12); // scope 3 at $SRC_DIR/core/src/slice/mod.rs:LL:COL - StorageLive(_4); // scope 0 at $DIR/slice_iter.rs:+1:14: +1:26 - _4 = move _3; // scope 0 at $DIR/slice_iter.rs:+1:14: +1:26 - goto -> bb1; // scope 1 at $DIR/slice_iter.rs:+1:5: +3:6 + bb12 (cleanup): { + resume; // scope 0 at $DIR/slice_iter.rs:+0:1: +4:2 } } diff --git a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.mir index 45b41b54c8b..4fde50c6fe4 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.mir @@ -4,61 +4,61 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { debug slice => _1; // in scope 0 at $DIR/slice_iter.rs:+0:28: +0:33 debug f => _2; // in scope 0 at $DIR/slice_iter.rs:+0:44: +0:45 let mut _0: (); // return place in scope 0 at $DIR/slice_iter.rs:+0:60: +0:60 - let mut _3: std::iter::Rev<std::slice::Iter<'_, T>>; // in scope 0 at $DIR/slice_iter.rs:+1:14: +1:32 - let mut _4: std::slice::Iter<'_, T>; // in scope 0 at $DIR/slice_iter.rs:+1:14: +1:26 - let mut _5: std::iter::Rev<std::slice::Iter<'_, T>>; // in scope 0 at $DIR/slice_iter.rs:+1:14: +1:32 - let _6: (); // in scope 0 at $DIR/slice_iter.rs:+1:14: +1:32 - let mut _7: std::option::Option<&T>; // in scope 0 at $DIR/slice_iter.rs:+1:14: +1:32 - let mut _8: &mut std::iter::Rev<std::slice::Iter<'_, T>>; // in scope 0 at $DIR/slice_iter.rs:+1:14: +1:32 - let mut _9: isize; // in scope 0 at $DIR/slice_iter.rs:+1:5: +3:6 - let mut _11: &impl Fn(&T); // in scope 0 at $DIR/slice_iter.rs:+2:9: +2:10 - let mut _12: (&T,); // in scope 0 at $DIR/slice_iter.rs:+2:9: +2:13 + let mut _13: std::slice::Iter<'_, T>; // in scope 0 at $DIR/slice_iter.rs:+1:14: +1:26 + let mut _14: std::iter::Rev<std::slice::Iter<'_, T>>; // in scope 0 at $DIR/slice_iter.rs:+1:14: +1:32 + let mut _15: std::iter::Rev<std::slice::Iter<'_, T>>; // in scope 0 at $DIR/slice_iter.rs:+1:14: +1:32 + let mut _16: &mut std::iter::Rev<std::slice::Iter<'_, T>>; // in scope 0 at $DIR/slice_iter.rs:+1:14: +1:32 + let mut _18: std::option::Option<&T>; // in scope 0 at $DIR/slice_iter.rs:+1:14: +1:32 + let mut _19: isize; // in scope 0 at $DIR/slice_iter.rs:+1:5: +3:6 + let mut _21: &impl Fn(&T); // in scope 0 at $DIR/slice_iter.rs:+2:9: +2:10 + let mut _22: (&T,); // in scope 0 at $DIR/slice_iter.rs:+2:9: +2:13 + let _23: (); // in scope 0 at $DIR/slice_iter.rs:+1:14: +1:32 scope 1 { - debug iter => _5; // in scope 1 at $DIR/slice_iter.rs:+1:14: +1:32 - let _10: &T; // in scope 1 at $DIR/slice_iter.rs:+1:9: +1:10 + debug iter => _15; // in scope 1 at $DIR/slice_iter.rs:+1:14: +1:32 + let _20: &T; // in scope 1 at $DIR/slice_iter.rs:+1:9: +1:10 scope 2 { - debug x => _10; // in scope 2 at $DIR/slice_iter.rs:+1:9: +1:10 + debug x => _20; // in scope 2 at $DIR/slice_iter.rs:+1:9: +1:10 } scope 25 (inlined <Rev<std::slice::Iter<'_, T>> as Iterator>::next) { // at $DIR/slice_iter.rs:35:14: 35:32 - debug self => _8; // in scope 25 at $SRC_DIR/core/src/iter/adapters/rev.rs:LL:COL - let mut _25: &mut std::slice::Iter<'_, T>; // in scope 25 at $SRC_DIR/core/src/iter/adapters/rev.rs:LL:COL + debug self => _16; // in scope 25 at $SRC_DIR/core/src/iter/adapters/rev.rs:LL:COL + let mut _17: &mut std::slice::Iter<'_, T>; // in scope 25 at $SRC_DIR/core/src/iter/adapters/rev.rs:LL:COL } } scope 3 (inlined core::slice::<impl [T]>::iter) { // at $DIR/slice_iter.rs:35:20: 35:26 debug self => _1; // in scope 3 at $SRC_DIR/core/src/slice/mod.rs:LL:COL scope 4 (inlined std::slice::Iter::<'_, T>::new) { // at $SRC_DIR/core/src/slice/mod.rs:LL:COL debug slice => _1; // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - let _13: *const T; // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - let mut _15: bool; // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - let mut _16: usize; // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - let mut _17: usize; // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - let mut _18: std::ptr::NonNull<T>; // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - let mut _19: *mut T; // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - let mut _20: *const T; // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + let _4: *const T; // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + let mut _5: bool; // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + let mut _6: usize; // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + let mut _8: usize; // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + let mut _9: *mut T; // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + let mut _11: std::ptr::NonNull<T>; // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + let mut _12: *const T; // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL scope 5 { - debug ptr => _13; // in scope 5 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + debug ptr => _4; // in scope 5 at $SRC_DIR/core/src/slice/iter.rs:LL:COL scope 6 { - let _14: *const T; // in scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + let _7: *const T; // in scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL scope 7 { - debug end => _14; // in scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + debug end => _7; // in scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL scope 13 (inlined NonNull::<T>::new_unchecked) { // at $SRC_DIR/core/src/slice/iter.rs:LL:COL - debug ptr => _19; // in scope 13 at $SRC_DIR/core/src/ptr/non_null.rs:LL:COL - let mut _22: *const T; // in scope 13 at $SRC_DIR/core/src/ptr/non_null.rs:LL:COL - let mut _23: *mut T; // in scope 13 at $SRC_DIR/core/src/intrinsics.rs:LL:COL + debug ptr => _9; // in scope 13 at $SRC_DIR/core/src/ptr/non_null.rs:LL:COL + let mut _10: *const T; // in scope 13 at $SRC_DIR/core/src/ptr/non_null.rs:LL:COL + let mut _24: *mut T; // in scope 13 at $SRC_DIR/core/src/intrinsics.rs:LL:COL scope 14 { scope 15 (inlined NonNull::<T>::new_unchecked::runtime::<T>) { // at $SRC_DIR/core/src/intrinsics.rs:LL:COL - debug ptr => _23; // in scope 15 at $SRC_DIR/core/src/intrinsics.rs:LL:COL + debug ptr => _24; // in scope 15 at $SRC_DIR/core/src/intrinsics.rs:LL:COL scope 16 (inlined ptr::mut_ptr::<impl *mut T>::is_null) { // at $SRC_DIR/core/src/ptr/non_null.rs:LL:COL - debug self => _23; // in scope 16 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL - let mut _24: *mut u8; // in scope 16 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL + debug self => _24; // in scope 16 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL + let mut _25: *mut u8; // in scope 16 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL scope 17 { scope 18 (inlined ptr::mut_ptr::<impl *mut T>::is_null::runtime_impl) { // at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL - debug ptr => _24; // in scope 18 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL + debug ptr => _25; // in scope 18 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL scope 19 (inlined ptr::mut_ptr::<impl *mut u8>::addr) { // at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL - debug self => _24; // in scope 19 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL + debug self => _25; // in scope 19 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL scope 20 { scope 21 (inlined ptr::mut_ptr::<impl *mut u8>::cast::<()>) { // at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL - debug self => _24; // in scope 21 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL + debug self => _25; // in scope 21 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL } } } @@ -70,13 +70,13 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { } } scope 9 (inlined invalid::<T>) { // at $SRC_DIR/core/src/slice/iter.rs:LL:COL - debug addr => _16; // in scope 9 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + debug addr => _8; // in scope 9 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL scope 10 { } } scope 11 (inlined ptr::const_ptr::<impl *const T>::add) { // at $SRC_DIR/core/src/slice/iter.rs:LL:COL - debug self => _13; // in scope 11 at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL - debug count => _17; // in scope 11 at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + debug self => _4; // in scope 11 at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + debug count => _6; // in scope 11 at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL scope 12 { } } @@ -84,137 +84,137 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { } scope 8 (inlined core::slice::<impl [T]>::as_ptr) { // at $SRC_DIR/core/src/slice/iter.rs:LL:COL debug self => _1; // in scope 8 at $SRC_DIR/core/src/slice/mod.rs:LL:COL - let mut _21: *const [T]; // in scope 8 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + let mut _3: *const [T]; // in scope 8 at $SRC_DIR/core/src/slice/mod.rs:LL:COL } } } scope 22 (inlined <std::slice::Iter<'_, T> as Iterator>::rev) { // at $DIR/slice_iter.rs:35:27: 35:32 - debug self => _4; // in scope 22 at $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL + debug self => _13; // in scope 22 at $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL scope 23 (inlined Rev::<std::slice::Iter<'_, T>>::new) { // at $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL - debug iter => _4; // in scope 23 at $SRC_DIR/core/src/iter/adapters/rev.rs:LL:COL + debug iter => _13; // in scope 23 at $SRC_DIR/core/src/iter/adapters/rev.rs:LL:COL } } scope 24 (inlined <Rev<std::slice::Iter<'_, T>> as IntoIterator>::into_iter) { // at $DIR/slice_iter.rs:35:14: 35:32 - debug self => _3; // in scope 24 at $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL + debug self => _14; // in scope 24 at $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL } bb0: { - StorageLive(_4); // scope 0 at $DIR/slice_iter.rs:+1:14: +1:26 - StorageLive(_13); // scope 3 at $SRC_DIR/core/src/slice/mod.rs:LL:COL - StorageLive(_21); // scope 8 at $SRC_DIR/core/src/slice/mod.rs:LL:COL - _21 = &raw const (*_1); // scope 8 at $SRC_DIR/core/src/slice/mod.rs:LL:COL - _13 = move _21 as *const T (PtrToPtr); // scope 8 at $SRC_DIR/core/src/slice/mod.rs:LL:COL - StorageDead(_21); // scope 8 at $SRC_DIR/core/src/slice/mod.rs:LL:COL - StorageLive(_14); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - StorageLive(_15); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - _15 = const _; // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - switchInt(move _15) -> [0: bb10, otherwise: bb9]; // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageLive(_13); // scope 0 at $DIR/slice_iter.rs:+1:14: +1:26 + StorageLive(_4); // scope 3 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + StorageLive(_3); // scope 8 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + _3 = &raw const (*_1); // scope 8 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + _4 = move _3 as *const T (PtrToPtr); // scope 8 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + StorageDead(_3); // scope 8 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + StorageLive(_7); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageLive(_5); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + _5 = const _; // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + switchInt(move _5) -> [0: bb1, otherwise: bb2]; // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL } bb1: { - StorageLive(_7); // scope 1 at $DIR/slice_iter.rs:+1:14: +1:32 - _8 = &mut _5; // scope 1 at $DIR/slice_iter.rs:+1:14: +1:32 - StorageLive(_25); // scope 25 at $SRC_DIR/core/src/iter/adapters/rev.rs:LL:COL - _25 = &mut ((*_8).0: std::slice::Iter<'_, T>); // scope 25 at $SRC_DIR/core/src/iter/adapters/rev.rs:LL:COL - _7 = <std::slice::Iter<'_, T> as DoubleEndedIterator>::next_back(move _25) -> [return: bb12, unwind: bb7]; // scope 25 at $SRC_DIR/core/src/iter/adapters/rev.rs:LL:COL - // mir::Constant - // + span: $SRC_DIR/core/src/iter/adapters/rev.rs:LL:COL - // + literal: Const { ty: for<'a> fn(&'a mut std::slice::Iter<'_, T>) -> Option<<std::slice::Iter<'_, T> as Iterator>::Item> {<std::slice::Iter<'_, T> as DoubleEndedIterator>::next_back}, val: Value(<ZST>) } + StorageLive(_6); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + _6 = Len((*_1)); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + _7 = Offset(_4, _6); // scope 12 at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + StorageDead(_6); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + goto -> bb3; // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL } bb2: { - _10 = ((_7 as Some).0: &T); // scope 1 at $DIR/slice_iter.rs:+1:9: +1:10 - StorageLive(_11); // scope 2 at $DIR/slice_iter.rs:+2:9: +2:10 - _11 = &_2; // scope 2 at $DIR/slice_iter.rs:+2:9: +2:10 - StorageLive(_12); // scope 2 at $DIR/slice_iter.rs:+2:9: +2:13 - _12 = (_10,); // scope 2 at $DIR/slice_iter.rs:+2:9: +2:13 - _6 = <impl Fn(&T) as Fn<(&T,)>>::call(move _11, move _12) -> [return: bb5, unwind: bb7]; // scope 2 at $DIR/slice_iter.rs:+2:9: +2:13 - // mir::Constant - // + span: $DIR/slice_iter.rs:36:9: 36:10 - // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a impl Fn(&T), (&T,)) -> <impl Fn(&T) as FnOnce<(&T,)>>::Output {<impl Fn(&T) as Fn<(&T,)>>::call}, val: Value(<ZST>) } + StorageLive(_8); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + _8 = Len((*_1)); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + _7 = _8 as *const T (Transmute); // scope 10 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + StorageDead(_8); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + goto -> bb3; // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL } bb3: { - unreachable; // scope 1 at $DIR/slice_iter.rs:+1:14: +1:32 + StorageDead(_5); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageLive(_11); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageLive(_9); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + _9 = _4 as *mut T (PtrToPtr); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageLive(_10); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageLive(_24); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageLive(_25); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + _10 = _9 as *const T (Pointer(MutToConstPointer)); // scope 14 at $SRC_DIR/core/src/ptr/non_null.rs:LL:COL + _11 = NonNull::<T> { pointer: _10 }; // scope 14 at $SRC_DIR/core/src/ptr/non_null.rs:LL:COL + StorageDead(_25); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageDead(_24); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageDead(_10); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageDead(_9); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageLive(_12); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + _12 = _7; // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + _13 = std::slice::Iter::<'_, T> { ptr: move _11, end: move _12, _marker: const ZeroSized: PhantomData<&T> }; // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + // mir::Constant + // + span: no-location + // + literal: Const { ty: PhantomData<&T>, val: Value(<ZST>) } + // adt + // + user_ty: UserType(1) + StorageDead(_12); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageDead(_11); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageDead(_7); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageDead(_4); // scope 3 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + _14 = Rev::<std::slice::Iter<'_, T>> { iter: move _13 }; // scope 23 at $SRC_DIR/core/src/iter/adapters/rev.rs:LL:COL + StorageDead(_13); // scope 0 at $DIR/slice_iter.rs:+1:31: +1:32 + StorageLive(_15); // scope 0 at $DIR/slice_iter.rs:+1:14: +1:32 + _15 = move _14; // scope 0 at $DIR/slice_iter.rs:+1:14: +1:32 + goto -> bb4; // scope 1 at $DIR/slice_iter.rs:+1:5: +3:6 } bb4: { - StorageDead(_7); // scope 1 at $DIR/slice_iter.rs:+3:5: +3:6 - StorageDead(_5); // scope 0 at $DIR/slice_iter.rs:+3:5: +3:6 - drop(_2) -> bb6; // scope 0 at $DIR/slice_iter.rs:+4:1: +4:2 + StorageLive(_18); // scope 1 at $DIR/slice_iter.rs:+1:14: +1:32 + _16 = &mut _15; // scope 1 at $DIR/slice_iter.rs:+1:14: +1:32 + StorageLive(_17); // scope 25 at $SRC_DIR/core/src/iter/adapters/rev.rs:LL:COL + _17 = &mut ((*_16).0: std::slice::Iter<'_, T>); // scope 25 at $SRC_DIR/core/src/iter/adapters/rev.rs:LL:COL + _18 = <std::slice::Iter<'_, T> as DoubleEndedIterator>::next_back(move _17) -> [return: bb5, unwind: bb11]; // scope 25 at $SRC_DIR/core/src/iter/adapters/rev.rs:LL:COL + // mir::Constant + // + span: $SRC_DIR/core/src/iter/adapters/rev.rs:LL:COL + // + literal: Const { ty: for<'a> fn(&'a mut std::slice::Iter<'_, T>) -> Option<<std::slice::Iter<'_, T> as Iterator>::Item> {<std::slice::Iter<'_, T> as DoubleEndedIterator>::next_back}, val: Value(<ZST>) } } bb5: { - StorageDead(_12); // scope 2 at $DIR/slice_iter.rs:+2:12: +2:13 - StorageDead(_11); // scope 2 at $DIR/slice_iter.rs:+2:12: +2:13 - StorageDead(_7); // scope 1 at $DIR/slice_iter.rs:+3:5: +3:6 - goto -> bb1; // scope 1 at $DIR/slice_iter.rs:+1:5: +3:6 + StorageDead(_17); // scope 25 at $SRC_DIR/core/src/iter/adapters/rev.rs:LL:COL + _19 = discriminant(_18); // scope 1 at $DIR/slice_iter.rs:+1:14: +1:32 + switchInt(move _19) -> [0: bb6, 1: bb8, otherwise: bb10]; // scope 1 at $DIR/slice_iter.rs:+1:14: +1:32 } bb6: { - return; // scope 0 at $DIR/slice_iter.rs:+4:2: +4:2 + StorageDead(_18); // scope 1 at $DIR/slice_iter.rs:+3:5: +3:6 + StorageDead(_15); // scope 0 at $DIR/slice_iter.rs:+3:5: +3:6 + drop(_2) -> bb7; // scope 0 at $DIR/slice_iter.rs:+4:1: +4:2 } - bb7 (cleanup): { - drop(_2) -> [return: bb8, unwind terminate]; // scope 0 at $DIR/slice_iter.rs:+4:1: +4:2 + bb7: { + return; // scope 0 at $DIR/slice_iter.rs:+4:2: +4:2 } - bb8 (cleanup): { - resume; // scope 0 at $DIR/slice_iter.rs:+0:1: +4:2 + bb8: { + _20 = ((_18 as Some).0: &T); // scope 1 at $DIR/slice_iter.rs:+1:9: +1:10 + StorageLive(_21); // scope 2 at $DIR/slice_iter.rs:+2:9: +2:10 + _21 = &_2; // scope 2 at $DIR/slice_iter.rs:+2:9: +2:10 + StorageLive(_22); // scope 2 at $DIR/slice_iter.rs:+2:9: +2:13 + _22 = (_20,); // scope 2 at $DIR/slice_iter.rs:+2:9: +2:13 + _23 = <impl Fn(&T) as Fn<(&T,)>>::call(move _21, move _22) -> [return: bb9, unwind: bb11]; // scope 2 at $DIR/slice_iter.rs:+2:9: +2:13 + // mir::Constant + // + span: $DIR/slice_iter.rs:36:9: 36:10 + // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a impl Fn(&T), (&T,)) -> <impl Fn(&T) as FnOnce<(&T,)>>::Output {<impl Fn(&T) as Fn<(&T,)>>::call}, val: Value(<ZST>) } } bb9: { - StorageLive(_16); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - _16 = Len((*_1)); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - _14 = _16 as *const T (Transmute); // scope 10 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL - StorageDead(_16); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - goto -> bb11; // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageDead(_22); // scope 2 at $DIR/slice_iter.rs:+2:12: +2:13 + StorageDead(_21); // scope 2 at $DIR/slice_iter.rs:+2:12: +2:13 + StorageDead(_18); // scope 1 at $DIR/slice_iter.rs:+3:5: +3:6 + goto -> bb4; // scope 1 at $DIR/slice_iter.rs:+1:5: +3:6 } bb10: { - StorageLive(_17); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - _17 = Len((*_1)); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - _14 = Offset(_13, _17); // scope 12 at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL - StorageDead(_17); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - goto -> bb11; // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + unreachable; // scope 1 at $DIR/slice_iter.rs:+1:14: +1:32 } - bb11: { - StorageDead(_15); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - StorageLive(_18); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - StorageLive(_19); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - _19 = _13 as *mut T (PtrToPtr); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - StorageLive(_22); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - StorageLive(_23); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - StorageLive(_24); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - _22 = _19 as *const T (Pointer(MutToConstPointer)); // scope 14 at $SRC_DIR/core/src/ptr/non_null.rs:LL:COL - _18 = NonNull::<T> { pointer: _22 }; // scope 14 at $SRC_DIR/core/src/ptr/non_null.rs:LL:COL - StorageDead(_24); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - StorageDead(_23); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - StorageDead(_22); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - StorageDead(_19); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - StorageLive(_20); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - _20 = _14; // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - _4 = std::slice::Iter::<'_, T> { ptr: move _18, end: move _20, _marker: const ZeroSized: PhantomData<&T> }; // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - // mir::Constant - // + span: no-location - // + literal: Const { ty: PhantomData<&T>, val: Value(<ZST>) } - // adt - // + user_ty: UserType(1) - StorageDead(_20); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - StorageDead(_18); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - StorageDead(_14); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - StorageDead(_13); // scope 3 at $SRC_DIR/core/src/slice/mod.rs:LL:COL - _3 = Rev::<std::slice::Iter<'_, T>> { iter: move _4 }; // scope 23 at $SRC_DIR/core/src/iter/adapters/rev.rs:LL:COL - StorageDead(_4); // scope 0 at $DIR/slice_iter.rs:+1:31: +1:32 - StorageLive(_5); // scope 0 at $DIR/slice_iter.rs:+1:14: +1:32 - _5 = move _3; // scope 0 at $DIR/slice_iter.rs:+1:14: +1:32 - goto -> bb1; // scope 1 at $DIR/slice_iter.rs:+1:5: +3:6 + bb11 (cleanup): { + drop(_2) -> [return: bb12, unwind terminate]; // scope 0 at $DIR/slice_iter.rs:+4:1: +4:2 } - bb12: { - StorageDead(_25); // scope 25 at $SRC_DIR/core/src/iter/adapters/rev.rs:LL:COL - _9 = discriminant(_7); // scope 1 at $DIR/slice_iter.rs:+1:14: +1:32 - switchInt(move _9) -> [0: bb4, 1: bb2, otherwise: bb3]; // scope 1 at $DIR/slice_iter.rs:+1:14: +1:32 + bb12 (cleanup): { + resume; // scope 0 at $DIR/slice_iter.rs:+0:1: +4:2 } } diff --git a/tests/mir-opt/pre-codegen/try_identity.new.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/try_identity.new.PreCodegen.after.mir index 53971b4cffc..c3f8745b422 100644 --- a/tests/mir-opt/pre-codegen/try_identity.new.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/try_identity.new.PreCodegen.after.mir @@ -3,15 +3,15 @@ fn new(_1: Result<T, E>) -> Result<T, E> { debug x => _1; // in scope 0 at $DIR/try_identity.rs:+0:14: +0:15 let mut _0: std::result::Result<T, E>; // return place in scope 0 at $DIR/try_identity.rs:+0:34: +0:46 - let mut _2: std::ops::ControlFlow<E, T>; // in scope 0 at $DIR/try_identity.rs:+2:15: +7:10 - let mut _3: isize; // in scope 0 at $DIR/try_identity.rs:+4:17: +4:22 - let _4: T; // in scope 0 at $DIR/try_identity.rs:+4:20: +4:21 + let mut _2: isize; // in scope 0 at $DIR/try_identity.rs:+4:17: +4:22 + let _3: T; // in scope 0 at $DIR/try_identity.rs:+4:20: +4:21 + let mut _4: std::ops::ControlFlow<E, T>; // in scope 0 at $DIR/try_identity.rs:+2:15: +7:10 let _5: E; // in scope 0 at $DIR/try_identity.rs:+5:21: +5:22 let mut _6: isize; // in scope 0 at $DIR/try_identity.rs:+8:13: +8:37 let _7: T; // in scope 0 at $DIR/try_identity.rs:+8:35: +8:36 let _8: E; // in scope 0 at $DIR/try_identity.rs:+9:32: +9:33 scope 1 { - debug v => _4; // in scope 1 at $DIR/try_identity.rs:+4:20: +4:21 + debug v => _3; // in scope 1 at $DIR/try_identity.rs:+4:20: +4:21 } scope 2 { debug e => _5; // in scope 2 at $DIR/try_identity.rs:+5:21: +5:22 @@ -24,47 +24,47 @@ fn new(_1: Result<T, E>) -> Result<T, E> { } bb0: { - StorageLive(_2); // scope 0 at $DIR/try_identity.rs:+2:15: +7:10 - _3 = discriminant(_1); // scope 0 at $DIR/try_identity.rs:+3:19: +3:20 - switchInt(move _3) -> [0: bb3, 1: bb1, otherwise: bb2]; // scope 0 at $DIR/try_identity.rs:+3:13: +3:20 + StorageLive(_4); // scope 0 at $DIR/try_identity.rs:+2:15: +7:10 + _2 = discriminant(_1); // scope 0 at $DIR/try_identity.rs:+3:19: +3:20 + switchInt(move _2) -> [0: bb1, 1: bb2, otherwise: bb7]; // scope 0 at $DIR/try_identity.rs:+3:13: +3:20 } bb1: { - _5 = move ((_1 as Err).0: E); // scope 0 at $DIR/try_identity.rs:+5:21: +5:22 - _2 = ControlFlow::<E, T>::Break(move _5); // scope 2 at $DIR/try_identity.rs:+5:27: +5:48 - goto -> bb4; // scope 0 at $DIR/try_identity.rs:+5:47: +5:48 + _3 = move ((_1 as Ok).0: T); // scope 0 at $DIR/try_identity.rs:+4:20: +4:21 + _4 = ControlFlow::<E, T>::Continue(move _3); // scope 1 at $DIR/try_identity.rs:+4:26: +4:50 + goto -> bb3; // scope 0 at $DIR/try_identity.rs:+4:49: +4:50 } bb2: { - unreachable; // scope 0 at $DIR/try_identity.rs:+3:19: +3:20 + _5 = move ((_1 as Err).0: E); // scope 0 at $DIR/try_identity.rs:+5:21: +5:22 + _4 = ControlFlow::<E, T>::Break(move _5); // scope 2 at $DIR/try_identity.rs:+5:27: +5:48 + goto -> bb3; // scope 0 at $DIR/try_identity.rs:+5:47: +5:48 } bb3: { - _4 = move ((_1 as Ok).0: T); // scope 0 at $DIR/try_identity.rs:+4:20: +4:21 - _2 = ControlFlow::<E, T>::Continue(move _4); // scope 1 at $DIR/try_identity.rs:+4:26: +4:50 - goto -> bb4; // scope 0 at $DIR/try_identity.rs:+4:49: +4:50 + _6 = discriminant(_4); // scope 0 at $DIR/try_identity.rs:+2:15: +7:10 + switchInt(move _6) -> [0: bb4, 1: bb5, otherwise: bb7]; // scope 0 at $DIR/try_identity.rs:+2:9: +7:10 } bb4: { - _6 = discriminant(_2); // scope 0 at $DIR/try_identity.rs:+2:15: +7:10 - switchInt(move _6) -> [0: bb6, 1: bb5, otherwise: bb2]; // scope 0 at $DIR/try_identity.rs:+2:9: +7:10 + _7 = move ((_4 as Continue).0: T); // scope 0 at $DIR/try_identity.rs:+8:35: +8:36 + _0 = Result::<T, E>::Ok(move _7); // scope 0 at $DIR/try_identity.rs:+1:5: +11:6 + StorageDead(_4); // scope 0 at $DIR/try_identity.rs:+12:1: +12:2 + goto -> bb6; // scope 0 at $DIR/try_identity.rs:+12:1: +12:2 } bb5: { - _8 = move ((_2 as Break).0: E); // scope 0 at $DIR/try_identity.rs:+9:32: +9:33 + _8 = move ((_4 as Break).0: E); // scope 0 at $DIR/try_identity.rs:+9:32: +9:33 _0 = Result::<T, E>::Err(move _8); // scope 4 at $DIR/try_identity.rs:+9:45: +9:51 - StorageDead(_2); // scope 0 at $DIR/try_identity.rs:+12:1: +12:2 - goto -> bb7; // scope 0 at $DIR/try_identity.rs:+12:1: +12:2 + StorageDead(_4); // scope 0 at $DIR/try_identity.rs:+12:1: +12:2 + goto -> bb6; // scope 0 at $DIR/try_identity.rs:+12:1: +12:2 } bb6: { - _7 = move ((_2 as Continue).0: T); // scope 0 at $DIR/try_identity.rs:+8:35: +8:36 - _0 = Result::<T, E>::Ok(move _7); // scope 0 at $DIR/try_identity.rs:+1:5: +11:6 - StorageDead(_2); // scope 0 at $DIR/try_identity.rs:+12:1: +12:2 - goto -> bb7; // scope 0 at $DIR/try_identity.rs:+12:1: +12:2 + return; // scope 0 at $DIR/try_identity.rs:+12:2: +12:2 } bb7: { - return; // scope 0 at $DIR/try_identity.rs:+12:2: +12:2 + unreachable; // scope 0 at $DIR/try_identity.rs:+3:19: +3:20 } } diff --git a/tests/mir-opt/pre-codegen/try_identity.old.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/try_identity.old.PreCodegen.after.mir index e217d19947f..0487c6c3994 100644 --- a/tests/mir-opt/pre-codegen/try_identity.old.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/try_identity.old.PreCodegen.after.mir @@ -15,26 +15,26 @@ fn old(_1: Result<T, E>) -> Result<T, E> { bb0: { _2 = discriminant(_1); // scope 0 at $DIR/try_identity.rs:+2:15: +2:16 - switchInt(move _2) -> [0: bb3, 1: bb1, otherwise: bb2]; // scope 0 at $DIR/try_identity.rs:+2:9: +2:16 + switchInt(move _2) -> [0: bb1, 1: bb2, otherwise: bb4]; // scope 0 at $DIR/try_identity.rs:+2:9: +2:16 } bb1: { - _4 = move ((_1 as Err).0: E); // scope 0 at $DIR/try_identity.rs:+4:17: +4:18 - _0 = Result::<T, E>::Err(move _4); // scope 2 at $DIR/try_identity.rs:+4:30: +4:36 - goto -> bb4; // scope 0 at $DIR/try_identity.rs:+7:1: +7:2 + _3 = move ((_1 as Ok).0: T); // scope 0 at $DIR/try_identity.rs:+3:16: +3:17 + _0 = Result::<T, E>::Ok(move _3); // scope 0 at $DIR/try_identity.rs:+1:5: +6:6 + goto -> bb3; // scope 0 at $DIR/try_identity.rs:+7:1: +7:2 } bb2: { - unreachable; // scope 0 at $DIR/try_identity.rs:+2:15: +2:16 + _4 = move ((_1 as Err).0: E); // scope 0 at $DIR/try_identity.rs:+4:17: +4:18 + _0 = Result::<T, E>::Err(move _4); // scope 2 at $DIR/try_identity.rs:+4:30: +4:36 + goto -> bb3; // scope 0 at $DIR/try_identity.rs:+7:1: +7:2 } bb3: { - _3 = move ((_1 as Ok).0: T); // scope 0 at $DIR/try_identity.rs:+3:16: +3:17 - _0 = Result::<T, E>::Ok(move _3); // scope 0 at $DIR/try_identity.rs:+1:5: +6:6 - goto -> bb4; // scope 0 at $DIR/try_identity.rs:+7:1: +7:2 + return; // scope 0 at $DIR/try_identity.rs:+7:2: +7:2 } bb4: { - return; // scope 0 at $DIR/try_identity.rs:+7:2: +7:2 + unreachable; // scope 0 at $DIR/try_identity.rs:+2:15: +2:16 } } diff --git a/tests/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals-final.diff b/tests/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals-final.diff index f908e8dd0c1..0b9ca29cedd 100644 --- a/tests/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals-final.diff +++ b/tests/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals-final.diff @@ -8,8 +8,6 @@ let mut _3: std::option::Option<T>; // in scope 0 at $DIR/simplify_locals_fixedpoint.rs:+1:51: +1:68 let mut _4: isize; // in scope 0 at $DIR/simplify_locals_fixedpoint.rs:+1:22: +1:26 let mut _5: isize; // in scope 0 at $DIR/simplify_locals_fixedpoint.rs:+1:13: +1:20 -- let mut _7: bool; // in scope 0 at $DIR/simplify_locals_fixedpoint.rs:+2:12: +2:20 -- let mut _8: u8; // in scope 0 at $DIR/simplify_locals_fixedpoint.rs:+2:12: +2:13 scope 1 { debug a => _6; // in scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:18: +1:19 let _6: u8; // in scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:18: +1:19 @@ -34,10 +32,9 @@ } bb2: { + StorageLive(_6); // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:18: +1:19 _6 = (((_1.0: std::option::Option<u8>) as Some).0: u8); // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:18: +1:19 -- StorageLive(_7); // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+2:12: +2:20 -- _7 = Gt(_6, const 42_u8); // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+2:12: +2:20 -- StorageDead(_7); // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+4:9: +4:10 + StorageDead(_6); // scope 0 at $DIR/simplify_locals_fixedpoint.rs:+5:5: +5:6 goto -> bb3; // scope 0 at $DIR/simplify_locals_fixedpoint.rs:+1:5: +5:6 } diff --git a/tests/mir-opt/switch_to_self.rs b/tests/mir-opt/switch_to_self.rs new file mode 100644 index 00000000000..6678e4b3bd2 --- /dev/null +++ b/tests/mir-opt/switch_to_self.rs @@ -0,0 +1,21 @@ +// Test that MatchBranchSimplification doesn't ICE on a SwitchInt where +// one of the targets is the block that the SwitchInt terminates. +#![crate_type = "lib"] +#![feature(core_intrinsics, custom_mir)] +use std::intrinsics::mir::*; + +// EMIT_MIR switch_to_self.test.MatchBranchSimplification.diff +#[custom_mir(dialect = "runtime", phase = "post-cleanup")] +pub fn test(x: bool) { + mir!( + { + Goto(bb0) + } + bb0 = { + match x { false => bb0, _ => bb1 } + } + bb1 = { + match x { false => bb0, _ => bb1 } + } + ) +} diff --git a/tests/mir-opt/switch_to_self.test.MatchBranchSimplification.diff b/tests/mir-opt/switch_to_self.test.MatchBranchSimplification.diff new file mode 100644 index 00000000000..b0a4f9f0188 --- /dev/null +++ b/tests/mir-opt/switch_to_self.test.MatchBranchSimplification.diff @@ -0,0 +1,19 @@ +- // MIR for `test` before MatchBranchSimplification ++ // MIR for `test` after MatchBranchSimplification + + fn test(_1: bool) -> () { + let mut _0: (); // return place in scope 0 at $DIR/switch_to_self.rs:+0:22: +0:22 + + bb0: { + goto -> bb1; // scope 0 at $DIR/switch_to_self.rs:+3:13: +3:22 + } + + bb1: { + switchInt(_1) -> [0: bb1, otherwise: bb2]; // scope 0 at $DIR/switch_to_self.rs:+6:13: +6:47 + } + + bb2: { + switchInt(_1) -> [0: bb1, otherwise: bb2]; // scope 0 at $DIR/switch_to_self.rs:+9:13: +9:47 + } + } + diff --git a/tests/mir-opt/tls_access.main.PreCodegen.after.mir b/tests/mir-opt/tls_access.main.PreCodegen.after.mir index 09453b8ba9c..03618ae2814 100644 --- a/tests/mir-opt/tls_access.main.PreCodegen.after.mir +++ b/tests/mir-opt/tls_access.main.PreCodegen.after.mir @@ -2,27 +2,27 @@ fn main() -> () { let mut _0: (); // return place in scope 0 at $DIR/tls_access.rs:+0:11: +0:11 - let _2: *mut u8; // in scope 0 at $DIR/tls_access.rs:+2:18: +2:21 + let _1: *mut u8; // in scope 0 at $DIR/tls_access.rs:+2:18: +2:21 let mut _3: *mut u8; // in scope 0 at $DIR/tls_access.rs:+3:9: +3:12 scope 1 { - let _1: &u8; // in scope 1 at $DIR/tls_access.rs:+2:13: +2:14 + let _2: &u8; // in scope 1 at $DIR/tls_access.rs:+2:13: +2:14 scope 2 { - debug a => _1; // in scope 2 at $DIR/tls_access.rs:+2:13: +2:14 + debug a => _2; // in scope 2 at $DIR/tls_access.rs:+2:13: +2:14 } } bb0: { - StorageLive(_1); // scope 1 at $DIR/tls_access.rs:+2:13: +2:14 - StorageLive(_2); // scope 1 at $DIR/tls_access.rs:+2:18: +2:21 - _2 = &/*tls*/ mut FOO; // scope 1 at $DIR/tls_access.rs:+2:18: +2:21 - _1 = &(*_2); // scope 1 at $DIR/tls_access.rs:+2:17: +2:21 + StorageLive(_2); // scope 1 at $DIR/tls_access.rs:+2:13: +2:14 + StorageLive(_1); // scope 1 at $DIR/tls_access.rs:+2:18: +2:21 + _1 = &/*tls*/ mut FOO; // scope 1 at $DIR/tls_access.rs:+2:18: +2:21 + _2 = &(*_1); // scope 1 at $DIR/tls_access.rs:+2:17: +2:21 StorageLive(_3); // scope 2 at $DIR/tls_access.rs:+3:9: +3:12 _3 = &/*tls*/ mut FOO; // scope 2 at $DIR/tls_access.rs:+3:9: +3:12 (*_3) = const 42_u8; // scope 2 at $DIR/tls_access.rs:+3:9: +3:17 StorageDead(_3); // scope 2 at $DIR/tls_access.rs:+3:17: +3:18 _0 = const (); // scope 1 at $DIR/tls_access.rs:+1:5: +4:6 - StorageDead(_2); // scope 1 at $DIR/tls_access.rs:+4:5: +4:6 StorageDead(_1); // scope 1 at $DIR/tls_access.rs:+4:5: +4:6 + StorageDead(_2); // scope 1 at $DIR/tls_access.rs:+4:5: +4:6 return; // scope 0 at $DIR/tls_access.rs:+5:2: +5:2 } } diff --git a/tests/mir-opt/while_storage.while_loop.PreCodegen.after.mir b/tests/mir-opt/while_storage.while_loop.PreCodegen.after.mir index 811789a60c3..8922eda07ac 100644 --- a/tests/mir-opt/while_storage.while_loop.PreCodegen.after.mir +++ b/tests/mir-opt/while_storage.while_loop.PreCodegen.after.mir @@ -31,18 +31,18 @@ fn while_loop(_1: bool) -> () { } bb4: { - switchInt(move _3) -> [0: bb6, otherwise: bb5]; // scope 0 at $DIR/while_storage.rs:+2:12: +2:23 + switchInt(move _3) -> [0: bb5, otherwise: bb6]; // scope 0 at $DIR/while_storage.rs:+2:12: +2:23 } bb5: { StorageDead(_3); // scope 0 at $DIR/while_storage.rs:+4:9: +4:10 - goto -> bb7; // scope 0 at no-location + StorageDead(_2); // scope 0 at $DIR/while_storage.rs:+5:5: +5:6 + goto -> bb1; // scope 0 at $DIR/while_storage.rs:+1:5: +5:6 } bb6: { StorageDead(_3); // scope 0 at $DIR/while_storage.rs:+4:9: +4:10 - StorageDead(_2); // scope 0 at $DIR/while_storage.rs:+5:5: +5:6 - goto -> bb1; // scope 0 at $DIR/while_storage.rs:+1:5: +5:6 + goto -> bb7; // scope 0 at no-location } bb7: { diff --git a/tests/rustdoc-gui/search-result-display.goml b/tests/rustdoc-gui/search-result-display.goml index ee5598e4b21..bf096f62c48 100644 --- a/tests/rustdoc-gui/search-result-display.goml +++ b/tests/rustdoc-gui/search-result-display.goml @@ -57,22 +57,22 @@ define-function: ( call-function: ("check-filter", { "theme": "ayu", - "border": "rgb(92, 103, 115)", + "border": "#5c6773", "filter": "invert(0.41) sepia(0.12) saturate(4.87) hue-rotate(171deg) brightness(0.94) contrast(0.94)", - "hover_border": "rgb(224, 224, 224)", + "hover_border": "#e0e0e0", "hover_filter": "invert(0.98) sepia(0.12) saturate(0.81) hue-rotate(343deg) brightness(1.13) contrast(0.76)", }) call-function: ("check-filter", { "theme": "dark", - "border": "rgb(224, 224, 224)", + "border": "#e0e0e0", "filter": "invert(0.94) sepia(0) saturate(7.21) hue-rotate(255deg) brightness(0.9) contrast(0.9)", - "hover_border": "rgb(33, 150, 243)", + "hover_border": "#2196f3", "hover_filter": "invert(0.69) sepia(0.6) saturate(66.13) hue-rotate(184deg) brightness(1) contrast(0.91)", }) call-function: ("check-filter", { "theme": "light", - "border": "rgb(224, 224, 224)", + "border": "#e0e0e0", "filter": "invert(1) sepia(0) saturate(42.23) hue-rotate(289deg) brightness(1.14) contrast(0.76)", - "hover_border": "rgb(113, 113, 113)", + "hover_border": "#717171", "hover_filter": "invert(0.44) sepia(0.18) saturate(0.23) hue-rotate(317deg) brightness(0.96) contrast(0.93)", }) diff --git a/tests/rustdoc-gui/source-anchor-scroll.goml b/tests/rustdoc-gui/source-anchor-scroll.goml index 3d88d5619b1..67f1497e70c 100644 --- a/tests/rustdoc-gui/source-anchor-scroll.goml +++ b/tests/rustdoc-gui/source-anchor-scroll.goml @@ -8,13 +8,13 @@ set-window-size: (600, 800) assert-property: ("html", {"scrollTop": "0"}) click: '//a[text() = "barbar"]' -assert-property: ("html", {"scrollTop": "125"}) +assert-property: ("html", {"scrollTop": "149"}) click: '//a[text() = "bar"]' -assert-property: ("html", {"scrollTop": "156"}) +assert-property: ("html", {"scrollTop": "180"}) click: '//a[text() = "sub_fn"]' -assert-property: ("html", {"scrollTop": "53"}) +assert-property: ("html", {"scrollTop": "77"}) // We now check that clicking on lines doesn't change the scroll // Extra information: the "sub_fn" function header is on line 1. click: '//*[@id="6"]' -assert-property: ("html", {"scrollTop": "53"}) +assert-property: ("html", {"scrollTop": "77"}) diff --git a/tests/rustdoc-gui/src/extend_css/lib.rs b/tests/rustdoc-gui/src/extend_css/lib.rs index 3a3babf8984..2308c0932fd 100644 --- a/tests/rustdoc-gui/src/extend_css/lib.rs +++ b/tests/rustdoc-gui/src/extend_css/lib.rs @@ -1 +1,2 @@ +// compile-flags: --extend-css extra.css //! <div class="extend">text in red</div> diff --git a/tests/rustdoc-gui/src/link_to_definition/lib.rs b/tests/rustdoc-gui/src/link_to_definition/lib.rs index 419a9cceec5..6fed79aedb8 100644 --- a/tests/rustdoc-gui/src/link_to_definition/lib.rs +++ b/tests/rustdoc-gui/src/link_to_definition/lib.rs @@ -1,3 +1,4 @@ +// compile-flags: -Zunstable-options --generate-link-to-definition pub fn sub_fn() { barbar(); } diff --git a/tests/rustdoc-gui/src/scrape_examples/src/lib.rs b/tests/rustdoc-gui/src/scrape_examples/src/lib.rs index 88b03cf2603..6666587ad54 100644 --- a/tests/rustdoc-gui/src/scrape_examples/src/lib.rs +++ b/tests/rustdoc-gui/src/scrape_examples/src/lib.rs @@ -1,3 +1,4 @@ +// run-flags:-Zrustdoc-scrape-examples /// # Examples /// /// ``` diff --git a/tests/rustdoc-gui/target.goml b/tests/rustdoc-gui/target.goml index 0c514fc6864..c5e7f813dd1 100644 --- a/tests/rustdoc-gui/target.goml +++ b/tests/rustdoc-gui/target.goml @@ -25,11 +25,11 @@ call-function: ("check-style", { }) call-function: ("check-style", { "theme": "dark", - "background": "rgb(73, 74, 61)", - "border": "rgb(187, 116, 16)", + "background": "#494a3d", + "border": "#bb7410", }) call-function: ("check-style", { "theme": "light", - "background": "rgb(253, 255, 211)", - "border": "rgb(173, 124, 55)", + "background": "#fdffd3", + "border": "#ad7c37", }) diff --git a/tests/rustdoc-ui/intra-doc/issue-110495-suffix-with-space.stderr b/tests/rustdoc-ui/intra-doc/issue-110495-suffix-with-space.stderr index 8669b0c2086..6c834fd0a1b 100644 --- a/tests/rustdoc-ui/intra-doc/issue-110495-suffix-with-space.stderr +++ b/tests/rustdoc-ui/intra-doc/issue-110495-suffix-with-space.stderr @@ -36,7 +36,7 @@ LL | //! [`Clone ()`]. help: to link to the trait, prefix with `trait@` | LL - //! [`Clone ()`]. -LL + //! [`trait@Clone (`]. +LL + //! [`trait@Clone `]. | error: incompatible link kind for `Clone` @@ -47,8 +47,9 @@ LL | //! [`Clone !`]. | help: to link to the derive macro, prefix with `derive@` | -LL | //! [`derive@Clone !`]. - | +++++++ +LL - //! [`Clone !`]. +LL + //! [`derive@Clone `]. + | error: aborting due to 4 previous errors diff --git a/tests/rustdoc-ui/intra-doc/weird-syntax.rs b/tests/rustdoc-ui/intra-doc/weird-syntax.rs new file mode 100644 index 00000000000..ca18842fb21 --- /dev/null +++ b/tests/rustdoc-ui/intra-doc/weird-syntax.rs @@ -0,0 +1,140 @@ +// Many examples are from +// https://github.com/rust-lang/rust/issues/110111#issuecomment-1517800781 +#![deny(rustdoc::broken_intra_doc_links)] + +//! This test case is closely linked to [raphlinus/pulldown-cmark#441], getting offsets of +//! link components. In particular, pulldown-cmark doesn't provide the offsets of the contents +//! of a link. +//! +//! To work around this, rustdoc parses parts of a link definition itself. This is basically a +//! test suite for that link syntax parser. +//! +//! [raphlinus/pulldown-cmark#441]: https://github.com/raphlinus/pulldown-cmark/issues/441 + +use std::clone::Clone; + +// Basic version // + +/// [`struct@Clone`] //~ERROR link +pub struct LinkToCloneWithBackquotes; + +/// [```struct@Clone```] //~ERROR link +pub struct LinkToCloneWithMultipleBackquotes; + +/// [ ` struct@Clone ` ] //~ERROR link +pub struct LinkToCloneWithSpacesAndBackquotes; + +/// [ `Clone ()` ] //~ERROR link +pub struct LinkToCloneWithSpacesBackquotesAndParens; + +/// [`Clone ()` ] //~ERROR link +pub struct LinkToCloneWithSpacesEndBackquotesAndParens; + +/// [ `Clone ()`] //~ERROR link +pub struct LinkToCloneWithSpacesStartBackquotesAndParens; + +/// [```Clone ()```] //~ERROR link +pub struct LinkToCloneWithMultipleBackquotesAndParens; + +/// [```Clone \(\)```] // not URL-shaped enough +pub struct LinkToCloneWithMultipleBackquotesAndEscapedParens; + +/// [ ``` Clone () ``` ] //~ERROR link +pub struct LinkToCloneWithSpacesMultipleBackquotesAndParens; + +/// [ x \] ] // not URL-shaped enough +pub struct LinkWithEscapedCloseBrace; + +/// [ x \[ ] // not URL-shaped enough +pub struct LinkWithEscapedOpenBrace; + +/// [ x \( ] // not URL-shaped enough +pub struct LinkWithEscapedCloseParen; + +/// [ x \) ] // not URL-shaped enough +pub struct LinkWithEscapedOpenParen; + +/// [ Clone \(\) ] // not URL-shaped enough +pub struct LinkWithEscapedParens; + +// [][] version // + +/// [x][ struct@Clone] //~ERROR link +pub struct XLinkToCloneWithStartSpace; + +/// [x][struct@Clone ] //~ERROR link +pub struct XLinkToCloneWithEndSpace; + +/// [x][Clone\(\)] not URL-shaped enough +pub struct XLinkToCloneWithEscapedParens; + +/// [x][`Clone`] not URL-shaped enough +pub struct XLinkToCloneWithBackquotes; + +/// [x][Clone()] //~ERROR link +pub struct XLinkToCloneWithUnescapedParens; + +/// [x][Clone ()] //~ERROR link +pub struct XLinkToCloneWithUnescapedParensAndDoubleSpace; + +/// [x][Clone [] //~ERROR unresolved link to `x` +pub struct XLinkToCloneWithUnmatchedOpenParenAndDoubleSpace; + +/// [x][Clone \[] // not URL-shaped enough +pub struct XLinkToCloneWithUnmatchedEscapedOpenParenAndDoubleSpace; + +/// [x][Clone \]] // not URL-shaped enough +pub struct XLinkToCloneWithUnmatchedEscapedCloseParenAndDoubleSpace; + +// []() version // + +/// [w]( struct@Clone) //~ERROR link +pub struct WLinkToCloneWithStartSpace; + +/// [w](struct@Clone ) //~ERROR link +pub struct WLinkToCloneWithEndSpace; + +/// [w](Clone\(\)) //~ERROR link +pub struct WLinkToCloneWithEscapedParens; + +/// [w](`Clone`) not URL-shaped enough +pub struct WLinkToCloneWithBackquotes; + +/// [w](Clone()) //~ERROR link +pub struct WLinkToCloneWithUnescapedParens; + +/// [w](Clone ()) not URL-shaped enough +pub struct WLinkToCloneWithUnescapedParensAndDoubleSpace; + +/// [w](Clone () //~ERROR unresolved link to `w` +pub struct WLinkToCloneWithUnmatchedOpenParenAndDoubleSpace; + +/// [w](Clone \() //~ERROR unresolved link to `w` +pub struct WLinkToCloneWithUnmatchedEscapedOpenParenAndDoubleSpace; + +/// [w](Clone \)) //~ERROR unresolved link to `w` +pub struct WLinkToCloneWithUnmatchedEscapedCloseParenAndDoubleSpace; + +// References + +/// The [cln][] link here is going to be unresolved, because `Clone()` gets rejected //~ERROR link +/// in Markdown for not being URL-shaped enough. +/// +/// [cln]: Clone() //~ERROR link +pub struct LinkToCloneWithParensInReference; + +/// The [cln][] link here is going to be unresolved, because `struct@Clone` gets //~ERROR link +/// rejected in Markdown for not being URL-shaped enough. +/// +/// [cln]: struct@Clone //~ERROR link +pub struct LinkToCloneWithWrongPrefix; + +/// The [cln][] link here will produce a plain text suggestion //~ERROR link +/// +/// [cln]: Clone\(\) +pub struct LinkToCloneWithEscapedParensInReference; + +/// The [cln][] link here will produce a plain text suggestion //~ERROR link +/// +/// [cln]: struct\@Clone +pub struct LinkToCloneWithEscapedAtsInReference; diff --git a/tests/rustdoc-ui/intra-doc/weird-syntax.stderr b/tests/rustdoc-ui/intra-doc/weird-syntax.stderr new file mode 100644 index 00000000000..f50feb57fcc --- /dev/null +++ b/tests/rustdoc-ui/intra-doc/weird-syntax.stderr @@ -0,0 +1,272 @@ +error: incompatible link kind for `Clone` + --> $DIR/weird-syntax.rs:18:7 + | +LL | /// [`struct@Clone`] + | ^^^^^^^^^^^^ this link resolved to a trait, which is not a struct + | +note: the lint level is defined here + --> $DIR/weird-syntax.rs:3:9 + | +LL | #![deny(rustdoc::broken_intra_doc_links)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: to link to the trait, prefix with `trait@` + | +LL | /// [`trait@Clone`] + | ~~~~~~ + +error: incompatible link kind for `Clone` + --> $DIR/weird-syntax.rs:21:9 + | +LL | /// [```struct@Clone```] + | ^^^^^^^^^^^^ this link resolved to a trait, which is not a struct + | +help: to link to the trait, prefix with `trait@` + | +LL | /// [```trait@Clone```] + | ~~~~~~ + +error: incompatible link kind for `Clone` + --> $DIR/weird-syntax.rs:24:11 + | +LL | /// [ ` struct@Clone ` ] + | ^^^^^^^^^^^^ this link resolved to a trait, which is not a struct + | +help: to link to the trait, prefix with `trait@` + | +LL | /// [ ` trait@Clone ` ] + | ~~~~~~ + +error: unresolved link to `Clone` + --> $DIR/weird-syntax.rs:27:9 + | +LL | /// [ `Clone ()` ] + | ^^^^^^^^ this link resolves to the trait `Clone`, which is not in the value namespace + | +help: to link to the trait, prefix with `trait@` + | +LL - /// [ `Clone ()` ] +LL + /// [ `trait@Clone ` ] + | + +error: unresolved link to `Clone` + --> $DIR/weird-syntax.rs:30:7 + | +LL | /// [`Clone ()` ] + | ^^^^^^^^ this link resolves to the trait `Clone`, which is not in the value namespace + | +help: to link to the trait, prefix with `trait@` + | +LL - /// [`Clone ()` ] +LL + /// [`trait@Clone ` ] + | + +error: unresolved link to `Clone` + --> $DIR/weird-syntax.rs:33:9 + | +LL | /// [ `Clone ()`] + | ^^^^^^^^ this link resolves to the trait `Clone`, which is not in the value namespace + | +help: to link to the trait, prefix with `trait@` + | +LL - /// [ `Clone ()`] +LL + /// [ `trait@Clone `] + | + +error: unresolved link to `Clone` + --> $DIR/weird-syntax.rs:36:9 + | +LL | /// [```Clone ()```] + | ^^^^^^^^ this link resolves to the trait `Clone`, which is not in the value namespace + | +help: to link to the trait, prefix with `trait@` + | +LL - /// [```Clone ()```] +LL + /// [```trait@Clone ```] + | + +error: unresolved link to `Clone` + --> $DIR/weird-syntax.rs:42:13 + | +LL | /// [ ``` Clone () ``` ] + | ^^^^^^^^ this link resolves to the trait `Clone`, which is not in the value namespace + | +help: to link to the trait, prefix with `trait@` + | +LL - /// [ ``` Clone () ``` ] +LL + /// [ ``` trait@Clone ``` ] + | + +error: incompatible link kind for `Clone` + --> $DIR/weird-syntax.rs:62:10 + | +LL | /// [x][ struct@Clone] + | ^^^^^^^^^^^^ this link resolved to a trait, which is not a struct + | +help: to link to the trait, prefix with `trait@` + | +LL | /// [x][ trait@Clone] + | ~~~~~~ + +error: incompatible link kind for `Clone` + --> $DIR/weird-syntax.rs:65:9 + | +LL | /// [x][struct@Clone ] + | ^^^^^^^^^^^^ this link resolved to a trait, which is not a struct + | +help: to link to the trait, prefix with `trait@` + | +LL | /// [x][trait@Clone ] + | ~~~~~~ + +error: unresolved link to `Clone` + --> $DIR/weird-syntax.rs:74:9 + | +LL | /// [x][Clone()] + | ^^^^^^^ this link resolves to the trait `Clone`, which is not in the value namespace + | +help: to link to the trait, prefix with `trait@` + | +LL - /// [x][Clone()] +LL + /// [x][trait@Clone] + | + +error: unresolved link to `Clone` + --> $DIR/weird-syntax.rs:77:9 + | +LL | /// [x][Clone ()] + | ^^^^^^^^^ this link resolves to the trait `Clone`, which is not in the value namespace + | +help: to link to the trait, prefix with `trait@` + | +LL - /// [x][Clone ()] +LL + /// [x][trait@Clone ] + | + +error: unresolved link to `x` + --> $DIR/weird-syntax.rs:80:6 + | +LL | /// [x][Clone [] + | ^ no item named `x` in scope + | + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + +error: incompatible link kind for `Clone` + --> $DIR/weird-syntax.rs:91:10 + | +LL | /// [w]( struct@Clone) + | ^^^^^^^^^^^^ this link resolved to a trait, which is not a struct + | +help: to link to the trait, prefix with `trait@` + | +LL | /// [w]( trait@Clone) + | ~~~~~~ + +error: incompatible link kind for `Clone` + --> $DIR/weird-syntax.rs:94:9 + | +LL | /// [w](struct@Clone ) + | ^^^^^^^^^^^^ this link resolved to a trait, which is not a struct + | +help: to link to the trait, prefix with `trait@` + | +LL | /// [w](trait@Clone ) + | ~~~~~~ + +error: unresolved link to `Clone` + --> $DIR/weird-syntax.rs:97:9 + | +LL | /// [w](Clone\(\)) + | ^^^^^^^^^ this link resolves to the trait `Clone`, which is not in the value namespace + | +help: to link to the trait, prefix with `trait@` + | +LL - /// [w](Clone\(\)) +LL + /// [w](trait@Clone) + | + +error: unresolved link to `Clone` + --> $DIR/weird-syntax.rs:103:9 + | +LL | /// [w](Clone()) + | ^^^^^^^ this link resolves to the trait `Clone`, which is not in the value namespace + | +help: to link to the trait, prefix with `trait@` + | +LL - /// [w](Clone()) +LL + /// [w](trait@Clone) + | + +error: unresolved link to `w` + --> $DIR/weird-syntax.rs:109:6 + | +LL | /// [w](Clone () + | ^ no item named `w` in scope + | + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + +error: unresolved link to `w` + --> $DIR/weird-syntax.rs:112:6 + | +LL | /// [w](Clone \() + | ^ no item named `w` in scope + | + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + +error: unresolved link to `w` + --> $DIR/weird-syntax.rs:115:6 + | +LL | /// [w](Clone \)) + | ^ no item named `w` in scope + | + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + +error: unresolved link to `cln` + --> $DIR/weird-syntax.rs:120:10 + | +LL | /// The [cln][] link here is going to be unresolved, because `Clone()` gets rejected + | ^^^ no item named `cln` in scope + | + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + +error: unresolved link to `cln` + --> $DIR/weird-syntax.rs:123:6 + | +LL | /// [cln]: Clone() + | ^^^ no item named `cln` in scope + | + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + +error: unresolved link to `cln` + --> $DIR/weird-syntax.rs:126:10 + | +LL | /// The [cln][] link here is going to be unresolved, because `struct@Clone` gets + | ^^^ no item named `cln` in scope + | + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + +error: unresolved link to `cln` + --> $DIR/weird-syntax.rs:129:6 + | +LL | /// [cln]: struct@Clone + | ^^^ no item named `cln` in scope + | + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + +error: unresolved link to `Clone` + --> $DIR/weird-syntax.rs:132:9 + | +LL | /// The [cln][] link here will produce a plain text suggestion + | ^^^^^ this link resolves to the trait `Clone`, which is not in the value namespace + | + = help: to link to the trait, prefix with `trait@`: trait@Clone + +error: incompatible link kind for `Clone` + --> $DIR/weird-syntax.rs:137:9 + | +LL | /// The [cln][] link here will produce a plain text suggestion + | ^^^^^ this link resolved to a trait, which is not a struct + | + = help: to link to the trait, prefix with `trait@`: trait@Clone + +error: aborting due to 26 previous errors + diff --git a/tests/rustdoc/reexport-doc-hidden-inside-private.rs b/tests/rustdoc/reexport-doc-hidden-inside-private.rs new file mode 100644 index 00000000000..1e4216d3c0c --- /dev/null +++ b/tests/rustdoc/reexport-doc-hidden-inside-private.rs @@ -0,0 +1,16 @@ +// This test ensures that a re-export of `#[doc(hidden)]` item inside a private +// module will still be displayed (the re-export, not the item). + +#![crate_name = "foo"] + +mod private_module { + #[doc(hidden)] + pub struct Public; +} + +// @has 'foo/index.html' +// @has - '//*[@id="reexport.Foo"]/code' 'pub use crate::private_module::Public as Foo;' +pub use crate::private_module::Public as Foo; +// Glob re-exports with no visible items should not be displayed. +// @count - '//*[@class="item-table"]/li' 1 +pub use crate::private_module::*; diff --git a/tests/rustdoc/reexport-doc-hidden.rs b/tests/rustdoc/reexport-doc-hidden.rs index 3ea5fde72f7..d9ed954868e 100644 --- a/tests/rustdoc/reexport-doc-hidden.rs +++ b/tests/rustdoc/reexport-doc-hidden.rs @@ -21,6 +21,5 @@ macro_rules! foo { () => {}; } -// This is a bug: https://github.com/rust-lang/rust/issues/59368 -// @!has - '//*[@id="reexport.Macro"]/code' 'pub use crate::foo as Macro;' +// @has - '//*[@id="reexport.Macro"]/code' 'pub use crate::foo as Macro;' pub use crate::foo as Macro; diff --git a/tests/rustdoc/reexport-hidden-macro.rs b/tests/rustdoc/reexport-hidden-macro.rs index afcfa979616..47a21e39462 100644 --- a/tests/rustdoc/reexport-hidden-macro.rs +++ b/tests/rustdoc/reexport-hidden-macro.rs @@ -5,6 +5,7 @@ // @has 'foo/index.html' // @has - '//*[@id="main-content"]//a[@href="macro.Macro2.html"]' 'Macro2' +// @has - '//*[@id="reexport.Macro"]/code' 'pub use crate::foo as Macro;' // @has 'foo/macro.Macro2.html' // @has - '//*[@class="docblock"]' 'Displayed' @@ -15,7 +16,6 @@ macro_rules! foo { () => {}; } -/// not displayed pub use crate::foo as Macro; /// Displayed #[doc(inline)] diff --git a/tests/rustdoc/reexport-of-doc-hidden.rs b/tests/rustdoc/reexport-of-doc-hidden.rs new file mode 100644 index 00000000000..b733716c22a --- /dev/null +++ b/tests/rustdoc/reexport-of-doc-hidden.rs @@ -0,0 +1,42 @@ +// This test ensures that all re-exports of doc hidden elements are displayed. + +#![crate_name = "foo"] + +#[doc(hidden)] +pub struct Bar; + +#[macro_export] +#[doc(hidden)] +macro_rules! foo { + () => {}; +} + +// @has 'foo/index.html' +// @has - '//*[@id="reexport.Macro"]/code' 'pub use crate::foo as Macro;' +pub use crate::foo as Macro; +// @has - '//*[@id="reexport.Macro2"]/code' 'pub use crate::foo as Macro2;' +pub use crate::foo as Macro2; +// @has - '//*[@id="reexport.Boo"]/code' 'pub use crate::Bar as Boo;' +pub use crate::Bar as Boo; +// @has - '//*[@id="reexport.Boo2"]/code' 'pub use crate::Bar as Boo2;' +pub use crate::Bar as Boo2; + +pub fn fofo() {} + +// @has - '//*[@id="reexport.f1"]/code' 'pub use crate::fofo as f1;' +pub use crate::fofo as f1; +// @has - '//*[@id="reexport.f2"]/code' 'pub use crate::fofo as f2;' +pub use crate::fofo as f2; + +pub mod sub { + // @has 'foo/sub/index.html' + // @has - '//*[@id="reexport.Macro"]/code' 'pub use crate::foo as Macro;' + pub use crate::foo as Macro; + // @has - '//*[@id="reexport.Macro2"]/code' 'pub use crate::foo as Macro2;' + pub use crate::foo as Macro2; + + // @has - '//*[@id="reexport.f1"]/code' 'pub use crate::fofo as f1;' + pub use crate::fofo as f1; + // @has - '//*[@id="reexport.f2"]/code' 'pub use crate::fofo as f2;' + pub use crate::fofo as f2; +} diff --git a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-doc-comment-field.stderr b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-doc-comment-field.stderr index e4b8958b4fa..8c876213ae0 100644 --- a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-doc-comment-field.stderr +++ b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-doc-comment-field.stderr @@ -23,7 +23,7 @@ LL | arg: NotIntoDiagnosticArg, | = help: normalized in stderr note: required by a bound in `Diagnostic::set_arg` - --> $COMPILER_DIR/rustc_errors/src/diagnostic.rs:964:5 + --> $COMPILER_DIR/rustc_errors/src/diagnostic.rs:960:5 error: aborting due to 2 previous errors diff --git a/tests/ui/issues/issue-78115.rs b/tests/ui/async-await/issue-78115.rs index ac18470c621..ac18470c621 100644 --- a/tests/ui/issues/issue-78115.rs +++ b/tests/ui/async-await/issue-78115.rs diff --git a/tests/ui/backtrace.rs b/tests/ui/backtrace.rs index dd73dd9886a..66b378f62d6 100644 --- a/tests/ui/backtrace.rs +++ b/tests/ui/backtrace.rs @@ -104,13 +104,17 @@ fn runtest(me: &str) { "bad output3: {}", s); // Make sure a stack trace isn't printed too many times + // + // Currently it is printed 3 times ("once", "twice" and "panic in a + // function that cannot unwind") but in the future the last one may be + // removed. let p = template(me).arg("double-fail") .env("RUST_BACKTRACE", "1").spawn().unwrap(); let out = p.wait_with_output().unwrap(); assert!(!out.status.success()); let s = str::from_utf8(&out.stderr).unwrap(); let mut i = 0; - for _ in 0..2 { + for _ in 0..3 { i += s[i + 10..].find("stack backtrace").unwrap() + 10; } assert!(s[i + 10..].find("stack backtrace").is_none(), diff --git a/tests/ui/borrowck/borrowck-thread-local-static-borrow-outlives-fn.stderr b/tests/ui/borrowck/borrowck-thread-local-static-borrow-outlives-fn.stderr index 26453b42fa9..2f397f6b585 100644 --- a/tests/ui/borrowck/borrowck-thread-local-static-borrow-outlives-fn.stderr +++ b/tests/ui/borrowck/borrowck-thread-local-static-borrow-outlives-fn.stderr @@ -4,7 +4,7 @@ error[E0712]: thread-local variable borrowed past end of function LL | assert_static(&FOO); | ^^^^ thread-local variables cannot be borrowed beyond the end of the function LL | } - | - end of enclosing function is here + | - end of enclosing function is here error: aborting due to previous error diff --git a/tests/ui/borrowck/borrowck-vec-pattern-nesting.rs b/tests/ui/borrowck/borrowck-vec-pattern-nesting.rs index 127a3f5b2dc..1bda7a49713 100644 --- a/tests/ui/borrowck/borrowck-vec-pattern-nesting.rs +++ b/tests/ui/borrowck/borrowck-vec-pattern-nesting.rs @@ -8,7 +8,6 @@ fn a() { //~^ NOTE `vec[_]` is borrowed here vec[0] = Box::new(4); //~ ERROR cannot assign //~^ NOTE `vec[_]` is assigned to here - //~| NOTE in this expansion of desugaring of drop and replace _a.use_ref(); //~^ NOTE borrow later used here } @@ -23,7 +22,6 @@ fn b() { //~^ `vec[_]` is borrowed here vec[0] = Box::new(4); //~ ERROR cannot assign //~^ NOTE `vec[_]` is assigned to here - //~| NOTE in this expansion of desugaring of drop and replace _b.use_ref(); //~^ NOTE borrow later used here } diff --git a/tests/ui/borrowck/borrowck-vec-pattern-nesting.stderr b/tests/ui/borrowck/borrowck-vec-pattern-nesting.stderr index 5e1251b0590..70b9e4f4433 100644 --- a/tests/ui/borrowck/borrowck-vec-pattern-nesting.stderr +++ b/tests/ui/borrowck/borrowck-vec-pattern-nesting.stderr @@ -6,24 +6,24 @@ LL | [box ref _a, _, _] => { LL | LL | vec[0] = Box::new(4); | ^^^^^^ `vec[_]` is assigned to here but it was already borrowed -... +LL | LL | _a.use_ref(); | ------------ borrow later used here error[E0506]: cannot assign to `vec[_]` because it is borrowed - --> $DIR/borrowck-vec-pattern-nesting.rs:24:13 + --> $DIR/borrowck-vec-pattern-nesting.rs:23:13 | LL | &mut [ref _b @ ..] => { | ------ `vec[_]` is borrowed here LL | LL | vec[0] = Box::new(4); | ^^^^^^ `vec[_]` is assigned to here but it was already borrowed -... +LL | LL | _b.use_ref(); | ------------ borrow later used here error[E0508]: cannot move out of type `[Box<isize>]`, a non-copy slice - --> $DIR/borrowck-vec-pattern-nesting.rs:36:11 + --> $DIR/borrowck-vec-pattern-nesting.rs:34:11 | LL | match vec { | ^^^ cannot move out of here @@ -41,7 +41,7 @@ LL + [_a, | error[E0508]: cannot move out of type `[Box<isize>]`, a non-copy slice - --> $DIR/borrowck-vec-pattern-nesting.rs:48:13 + --> $DIR/borrowck-vec-pattern-nesting.rs:46:13 | LL | let a = vec[0]; | ^^^^^^ @@ -55,7 +55,7 @@ LL | let a = &vec[0]; | + error[E0508]: cannot move out of type `[Box<isize>]`, a non-copy slice - --> $DIR/borrowck-vec-pattern-nesting.rs:57:11 + --> $DIR/borrowck-vec-pattern-nesting.rs:55:11 | LL | match vec { | ^^^ cannot move out of here @@ -73,7 +73,7 @@ LL + [ | error[E0508]: cannot move out of type `[Box<isize>]`, a non-copy slice - --> $DIR/borrowck-vec-pattern-nesting.rs:67:13 + --> $DIR/borrowck-vec-pattern-nesting.rs:65:13 | LL | let a = vec[0]; | ^^^^^^ @@ -87,7 +87,7 @@ LL | let a = &vec[0]; | + error[E0508]: cannot move out of type `[Box<isize>]`, a non-copy slice - --> $DIR/borrowck-vec-pattern-nesting.rs:76:11 + --> $DIR/borrowck-vec-pattern-nesting.rs:74:11 | LL | match vec { | ^^^ cannot move out of here @@ -106,7 +106,7 @@ LL + [_a, _b, _c] => {} | error[E0508]: cannot move out of type `[Box<isize>]`, a non-copy slice - --> $DIR/borrowck-vec-pattern-nesting.rs:87:13 + --> $DIR/borrowck-vec-pattern-nesting.rs:85:13 | LL | let a = vec[0]; | ^^^^^^ diff --git a/tests/ui/borrowck/issue-45199.rs b/tests/ui/borrowck/issue-45199.rs index 6a6b25541f3..ded46e56e34 100644 --- a/tests/ui/borrowck/issue-45199.rs +++ b/tests/ui/borrowck/issue-45199.rs @@ -5,7 +5,6 @@ fn test_drop_replace() { b = Box::new(1); //~ NOTE first assignment b = Box::new(2); //~ ERROR cannot assign twice to immutable variable `b` //~| NOTE cannot assign twice to immutable - //~| NOTE in this expansion of desugaring of drop and replace } fn test_call() { @@ -14,14 +13,12 @@ fn test_call() { //~| SUGGESTION mut b b = Box::new(2); //~ ERROR cannot assign twice to immutable variable `b` //~| NOTE cannot assign twice to immutable - //~| NOTE in this expansion of desugaring of drop and replace } fn test_args(b: Box<i32>) { //~ HELP consider making this binding mutable //~| SUGGESTION mut b b = Box::new(2); //~ ERROR cannot assign to immutable argument `b` //~| NOTE cannot assign to immutable argument - //~| NOTE in this expansion of desugaring of drop and replace } fn main() {} diff --git a/tests/ui/borrowck/issue-45199.stderr b/tests/ui/borrowck/issue-45199.stderr index 163f2370ba0..47aa3090827 100644 --- a/tests/ui/borrowck/issue-45199.stderr +++ b/tests/ui/borrowck/issue-45199.stderr @@ -10,7 +10,7 @@ LL | b = Box::new(2); | ^ cannot assign twice to immutable variable error[E0384]: cannot assign twice to immutable variable `b` - --> $DIR/issue-45199.rs:15:5 + --> $DIR/issue-45199.rs:14:5 | LL | let b = Box::new(1); | - @@ -22,7 +22,7 @@ LL | b = Box::new(2); | ^ cannot assign twice to immutable variable error[E0384]: cannot assign to immutable argument `b` - --> $DIR/issue-45199.rs:22:5 + --> $DIR/issue-45199.rs:20:5 | LL | fn test_args(b: Box<i32>) { | - help: consider making this binding mutable: `mut b` diff --git a/tests/ui/closures/2229_closure_analysis/unique-borrows-are-invariant-1.rs b/tests/ui/closures/2229_closure_analysis/unique-borrows-are-invariant-1.rs new file mode 100644 index 00000000000..f21ef43fb7c --- /dev/null +++ b/tests/ui/closures/2229_closure_analysis/unique-borrows-are-invariant-1.rs @@ -0,0 +1,18 @@ +// edition:2021 + +// regression test for #112056 + +fn extend_lifetime<'a, 'b>(x: &mut (&'a str,), y: &'b str) { + let mut closure = |input| x.0 = input; + //~^ ERROR: lifetime may not live long enough + closure(y); +} + +fn main() { + let mut tuple = ("static",); + { + let x = String::from("temporary"); + extend_lifetime(&mut tuple, &x); + } + println!("{}", tuple.0); +} diff --git a/tests/ui/closures/2229_closure_analysis/unique-borrows-are-invariant-1.stderr b/tests/ui/closures/2229_closure_analysis/unique-borrows-are-invariant-1.stderr new file mode 100644 index 00000000000..730823281ab --- /dev/null +++ b/tests/ui/closures/2229_closure_analysis/unique-borrows-are-invariant-1.stderr @@ -0,0 +1,14 @@ +error: lifetime may not live long enough + --> $DIR/unique-borrows-are-invariant-1.rs:6:31 + | +LL | fn extend_lifetime<'a, 'b>(x: &mut (&'a str,), y: &'b str) { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | let mut closure = |input| x.0 = input; + | ^^^^^^^^^^^ assignment requires that `'b` must outlive `'a` + | + = help: consider adding the following bound: `'b: 'a` + +error: aborting due to previous error + diff --git a/tests/ui/closures/2229_closure_analysis/unique-borrows-are-invariant-2.rs b/tests/ui/closures/2229_closure_analysis/unique-borrows-are-invariant-2.rs new file mode 100644 index 00000000000..dd9d986c208 --- /dev/null +++ b/tests/ui/closures/2229_closure_analysis/unique-borrows-are-invariant-2.rs @@ -0,0 +1,31 @@ +// edition:2021 + +// regression test for #112056 + +struct Spooky<'b> { + owned: Option<&'static u32>, + borrowed: &'b &'static u32, +} + +impl<'b> Spooky<'b> { + fn create_self_reference<'a>(&'a mut self) { + let mut closure = || { + if let Some(owned) = &self.owned { + let borrow: &'a &'static u32 = owned; + self.borrowed = borrow; + //~^ ERROR: lifetime may not live long enough + } + }; + closure(); + } +} + +fn main() { + let mut spooky: Spooky<'static> = Spooky { + owned: Some(&1), + borrowed: &&1, + }; + spooky.create_self_reference(); + spooky.owned = None; + println!("{}", **spooky.borrowed); +} diff --git a/tests/ui/closures/2229_closure_analysis/unique-borrows-are-invariant-2.stderr b/tests/ui/closures/2229_closure_analysis/unique-borrows-are-invariant-2.stderr new file mode 100644 index 00000000000..66ba0fe3547 --- /dev/null +++ b/tests/ui/closures/2229_closure_analysis/unique-borrows-are-invariant-2.stderr @@ -0,0 +1,15 @@ +error: lifetime may not live long enough + --> $DIR/unique-borrows-are-invariant-2.rs:15:17 + | +LL | impl<'b> Spooky<'b> { + | -- lifetime `'b` defined here +LL | fn create_self_reference<'a>(&'a mut self) { + | -- lifetime `'a` defined here +... +LL | self.borrowed = borrow; + | ^^^^^^^^^^^^^^^^^^^^^^ assignment requires that `'a` must outlive `'b` + | + = help: consider adding the following bound: `'a: 'b` + +error: aborting due to previous error + diff --git a/tests/ui/issues/issue-3794.rs b/tests/ui/coercion/issue-3794.rs index b1f028fbccb..b1f028fbccb 100644 --- a/tests/ui/issues/issue-3794.rs +++ b/tests/ui/coercion/issue-3794.rs diff --git a/tests/ui/coherence/coherence-inherited-subtyping.re.stderr b/tests/ui/coherence/coherence-inherited-subtyping.re.stderr deleted file mode 100644 index 4701bc0b139..00000000000 --- a/tests/ui/coherence/coherence-inherited-subtyping.re.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0592]: duplicate definitions with name `method1` - --> $DIR/coherence-inherited-subtyping.rs:14:5 - | -LL | fn method1(&self) {} - | ^^^^^^^^^^^^^^^^^ duplicate definitions for `method1` -... -LL | fn method1(&self) {} - | ----------------- other definition for `method1` - | - = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0592`. diff --git a/tests/ui/coherence/coherence-inherited-subtyping.rs b/tests/ui/coherence/coherence-inherited-subtyping.rs index 8587eb77950..f35cd2103da 100644 --- a/tests/ui/coherence/coherence-inherited-subtyping.rs +++ b/tests/ui/coherence/coherence-inherited-subtyping.rs @@ -4,8 +4,6 @@ // Note: This scenario is currently accepted, but as part of the // universe transition (#56105) may eventually become an error. -// revisions: old re - struct Foo<T> { t: T, } diff --git a/tests/ui/coherence/coherence-inherited-subtyping.old.stderr b/tests/ui/coherence/coherence-inherited-subtyping.stderr index 4701bc0b139..f60b2aa2735 100644 --- a/tests/ui/coherence/coherence-inherited-subtyping.old.stderr +++ b/tests/ui/coherence/coherence-inherited-subtyping.stderr @@ -1,5 +1,5 @@ error[E0592]: duplicate definitions with name `method1` - --> $DIR/coherence-inherited-subtyping.rs:14:5 + --> $DIR/coherence-inherited-subtyping.rs:12:5 | LL | fn method1(&self) {} | ^^^^^^^^^^^^^^^^^ duplicate definitions for `method1` diff --git a/tests/ui/coinduction/canonicalization-rerun.rs b/tests/ui/coinduction/canonicalization-rerun.rs index b10ba3a810f..c68895fc4e6 100644 --- a/tests/ui/coinduction/canonicalization-rerun.rs +++ b/tests/ui/coinduction/canonicalization-rerun.rs @@ -1,6 +1,6 @@ // check-pass -// revisions: old new -//[new] compile-flags: -Ztrait-solver=next +// revisions: old next +//[next] compile-flags: -Ztrait-solver=next // If we use canonical goals during trait solving we have to reevaluate // the root goal of a cycle until we hit a fixpoint. diff --git a/tests/ui/const-generics/generic_const_exprs/typeid-equality-by-subtyping.rs b/tests/ui/const-generics/generic_const_exprs/typeid-equality-by-subtyping.rs index 85345d65c4a..b22cab7c7ff 100644 --- a/tests/ui/const-generics/generic_const_exprs/typeid-equality-by-subtyping.rs +++ b/tests/ui/const-generics/generic_const_exprs/typeid-equality-by-subtyping.rs @@ -1,7 +1,7 @@ -// check-pass +// known-bug: #110395 // known-bug: #97156 -#![feature(const_type_id, generic_const_exprs)] +#![feature(const_type_id, const_trait_impl, generic_const_exprs)] #![allow(incomplete_features)] use std::any::TypeId; @@ -26,7 +26,10 @@ impl<T: 'static> AssocCt for T { trait WithAssoc<U> { type Assoc; } -impl<T: 'static> WithAssoc<()> for T where [(); <T as AssocCt>::ASSOC]: { +impl<T: 'static> WithAssoc<()> for T +where + [(); <T as AssocCt>::ASSOC]:, +{ type Assoc = [u8; <T as AssocCt>::ASSOC]; } @@ -38,7 +41,6 @@ where x } - fn unsound<T>(x: <One as WithAssoc<T>>::Assoc) -> <Two as WithAssoc<T>>::Assoc where One: WithAssoc<T>, diff --git a/tests/ui/const-generics/generic_const_exprs/typeid-equality-by-subtyping.stderr b/tests/ui/const-generics/generic_const_exprs/typeid-equality-by-subtyping.stderr new file mode 100644 index 00000000000..8cbd1265448 --- /dev/null +++ b/tests/ui/const-generics/generic_const_exprs/typeid-equality-by-subtyping.stderr @@ -0,0 +1,11 @@ +error: to use a constant of type `TypeId` in a pattern, `TypeId` must be annotated with `#[derive(PartialEq, Eq)]` + --> $DIR/typeid-equality-by-subtyping.rs:18:9 + | +LL | WHAT_A_TYPE => 0, + | ^^^^^^^^^^^ + | + = note: the traits must be derived, manual `impl`s are not sufficient + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details + +error: aborting due to previous error + diff --git a/tests/ui/const-generics/transmute-fail.stderr b/tests/ui/const-generics/transmute-fail.stderr index 41b098135e8..3d1197afd0f 100644 --- a/tests/ui/const-generics/transmute-fail.stderr +++ b/tests/ui/const-generics/transmute-fail.stderr @@ -4,8 +4,8 @@ error[E0512]: cannot transmute between types of different sizes, or dependently- LL | std::mem::transmute(v) | ^^^^^^^^^^^^^^^^^^^ | - = note: source type: `[[u32; H+1]; W]` (generic size [const expr]) - = note: target type: `[[u32; W+1]; H]` (generic size [const expr]) + = note: source type: `[[u32; H+1]; W]` (generic size {const expr}) + = note: target type: `[[u32; W+1]; H]` (generic size {const expr}) error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> $DIR/transmute-fail.rs:16:5 @@ -34,8 +34,8 @@ error[E0512]: cannot transmute between types of different sizes, or dependently- LL | std::mem::transmute(v) | ^^^^^^^^^^^^^^^^^^^ | - = note: source type: `[[u32; H]; W]` (generic size [const expr]) - = note: target type: `[u32; W * H * H]` (generic size [const expr]) + = note: source type: `[[u32; H]; W]` (generic size {const expr}) + = note: target type: `[u32; W * H * H]` (generic size {const expr}) error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> $DIR/transmute-fail.rs:30:5 diff --git a/tests/ui/consts/const_cmp_type_id.stderr b/tests/ui/consts/const_cmp_type_id.stderr index 319d2b924a8..dc2c702d885 100644 --- a/tests/ui/consts/const_cmp_type_id.stderr +++ b/tests/ui/consts/const_cmp_type_id.stderr @@ -20,7 +20,6 @@ LL | assert!(TypeId::of::<u8>() == TypeId::of::<u8>()); note: impl defined here, but it is not `const` --> $SRC_DIR/core/src/any.rs:LL:COL = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants - = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: can't compare `TypeId` with `TypeId` in const contexts --> $DIR/const_cmp_type_id.rs:9:13 @@ -44,7 +43,6 @@ LL | assert!(TypeId::of::<()>() != TypeId::of::<u8>()); note: impl defined here, but it is not `const` --> $SRC_DIR/core/src/any.rs:LL:COL = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants - = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: can't compare `TypeId` with `TypeId` in const contexts --> $DIR/const_cmp_type_id.rs:10:22 diff --git a/tests/ui/issues/issue-16538.mir.stderr b/tests/ui/consts/issue-16538.mir.stderr index e320df4b7ad..e320df4b7ad 100644 --- a/tests/ui/issues/issue-16538.mir.stderr +++ b/tests/ui/consts/issue-16538.mir.stderr diff --git a/tests/ui/issues/issue-16538.rs b/tests/ui/consts/issue-16538.rs index 270fa301414..270fa301414 100644 --- a/tests/ui/issues/issue-16538.rs +++ b/tests/ui/consts/issue-16538.rs diff --git a/tests/ui/issues/issue-16538.thir.stderr b/tests/ui/consts/issue-16538.thir.stderr index 4a862869274..4a862869274 100644 --- a/tests/ui/issues/issue-16538.thir.stderr +++ b/tests/ui/consts/issue-16538.thir.stderr diff --git a/tests/ui/issues/issue-28822.rs b/tests/ui/consts/issue-28822.rs index 10e5d1dd0ac..10e5d1dd0ac 100644 --- a/tests/ui/issues/issue-28822.rs +++ b/tests/ui/consts/issue-28822.rs diff --git a/tests/ui/issues/issue-29798.rs b/tests/ui/consts/issue-29798.rs index 5eff5d1915b..5eff5d1915b 100644 --- a/tests/ui/issues/issue-29798.rs +++ b/tests/ui/consts/issue-29798.rs diff --git a/tests/ui/consts/issue-73976-monomorphic.stderr b/tests/ui/consts/issue-73976-monomorphic.stderr index 95ab78b1b23..09661d3f344 100644 --- a/tests/ui/consts/issue-73976-monomorphic.stderr +++ b/tests/ui/consts/issue-73976-monomorphic.stderr @@ -20,7 +20,6 @@ LL | GetTypeId::<T>::VALUE == GetTypeId::<usize>::VALUE note: impl defined here, but it is not `const` --> $SRC_DIR/core/src/any.rs:LL:COL = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants - = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 2 previous errors diff --git a/tests/ui/deriving/deriving-all-codegen.stdout b/tests/ui/deriving/deriving-all-codegen.stdout index 5bca83e87f8..d6a2c80cc06 100644 --- a/tests/ui/deriving/deriving-all-codegen.stdout +++ b/tests/ui/deriving/deriving-all-codegen.stdout @@ -44,6 +44,7 @@ impl ::core::default::Default for Empty { } #[automatically_derived] impl ::core::hash::Hash for Empty { + #[inline] fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {} } #[automatically_derived] @@ -113,6 +114,7 @@ impl ::core::default::Default for Point { } #[automatically_derived] impl ::core::hash::Hash for Point { + #[inline] fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () { ::core::hash::Hash::hash(&self.x, state); ::core::hash::Hash::hash(&self.y, state) @@ -198,6 +200,7 @@ impl ::core::default::Default for PackedPoint { } #[automatically_derived] impl ::core::hash::Hash for PackedPoint { + #[inline] fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () { ::core::hash::Hash::hash(&{ self.x }, state); ::core::hash::Hash::hash(&{ self.y }, state) @@ -301,6 +304,7 @@ impl ::core::default::Default for Big { } #[automatically_derived] impl ::core::hash::Hash for Big { + #[inline] fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () { ::core::hash::Hash::hash(&self.b1, state); ::core::hash::Hash::hash(&self.b2, state); @@ -478,6 +482,7 @@ impl ::core::fmt::Debug for Unsized { } #[automatically_derived] impl ::core::hash::Hash for Unsized { + #[inline] fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () { ::core::hash::Hash::hash(&self.0, state) } @@ -529,6 +534,7 @@ impl ::core::fmt::Debug for PackedUnsizedU8 { } #[automatically_derived] impl ::core::hash::Hash for PackedUnsizedU8 { + #[inline] fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () { ::core::hash::Hash::hash(&self.0, state) } @@ -584,6 +590,7 @@ impl<T: ::core::default::Default + Trait, U: ::core::default::Default> #[automatically_derived] impl<T: ::core::hash::Hash + Trait, U: ::core::hash::Hash> ::core::hash::Hash for Generic<T, U> where T::A: ::core::hash::Hash { + #[inline] fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () { ::core::hash::Hash::hash(&self.t, state); ::core::hash::Hash::hash(&self.ta, state); @@ -701,6 +708,7 @@ impl<T: ::core::hash::Hash + ::core::marker::Copy + Trait, U: ::core::hash::Hash + ::core::marker::Copy> ::core::hash::Hash for PackedGeneric<T, U> where T::A: ::core::hash::Hash + ::core::marker::Copy { + #[inline] fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () { ::core::hash::Hash::hash(&{ self.0 }, state); ::core::hash::Hash::hash(&{ self.1 }, state); @@ -795,6 +803,7 @@ impl ::core::fmt::Debug for Enum0 { } #[automatically_derived] impl ::core::hash::Hash for Enum0 { + #[inline] fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () { unsafe { ::core::intrinsics::unreachable() } } @@ -861,6 +870,7 @@ impl ::core::fmt::Debug for Enum1 { } #[automatically_derived] impl ::core::hash::Hash for Enum1 { + #[inline] fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () { match self { Enum1::Single { x: __self_0 } => @@ -937,6 +947,7 @@ impl ::core::default::Default for Fieldless1 { } #[automatically_derived] impl ::core::hash::Hash for Fieldless1 { + #[inline] fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {} } #[automatically_derived] @@ -1004,6 +1015,7 @@ impl ::core::default::Default for Fieldless { } #[automatically_derived] impl ::core::hash::Hash for Fieldless { + #[inline] fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () { let __self_tag = ::core::intrinsics::discriminant_value(self); ::core::hash::Hash::hash(&__self_tag, state) @@ -1095,6 +1107,7 @@ impl ::core::default::Default for Mixed { } #[automatically_derived] impl ::core::hash::Hash for Mixed { + #[inline] fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () { let __self_tag = ::core::intrinsics::discriminant_value(self); ::core::hash::Hash::hash(&__self_tag, state); @@ -1224,6 +1237,7 @@ impl ::core::fmt::Debug for Fielded { } #[automatically_derived] impl ::core::hash::Hash for Fielded { + #[inline] fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () { let __self_tag = ::core::intrinsics::discriminant_value(self); ::core::hash::Hash::hash(&__self_tag, state); @@ -1345,6 +1359,7 @@ impl<T: ::core::fmt::Debug, U: ::core::fmt::Debug> ::core::fmt::Debug for #[automatically_derived] impl<T: ::core::hash::Hash, U: ::core::hash::Hash> ::core::hash::Hash for EnumGeneric<T, U> { + #[inline] fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () { let __self_tag = ::core::intrinsics::discriminant_value(self); ::core::hash::Hash::hash(&__self_tag, state); diff --git a/tests/ui/editions/edition-raw-pointer-method-2018.rs b/tests/ui/editions/edition-raw-pointer-method-2018.rs index af0b2d6bd4a..0bae65a9ae5 100644 --- a/tests/ui/editions/edition-raw-pointer-method-2018.rs +++ b/tests/ui/editions/edition-raw-pointer-method-2018.rs @@ -7,5 +7,5 @@ fn main() { let x = 0; let y = &x as *const _; let _ = y.is_null(); - //~^ error: the type of this value must be known to call a method on a raw pointer on it [E0699] + //~^ error: cannot call a method on a raw pointer with an unknown pointee type [E0699] } diff --git a/tests/ui/editions/edition-raw-pointer-method-2018.stderr b/tests/ui/editions/edition-raw-pointer-method-2018.stderr index 23452495b4b..b9afa0133ca 100644 --- a/tests/ui/editions/edition-raw-pointer-method-2018.stderr +++ b/tests/ui/editions/edition-raw-pointer-method-2018.stderr @@ -1,4 +1,4 @@ -error[E0699]: the type of this value must be known to call a method on a raw pointer on it +error[E0699]: cannot call a method on a raw pointer with an unknown pointee type --> $DIR/edition-raw-pointer-method-2018.rs:9:15 | LL | let _ = y.is_null(); diff --git a/tests/ui/issues/issue-50689.rs b/tests/ui/enum-discriminant/issue-50689.rs index b49f2950020..b49f2950020 100644 --- a/tests/ui/issues/issue-50689.rs +++ b/tests/ui/enum-discriminant/issue-50689.rs diff --git a/tests/ui/issues/issue-1251.rs b/tests/ui/extern/issue-1251.rs index c2c047c7961..c2c047c7961 100644 --- a/tests/ui/issues/issue-1251.rs +++ b/tests/ui/extern/issue-1251.rs diff --git a/tests/ui/issues/issue-1257.rs b/tests/ui/for-loop-while/issue-1257.rs index de5a6d35925..de5a6d35925 100644 --- a/tests/ui/issues/issue-1257.rs +++ b/tests/ui/for-loop-while/issue-1257.rs diff --git a/tests/ui/higher-rank-trait-bounds/issue-95230.rs b/tests/ui/higher-rank-trait-bounds/issue-95230.rs deleted file mode 100644 index 769b6a92537..00000000000 --- a/tests/ui/higher-rank-trait-bounds/issue-95230.rs +++ /dev/null @@ -1,11 +0,0 @@ -// revisions: old new -//[new] compile-flags: -Ztrait-solver=next -//[old] check-pass -//[new] known-bug: #109764 - - -pub struct Bar -where - for<'a> &'a mut Self:; - -fn main() {} diff --git a/tests/ui/higher-lifetime-bounds.rs b/tests/ui/higher-ranked/higher-lifetime-bounds.rs index f3393347d90..f3393347d90 100644 --- a/tests/ui/higher-lifetime-bounds.rs +++ b/tests/ui/higher-ranked/higher-lifetime-bounds.rs diff --git a/tests/ui/higher-lifetime-bounds.stderr b/tests/ui/higher-ranked/higher-lifetime-bounds.stderr index bc6d2288cdf..bc6d2288cdf 100644 --- a/tests/ui/higher-lifetime-bounds.stderr +++ b/tests/ui/higher-ranked/higher-lifetime-bounds.stderr diff --git a/tests/ui/higher-ranked/leak-check-in-selection.rs b/tests/ui/higher-ranked/leak-check-in-selection.rs new file mode 100644 index 00000000000..e8d6cff856c --- /dev/null +++ b/tests/ui/higher-ranked/leak-check-in-selection.rs @@ -0,0 +1,24 @@ +// run-pass +// revisions: old next +//[next] compile-flags: -Ztrait-solver=next +#![allow(coherence_leak_check)] + +trait Trait: Sized { + fn is_higher_ranked(self) -> bool; +} + +impl Trait for for<'a> fn(&'a ()) { + fn is_higher_ranked(self) -> bool { + true + } +} +impl<'a> Trait for fn(&'a ()) { + fn is_higher_ranked(self) -> bool { + false + } +} + +fn main() { + let x: for<'a> fn(&'a ()) = |&()| (); + assert!(x.is_higher_ranked()); +} diff --git a/tests/ui/hr-subtype/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.stderr b/tests/ui/higher-ranked/subtype/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.stderr index b7264c7e933..b7264c7e933 100644 --- a/tests/ui/hr-subtype/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.stderr +++ b/tests/ui/higher-ranked/subtype/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.stderr diff --git a/tests/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.stderr b/tests/ui/higher-ranked/subtype/hr-subtype.bound_a_vs_free_x.stderr index 2355979b0f9..2355979b0f9 100644 --- a/tests/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.stderr +++ b/tests/ui/higher-ranked/subtype/hr-subtype.bound_a_vs_free_x.stderr diff --git a/tests/ui/hr-subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.stderr b/tests/ui/higher-ranked/subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.stderr index a73c03feb87..a73c03feb87 100644 --- a/tests/ui/hr-subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.stderr +++ b/tests/ui/higher-ranked/subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.stderr diff --git a/tests/ui/hr-subtype/hr-subtype.free_inv_x_vs_free_inv_y.stderr b/tests/ui/higher-ranked/subtype/hr-subtype.free_inv_x_vs_free_inv_y.stderr index 31d36d7168b..31d36d7168b 100644 --- a/tests/ui/hr-subtype/hr-subtype.free_inv_x_vs_free_inv_y.stderr +++ b/tests/ui/higher-ranked/subtype/hr-subtype.free_inv_x_vs_free_inv_y.stderr diff --git a/tests/ui/hr-subtype/hr-subtype.free_x_vs_free_y.stderr b/tests/ui/higher-ranked/subtype/hr-subtype.free_x_vs_free_y.stderr index 269cde54c7e..269cde54c7e 100644 --- a/tests/ui/hr-subtype/hr-subtype.free_x_vs_free_y.stderr +++ b/tests/ui/higher-ranked/subtype/hr-subtype.free_x_vs_free_y.stderr diff --git a/tests/ui/hr-subtype/hr-subtype.rs b/tests/ui/higher-ranked/subtype/hr-subtype.rs index c770e0de85c..c770e0de85c 100644 --- a/tests/ui/hr-subtype/hr-subtype.rs +++ b/tests/ui/higher-ranked/subtype/hr-subtype.rs diff --git a/tests/ui/hr-subtype/placeholder-pattern-fail.rs b/tests/ui/higher-ranked/subtype/placeholder-pattern-fail.rs index bd4533e0433..bd4533e0433 100644 --- a/tests/ui/hr-subtype/placeholder-pattern-fail.rs +++ b/tests/ui/higher-ranked/subtype/placeholder-pattern-fail.rs diff --git a/tests/ui/hr-subtype/placeholder-pattern-fail.stderr b/tests/ui/higher-ranked/subtype/placeholder-pattern-fail.stderr index 73b0a317364..73b0a317364 100644 --- a/tests/ui/hr-subtype/placeholder-pattern-fail.stderr +++ b/tests/ui/higher-ranked/subtype/placeholder-pattern-fail.stderr diff --git a/tests/ui/hr-subtype/placeholder-pattern.rs b/tests/ui/higher-ranked/subtype/placeholder-pattern.rs index 061e66e54d2..061e66e54d2 100644 --- a/tests/ui/hr-subtype/placeholder-pattern.rs +++ b/tests/ui/higher-ranked/subtype/placeholder-pattern.rs diff --git a/tests/ui/hr-subtype/return-static.rs b/tests/ui/higher-ranked/subtype/return-static.rs index 6455854f34d..6455854f34d 100644 --- a/tests/ui/hr-subtype/return-static.rs +++ b/tests/ui/higher-ranked/subtype/return-static.rs diff --git a/tests/ui/higher-rank-trait-bounds/complex.rs b/tests/ui/higher-ranked/trait-bounds/complex.rs index 8cdfe247e02..8cdfe247e02 100644 --- a/tests/ui/higher-rank-trait-bounds/complex.rs +++ b/tests/ui/higher-ranked/trait-bounds/complex.rs diff --git a/tests/ui/higher-rank-trait-bounds/due-to-where-clause.rs b/tests/ui/higher-ranked/trait-bounds/due-to-where-clause.rs index 1afd15613b5..1afd15613b5 100644 --- a/tests/ui/higher-rank-trait-bounds/due-to-where-clause.rs +++ b/tests/ui/higher-ranked/trait-bounds/due-to-where-clause.rs diff --git a/tests/ui/higher-rank-trait-bounds/due-to-where-clause.stderr b/tests/ui/higher-ranked/trait-bounds/due-to-where-clause.stderr index 520938a6335..520938a6335 100644 --- a/tests/ui/higher-rank-trait-bounds/due-to-where-clause.stderr +++ b/tests/ui/higher-ranked/trait-bounds/due-to-where-clause.stderr diff --git a/tests/ui/higher-rank-trait-bounds/fn-ptr.classic.stderr b/tests/ui/higher-ranked/trait-bounds/fn-ptr.classic.stderr index 9af6bc45c7a..9af6bc45c7a 100644 --- a/tests/ui/higher-rank-trait-bounds/fn-ptr.classic.stderr +++ b/tests/ui/higher-ranked/trait-bounds/fn-ptr.classic.stderr diff --git a/tests/ui/higher-rank-trait-bounds/fn-ptr.rs b/tests/ui/higher-ranked/trait-bounds/fn-ptr.rs index 853160f9612..853160f9612 100644 --- a/tests/ui/higher-rank-trait-bounds/fn-ptr.rs +++ b/tests/ui/higher-ranked/trait-bounds/fn-ptr.rs diff --git a/tests/ui/higher-rank-trait-bounds/hang-on-deeply-nested-dyn.rs b/tests/ui/higher-ranked/trait-bounds/hang-on-deeply-nested-dyn.rs index d34b7a29623..d34b7a29623 100644 --- a/tests/ui/higher-rank-trait-bounds/hang-on-deeply-nested-dyn.rs +++ b/tests/ui/higher-ranked/trait-bounds/hang-on-deeply-nested-dyn.rs diff --git a/tests/ui/higher-rank-trait-bounds/hang-on-deeply-nested-dyn.stderr b/tests/ui/higher-ranked/trait-bounds/hang-on-deeply-nested-dyn.stderr index 3662cbfb9ba..a9d649b8285 100644 --- a/tests/ui/higher-rank-trait-bounds/hang-on-deeply-nested-dyn.stderr +++ b/tests/ui/higher-ranked/trait-bounds/hang-on-deeply-nested-dyn.stderr @@ -14,7 +14,7 @@ LL | f | ^ expected `&dyn Fn(&dyn Fn(&dyn Fn(&...)))`, found `&dyn Fn(u32)` | = note: expected reference `&dyn Fn(&dyn Fn(&dyn Fn(&dyn Fn(&dyn Fn(&dyn Fn(&dyn Fn(&dyn Fn(&dyn Fn(&dyn Fn(&dyn Fn(&...)))))))))))` - the full type name has been written to '$TEST_BUILD_DIR/higher-rank-trait-bounds/hang-on-deeply-nested-dyn/hang-on-deeply-nested-dyn.long-type-hash.txt' + the full type name has been written to '$TEST_BUILD_DIR/higher-ranked/trait-bounds/hang-on-deeply-nested-dyn/hang-on-deeply-nested-dyn.long-type-hash.txt' found reference `&dyn Fn(u32)` error: aborting due to previous error diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-binder-levels-in-object-types.rs b/tests/ui/higher-ranked/trait-bounds/hrtb-binder-levels-in-object-types.rs index cc766c0605c..cc766c0605c 100644 --- a/tests/ui/higher-rank-trait-bounds/hrtb-binder-levels-in-object-types.rs +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-binder-levels-in-object-types.rs diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-cache-issue-54302.rs b/tests/ui/higher-ranked/trait-bounds/hrtb-cache-issue-54302.rs index a20d03c7747..a20d03c7747 100644 --- a/tests/ui/higher-rank-trait-bounds/hrtb-cache-issue-54302.rs +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-cache-issue-54302.rs diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-cache-issue-54302.stderr b/tests/ui/higher-ranked/trait-bounds/hrtb-cache-issue-54302.stderr index f014eab8601..f014eab8601 100644 --- a/tests/ui/higher-rank-trait-bounds/hrtb-cache-issue-54302.stderr +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-cache-issue-54302.stderr diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-conflate-regions.rs b/tests/ui/higher-ranked/trait-bounds/hrtb-conflate-regions.rs index e83686404a3..e83686404a3 100644 --- a/tests/ui/higher-rank-trait-bounds/hrtb-conflate-regions.rs +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-conflate-regions.rs diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-conflate-regions.stderr b/tests/ui/higher-ranked/trait-bounds/hrtb-conflate-regions.stderr index 46f5308dd87..46f5308dd87 100644 --- a/tests/ui/higher-rank-trait-bounds/hrtb-conflate-regions.stderr +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-conflate-regions.stderr diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-debruijn-in-receiver.rs b/tests/ui/higher-ranked/trait-bounds/hrtb-debruijn-in-receiver.rs index 05d3e1a434e..05d3e1a434e 100644 --- a/tests/ui/higher-rank-trait-bounds/hrtb-debruijn-in-receiver.rs +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-debruijn-in-receiver.rs diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-debruijn-in-receiver.stderr b/tests/ui/higher-ranked/trait-bounds/hrtb-debruijn-in-receiver.stderr index fa391ecba8a..fa391ecba8a 100644 --- a/tests/ui/higher-rank-trait-bounds/hrtb-debruijn-in-receiver.stderr +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-debruijn-in-receiver.stderr diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-debruijn-object-types-in-closures.rs b/tests/ui/higher-ranked/trait-bounds/hrtb-debruijn-object-types-in-closures.rs index 8431226a3ec..8431226a3ec 100644 --- a/tests/ui/higher-rank-trait-bounds/hrtb-debruijn-object-types-in-closures.rs +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-debruijn-object-types-in-closures.rs diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-exists-forall-fn.rs b/tests/ui/higher-ranked/trait-bounds/hrtb-exists-forall-fn.rs index 56780237618..56780237618 100644 --- a/tests/ui/higher-rank-trait-bounds/hrtb-exists-forall-fn.rs +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-exists-forall-fn.rs diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-exists-forall-fn.stderr b/tests/ui/higher-ranked/trait-bounds/hrtb-exists-forall-fn.stderr index 9914783d976..9914783d976 100644 --- a/tests/ui/higher-rank-trait-bounds/hrtb-exists-forall-fn.stderr +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-exists-forall-fn.stderr diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-exists-forall-trait-contravariant.rs b/tests/ui/higher-ranked/trait-bounds/hrtb-exists-forall-trait-contravariant.rs index 921061916fc..921061916fc 100644 --- a/tests/ui/higher-rank-trait-bounds/hrtb-exists-forall-trait-contravariant.rs +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-exists-forall-trait-contravariant.rs diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-exists-forall-trait-contravariant.stderr b/tests/ui/higher-ranked/trait-bounds/hrtb-exists-forall-trait-contravariant.stderr index 364b613fc77..364b613fc77 100644 --- a/tests/ui/higher-rank-trait-bounds/hrtb-exists-forall-trait-contravariant.stderr +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-exists-forall-trait-contravariant.stderr diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-exists-forall-trait-covariant.rs b/tests/ui/higher-ranked/trait-bounds/hrtb-exists-forall-trait-covariant.rs index f95496a6c3c..f95496a6c3c 100644 --- a/tests/ui/higher-rank-trait-bounds/hrtb-exists-forall-trait-covariant.rs +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-exists-forall-trait-covariant.rs diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-exists-forall-trait-invariant.rs b/tests/ui/higher-ranked/trait-bounds/hrtb-exists-forall-trait-invariant.rs index 9b9e4496a87..9b9e4496a87 100644 --- a/tests/ui/higher-rank-trait-bounds/hrtb-exists-forall-trait-invariant.rs +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-exists-forall-trait-invariant.rs diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-exists-forall-trait-invariant.stderr b/tests/ui/higher-ranked/trait-bounds/hrtb-exists-forall-trait-invariant.stderr index cb2ce8a4116..cb2ce8a4116 100644 --- a/tests/ui/higher-rank-trait-bounds/hrtb-exists-forall-trait-invariant.stderr +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-exists-forall-trait-invariant.stderr diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-fn-like-trait-object.rs b/tests/ui/higher-ranked/trait-bounds/hrtb-fn-like-trait-object.rs index ff84ad9d298..ff84ad9d298 100644 --- a/tests/ui/higher-rank-trait-bounds/hrtb-fn-like-trait-object.rs +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-fn-like-trait-object.rs diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-fn-like-trait.rs b/tests/ui/higher-ranked/trait-bounds/hrtb-fn-like-trait.rs index afab9986ce2..afab9986ce2 100644 --- a/tests/ui/higher-rank-trait-bounds/hrtb-fn-like-trait.rs +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-fn-like-trait.rs diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-higher-ranker-supertraits-transitive.rs b/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits-transitive.rs index f9ae1429ee4..f9ae1429ee4 100644 --- a/tests/ui/higher-rank-trait-bounds/hrtb-higher-ranker-supertraits-transitive.rs +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits-transitive.rs diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-higher-ranker-supertraits-transitive.stderr b/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits-transitive.stderr index b1b8ffa8c54..b1b8ffa8c54 100644 --- a/tests/ui/higher-rank-trait-bounds/hrtb-higher-ranker-supertraits-transitive.stderr +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits-transitive.stderr diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-higher-ranker-supertraits.rs b/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits.rs index 48ebe5017aa..48ebe5017aa 100644 --- a/tests/ui/higher-rank-trait-bounds/hrtb-higher-ranker-supertraits.rs +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits.rs diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-higher-ranker-supertraits.stderr b/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits.stderr index 7f96909b6e7..7f96909b6e7 100644 --- a/tests/ui/higher-rank-trait-bounds/hrtb-higher-ranker-supertraits.stderr +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits.stderr diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-identity-fn-borrows.rs b/tests/ui/higher-ranked/trait-bounds/hrtb-identity-fn-borrows.rs index 89fc4705a78..89fc4705a78 100644 --- a/tests/ui/higher-rank-trait-bounds/hrtb-identity-fn-borrows.rs +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-identity-fn-borrows.rs diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-identity-fn-borrows.stderr b/tests/ui/higher-ranked/trait-bounds/hrtb-identity-fn-borrows.stderr index 25af011e3fc..25af011e3fc 100644 --- a/tests/ui/higher-rank-trait-bounds/hrtb-identity-fn-borrows.stderr +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-identity-fn-borrows.stderr diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-just-for-static.rs b/tests/ui/higher-ranked/trait-bounds/hrtb-just-for-static.rs index 8fb4218f8a4..8fb4218f8a4 100644 --- a/tests/ui/higher-rank-trait-bounds/hrtb-just-for-static.rs +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-just-for-static.rs diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-just-for-static.stderr b/tests/ui/higher-ranked/trait-bounds/hrtb-just-for-static.stderr index 31e11e12835..31e11e12835 100644 --- a/tests/ui/higher-rank-trait-bounds/hrtb-just-for-static.stderr +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-just-for-static.stderr diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-malformed-lifetime-generics.rs b/tests/ui/higher-ranked/trait-bounds/hrtb-malformed-lifetime-generics.rs index 4b096be591a..4b096be591a 100644 --- a/tests/ui/higher-rank-trait-bounds/hrtb-malformed-lifetime-generics.rs +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-malformed-lifetime-generics.rs diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-malformed-lifetime-generics.stderr b/tests/ui/higher-ranked/trait-bounds/hrtb-malformed-lifetime-generics.stderr index e8f6d63b5ab..e8f6d63b5ab 100644 --- a/tests/ui/higher-rank-trait-bounds/hrtb-malformed-lifetime-generics.stderr +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-malformed-lifetime-generics.stderr diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-opt-in-copy.rs b/tests/ui/higher-ranked/trait-bounds/hrtb-opt-in-copy.rs index 04519f11600..04519f11600 100644 --- a/tests/ui/higher-rank-trait-bounds/hrtb-opt-in-copy.rs +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-opt-in-copy.rs diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-parse.rs b/tests/ui/higher-ranked/trait-bounds/hrtb-parse.rs index 1fab9758c5c..1fab9758c5c 100644 --- a/tests/ui/higher-rank-trait-bounds/hrtb-parse.rs +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-parse.rs diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-perfect-forwarding.polonius.stderr b/tests/ui/higher-ranked/trait-bounds/hrtb-perfect-forwarding.polonius.stderr index a94c80eb30b..a94c80eb30b 100644 --- a/tests/ui/higher-rank-trait-bounds/hrtb-perfect-forwarding.polonius.stderr +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-perfect-forwarding.polonius.stderr diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-perfect-forwarding.rs b/tests/ui/higher-ranked/trait-bounds/hrtb-perfect-forwarding.rs index d45fa183c0c..d45fa183c0c 100644 --- a/tests/ui/higher-rank-trait-bounds/hrtb-perfect-forwarding.rs +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-perfect-forwarding.rs diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-perfect-forwarding.stderr b/tests/ui/higher-ranked/trait-bounds/hrtb-perfect-forwarding.stderr index 727b9e6bec8..727b9e6bec8 100644 --- a/tests/ui/higher-rank-trait-bounds/hrtb-perfect-forwarding.stderr +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-perfect-forwarding.stderr diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-precedence-of-plus-where-clause.rs b/tests/ui/higher-ranked/trait-bounds/hrtb-precedence-of-plus-where-clause.rs index 42247798f66..42247798f66 100644 --- a/tests/ui/higher-rank-trait-bounds/hrtb-precedence-of-plus-where-clause.rs +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-precedence-of-plus-where-clause.rs diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-precedence-of-plus.rs b/tests/ui/higher-ranked/trait-bounds/hrtb-precedence-of-plus.rs index 6834c392d4e..6834c392d4e 100644 --- a/tests/ui/higher-rank-trait-bounds/hrtb-precedence-of-plus.rs +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-precedence-of-plus.rs diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-resolve-lifetime.rs b/tests/ui/higher-ranked/trait-bounds/hrtb-resolve-lifetime.rs index b97fdf4df50..b97fdf4df50 100644 --- a/tests/ui/higher-rank-trait-bounds/hrtb-resolve-lifetime.rs +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-resolve-lifetime.rs diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-trait-object-paren-notation.rs b/tests/ui/higher-ranked/trait-bounds/hrtb-trait-object-paren-notation.rs index d8c726cdd71..d8c726cdd71 100644 --- a/tests/ui/higher-rank-trait-bounds/hrtb-trait-object-paren-notation.rs +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-trait-object-paren-notation.rs diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-trait-object-passed-to-closure.rs b/tests/ui/higher-ranked/trait-bounds/hrtb-trait-object-passed-to-closure.rs index 41ebb3f5a14..41ebb3f5a14 100644 --- a/tests/ui/higher-rank-trait-bounds/hrtb-trait-object-passed-to-closure.rs +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-trait-object-passed-to-closure.rs diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-type-outlives.rs b/tests/ui/higher-ranked/trait-bounds/hrtb-type-outlives.rs index 88d396101db..88d396101db 100644 --- a/tests/ui/higher-rank-trait-bounds/hrtb-type-outlives.rs +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-type-outlives.rs diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-unboxed-closure-trait.rs b/tests/ui/higher-ranked/trait-bounds/hrtb-unboxed-closure-trait.rs index a4a8a5ac6cc..a4a8a5ac6cc 100644 --- a/tests/ui/higher-rank-trait-bounds/hrtb-unboxed-closure-trait.rs +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-unboxed-closure-trait.rs diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-wrong-kind.rs b/tests/ui/higher-ranked/trait-bounds/hrtb-wrong-kind.rs index 1a9bb252340..1a9bb252340 100644 --- a/tests/ui/higher-rank-trait-bounds/hrtb-wrong-kind.rs +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-wrong-kind.rs diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-wrong-kind.stderr b/tests/ui/higher-ranked/trait-bounds/hrtb-wrong-kind.stderr index 765ea9f7854..765ea9f7854 100644 --- a/tests/ui/higher-rank-trait-bounds/hrtb-wrong-kind.stderr +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-wrong-kind.stderr diff --git a/tests/ui/higher-rank-trait-bounds/issue-100689.rs b/tests/ui/higher-ranked/trait-bounds/issue-100689.rs index 2db7f8a354c..2db7f8a354c 100644 --- a/tests/ui/higher-rank-trait-bounds/issue-100689.rs +++ b/tests/ui/higher-ranked/trait-bounds/issue-100689.rs diff --git a/tests/ui/higher-rank-trait-bounds/issue-102899.rs b/tests/ui/higher-ranked/trait-bounds/issue-102899.rs index 952b81584f3..952b81584f3 100644 --- a/tests/ui/higher-rank-trait-bounds/issue-102899.rs +++ b/tests/ui/higher-ranked/trait-bounds/issue-102899.rs diff --git a/tests/ui/higher-rank-trait-bounds/issue-30786.rs b/tests/ui/higher-ranked/trait-bounds/issue-30786.rs index 4a6399c8f62..4a6399c8f62 100644 --- a/tests/ui/higher-rank-trait-bounds/issue-30786.rs +++ b/tests/ui/higher-ranked/trait-bounds/issue-30786.rs diff --git a/tests/ui/higher-rank-trait-bounds/issue-30786.stderr b/tests/ui/higher-ranked/trait-bounds/issue-30786.stderr index 6ec34d11a7e..f32ba57200d 100644 --- a/tests/ui/higher-rank-trait-bounds/issue-30786.stderr +++ b/tests/ui/higher-ranked/trait-bounds/issue-30786.stderr @@ -31,7 +31,7 @@ LL | pub struct Filter<S, F> { LL | let count = filter.countx(); | ^^^^^^ method cannot be called due to unsatisfied trait bounds | - = note: the full type name has been written to '$TEST_BUILD_DIR/higher-rank-trait-bounds/issue-30786/issue-30786.long-type-hash.txt' + = note: the full type name has been written to '$TEST_BUILD_DIR/higher-ranked/trait-bounds/issue-30786/issue-30786.long-type-hash.txt' note: the following trait bounds were not satisfied: `&'a mut &Filter<Map<Repeat, for<'a> fn(&'a u64) -> &'a u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:131:30: 131:37]>: Stream` `&'a mut &mut Filter<Map<Repeat, for<'a> fn(&'a u64) -> &'a u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:131:30: 131:37]>: Stream` diff --git a/tests/ui/higher-rank-trait-bounds/issue-36139-normalize-closure-sig.rs b/tests/ui/higher-ranked/trait-bounds/issue-36139-normalize-closure-sig.rs index 2d49151ffcc..2d49151ffcc 100644 --- a/tests/ui/higher-rank-trait-bounds/issue-36139-normalize-closure-sig.rs +++ b/tests/ui/higher-ranked/trait-bounds/issue-36139-normalize-closure-sig.rs diff --git a/tests/ui/higher-rank-trait-bounds/issue-39292.rs b/tests/ui/higher-ranked/trait-bounds/issue-39292.rs index 968cf08916f..968cf08916f 100644 --- a/tests/ui/higher-rank-trait-bounds/issue-39292.rs +++ b/tests/ui/higher-ranked/trait-bounds/issue-39292.rs diff --git a/tests/ui/higher-rank-trait-bounds/issue-42114.rs b/tests/ui/higher-ranked/trait-bounds/issue-42114.rs index 01515fdc9d2..01515fdc9d2 100644 --- a/tests/ui/higher-rank-trait-bounds/issue-42114.rs +++ b/tests/ui/higher-ranked/trait-bounds/issue-42114.rs diff --git a/tests/ui/higher-rank-trait-bounds/issue-43623.rs b/tests/ui/higher-ranked/trait-bounds/issue-43623.rs index cedcf7c361c..cedcf7c361c 100644 --- a/tests/ui/higher-rank-trait-bounds/issue-43623.rs +++ b/tests/ui/higher-ranked/trait-bounds/issue-43623.rs diff --git a/tests/ui/higher-rank-trait-bounds/issue-46989.rs b/tests/ui/higher-ranked/trait-bounds/issue-46989.rs index 4a09f4be156..4a09f4be156 100644 --- a/tests/ui/higher-rank-trait-bounds/issue-46989.rs +++ b/tests/ui/higher-ranked/trait-bounds/issue-46989.rs diff --git a/tests/ui/higher-rank-trait-bounds/issue-46989.stderr b/tests/ui/higher-ranked/trait-bounds/issue-46989.stderr index 3f874220a27..3f874220a27 100644 --- a/tests/ui/higher-rank-trait-bounds/issue-46989.stderr +++ b/tests/ui/higher-ranked/trait-bounds/issue-46989.stderr diff --git a/tests/ui/higher-rank-trait-bounds/issue-57639.rs b/tests/ui/higher-ranked/trait-bounds/issue-57639.rs index 392e7233b56..392e7233b56 100644 --- a/tests/ui/higher-rank-trait-bounds/issue-57639.rs +++ b/tests/ui/higher-ranked/trait-bounds/issue-57639.rs diff --git a/tests/ui/higher-rank-trait-bounds/issue-58451.rs b/tests/ui/higher-ranked/trait-bounds/issue-58451.rs index 6006a108c5c..6006a108c5c 100644 --- a/tests/ui/higher-rank-trait-bounds/issue-58451.rs +++ b/tests/ui/higher-ranked/trait-bounds/issue-58451.rs diff --git a/tests/ui/higher-rank-trait-bounds/issue-58451.stderr b/tests/ui/higher-ranked/trait-bounds/issue-58451.stderr index 0f051be2128..0f051be2128 100644 --- a/tests/ui/higher-rank-trait-bounds/issue-58451.stderr +++ b/tests/ui/higher-ranked/trait-bounds/issue-58451.stderr diff --git a/tests/ui/higher-rank-trait-bounds/issue-59311.rs b/tests/ui/higher-ranked/trait-bounds/issue-59311.rs index 3ad548450e5..3ad548450e5 100644 --- a/tests/ui/higher-rank-trait-bounds/issue-59311.rs +++ b/tests/ui/higher-ranked/trait-bounds/issue-59311.rs diff --git a/tests/ui/higher-rank-trait-bounds/issue-59311.stderr b/tests/ui/higher-ranked/trait-bounds/issue-59311.stderr index c01ab8e347c..c01ab8e347c 100644 --- a/tests/ui/higher-rank-trait-bounds/issue-59311.stderr +++ b/tests/ui/higher-ranked/trait-bounds/issue-59311.stderr diff --git a/tests/ui/higher-rank-trait-bounds/issue-60283.rs b/tests/ui/higher-ranked/trait-bounds/issue-60283.rs index 05315b3f9f5..05315b3f9f5 100644 --- a/tests/ui/higher-rank-trait-bounds/issue-60283.rs +++ b/tests/ui/higher-ranked/trait-bounds/issue-60283.rs diff --git a/tests/ui/higher-rank-trait-bounds/issue-62203-hrtb-ice.rs b/tests/ui/higher-ranked/trait-bounds/issue-62203-hrtb-ice.rs index e70f6fc3430..e70f6fc3430 100644 --- a/tests/ui/higher-rank-trait-bounds/issue-62203-hrtb-ice.rs +++ b/tests/ui/higher-ranked/trait-bounds/issue-62203-hrtb-ice.rs diff --git a/tests/ui/higher-rank-trait-bounds/issue-62203-hrtb-ice.stderr b/tests/ui/higher-ranked/trait-bounds/issue-62203-hrtb-ice.stderr index 4d470ae7022..4d470ae7022 100644 --- a/tests/ui/higher-rank-trait-bounds/issue-62203-hrtb-ice.stderr +++ b/tests/ui/higher-ranked/trait-bounds/issue-62203-hrtb-ice.stderr diff --git a/tests/ui/higher-rank-trait-bounds/issue-88446.rs b/tests/ui/higher-ranked/trait-bounds/issue-88446.rs index 571b8531757..571b8531757 100644 --- a/tests/ui/higher-rank-trait-bounds/issue-88446.rs +++ b/tests/ui/higher-ranked/trait-bounds/issue-88446.rs diff --git a/tests/ui/higher-rank-trait-bounds/issue-88586-hr-self-outlives-in-trait-def.rs b/tests/ui/higher-ranked/trait-bounds/issue-88586-hr-self-outlives-in-trait-def.rs index 92b7c5deb81..92b7c5deb81 100644 --- a/tests/ui/higher-rank-trait-bounds/issue-88586-hr-self-outlives-in-trait-def.rs +++ b/tests/ui/higher-ranked/trait-bounds/issue-88586-hr-self-outlives-in-trait-def.rs diff --git a/tests/ui/higher-rank-trait-bounds/issue-90177.rs b/tests/ui/higher-ranked/trait-bounds/issue-90177.rs index b151a9d3ab6..b151a9d3ab6 100644 --- a/tests/ui/higher-rank-trait-bounds/issue-90177.rs +++ b/tests/ui/higher-ranked/trait-bounds/issue-90177.rs diff --git a/tests/ui/higher-rank-trait-bounds/issue-95034.rs b/tests/ui/higher-ranked/trait-bounds/issue-95034.rs index af4946a187f..af4946a187f 100644 --- a/tests/ui/higher-rank-trait-bounds/issue-95034.rs +++ b/tests/ui/higher-ranked/trait-bounds/issue-95034.rs diff --git a/tests/ui/higher-rank-trait-bounds/issue-95230.new.stderr b/tests/ui/higher-ranked/trait-bounds/issue-95230.next.stderr index d4bc5b67220..d4bc5b67220 100644 --- a/tests/ui/higher-rank-trait-bounds/issue-95230.new.stderr +++ b/tests/ui/higher-ranked/trait-bounds/issue-95230.next.stderr diff --git a/tests/ui/higher-ranked/trait-bounds/issue-95230.rs b/tests/ui/higher-ranked/trait-bounds/issue-95230.rs new file mode 100644 index 00000000000..49a1584d54e --- /dev/null +++ b/tests/ui/higher-ranked/trait-bounds/issue-95230.rs @@ -0,0 +1,11 @@ +// revisions: old next +//[next] compile-flags: -Ztrait-solver=next +//[old] check-pass +//[next] known-bug: #109764 + + +pub struct Bar +where + for<'a> &'a mut Self:; + +fn main() {} diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-44005.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-44005.rs index f255eac0c4b..f255eac0c4b 100644 --- a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-44005.rs +++ b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-44005.rs diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-56556.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-56556.rs index 4d38cb19e9b..4d38cb19e9b 100644 --- a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-56556.rs +++ b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-56556.rs diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-1.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-1.rs index c6f29fa5908..c6f29fa5908 100644 --- a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-1.rs +++ b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-1.rs diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-2.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-2.rs index 00205473291..00205473291 100644 --- a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-2.rs +++ b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-2.rs diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-3.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-3.rs index d84e30f4984..d84e30f4984 100644 --- a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-3.rs +++ b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-3.rs diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-3.stderr b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-3.stderr index b30dd36d2ad..b30dd36d2ad 100644 --- a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-3.stderr +++ b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-3.stderr diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-4.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-4.rs index 8c2a59868ca..8c2a59868ca 100644 --- a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-4.rs +++ b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-4.rs diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-5.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-5.rs index 03f257a029c..03f257a029c 100644 --- a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-5.rs +++ b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-5.rs diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-6.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-6.rs index 74a4785e478..74a4785e478 100644 --- a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-6.rs +++ b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-6.rs diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-70120.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-70120.rs index 3ced40230f0..3ced40230f0 100644 --- a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-70120.rs +++ b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-70120.rs diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.migrate.stderr b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.migrate.stderr index 0f38f8e3283..0f38f8e3283 100644 --- a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.migrate.stderr +++ b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.migrate.stderr diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.rs index 1d90226a3f4..1d90226a3f4 100644 --- a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.rs +++ b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.rs diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.stderr b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.stderr index 4ef96cd9541..4ef96cd9541 100644 --- a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.stderr +++ b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.stderr diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-74261.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-74261.rs index 93ccb42684c..93ccb42684c 100644 --- a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-74261.rs +++ b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-74261.rs diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-76956.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-76956.rs index 583470080a2..583470080a2 100644 --- a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-76956.rs +++ b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-76956.rs diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-80706.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-80706.rs index 00a866f220b..00a866f220b 100644 --- a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-80706.rs +++ b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-80706.rs diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-80956.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-80956.rs index 6316ceea156..6316ceea156 100644 --- a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-80956.rs +++ b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-80956.rs diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-81809.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-81809.rs index f6ab9c203b5..f6ab9c203b5 100644 --- a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-81809.rs +++ b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-81809.rs diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-85455.rs index 8aa29926d4f..8aa29926d4f 100644 --- a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.rs +++ b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-85455.rs diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.stderr b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-85455.stderr index 3240518fbbe..3240518fbbe 100644 --- a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.stderr +++ b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-85455.stderr diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-89118.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-89118.rs index fffb54f86ca..fffb54f86ca 100644 --- a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-89118.rs +++ b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-89118.rs diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-89118.stderr b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-89118.stderr index edef6ccd34e..edef6ccd34e 100644 --- a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-89118.stderr +++ b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-89118.stderr diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-89436.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-89436.rs index f7e467b3786..f7e467b3786 100644 --- a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-89436.rs +++ b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-89436.rs diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90612.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-90612.rs index effc329456d..effc329456d 100644 --- a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90612.rs +++ b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-90612.rs diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90638.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-90638.rs index 628b5cba104..628b5cba104 100644 --- a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90638.rs +++ b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-90638.rs diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90875.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-90875.rs index ffd6857d84a..ffd6857d84a 100644 --- a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90875.rs +++ b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-90875.rs diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90950.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-90950.rs index ab9d9a7ce6f..ab9d9a7ce6f 100644 --- a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90950.rs +++ b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-90950.rs diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90950.stderr b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-90950.stderr index 5be33bccdc3..5be33bccdc3 100644 --- a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90950.stderr +++ b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-90950.stderr diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/norm-before-method-resolution.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/norm-before-method-resolution.rs index 7693b118247..7693b118247 100644 --- a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/norm-before-method-resolution.rs +++ b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/norm-before-method-resolution.rs diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/norm-before-method-resolution.stderr b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/norm-before-method-resolution.stderr index 73388a72574..73388a72574 100644 --- a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/norm-before-method-resolution.stderr +++ b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/norm-before-method-resolution.stderr diff --git a/tests/ui/impl-trait/autoderef.rs b/tests/ui/impl-trait/autoderef.rs index 5e4f4995447..0d07a549640 100644 --- a/tests/ui/impl-trait/autoderef.rs +++ b/tests/ui/impl-trait/autoderef.rs @@ -1,3 +1,5 @@ +// revisions: current next +//[next] compile-flag: -Ztrait-solver=next // check-pass use std::path::Path; diff --git a/tests/ui/impl-trait/multiple-defining-usages-in-body.rs b/tests/ui/impl-trait/multiple-defining-usages-in-body.rs new file mode 100644 index 00000000000..c3a6f09f86d --- /dev/null +++ b/tests/ui/impl-trait/multiple-defining-usages-in-body.rs @@ -0,0 +1,12 @@ +trait Trait {} +impl Trait for () {} + +fn foo<T: Trait, U: Trait>() -> impl Trait { + //~^ WARN function cannot return without recursing [unconditional_recursion] + let a: T = foo::<T, U>(); + //~^ ERROR concrete type differs from previous defining opaque type use + loop {} + let _: T = foo::<U, T>(); +} + +fn main() {} diff --git a/tests/ui/impl-trait/multiple-defining-usages-in-body.stderr b/tests/ui/impl-trait/multiple-defining-usages-in-body.stderr new file mode 100644 index 00000000000..06991749bfa --- /dev/null +++ b/tests/ui/impl-trait/multiple-defining-usages-in-body.stderr @@ -0,0 +1,26 @@ +warning: function cannot return without recursing + --> $DIR/multiple-defining-usages-in-body.rs:4:1 + | +LL | fn foo<T: Trait, U: Trait>() -> impl Trait { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing +LL | +LL | let a: T = foo::<T, U>(); + | ------------- recursive call site + | + = help: a `loop` may express intention better if this is on purpose + = note: `#[warn(unconditional_recursion)]` on by default + +error: concrete type differs from previous defining opaque type use + --> $DIR/multiple-defining-usages-in-body.rs:6:16 + | +LL | let a: T = foo::<T, U>(); + | ^^^^^^^^^^^^^ expected `U`, got `T` + | +note: previous use here + --> $DIR/multiple-defining-usages-in-body.rs:9:16 + | +LL | let _: T = foo::<U, T>(); + | ^^^^^^^^^^^^^ + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/ui/imports/issue-55884-2.rs b/tests/ui/imports/issue-55884-2.rs index 75bb4206f97..6f8d0cf8ae2 100644 --- a/tests/ui/imports/issue-55884-2.rs +++ b/tests/ui/imports/issue-55884-2.rs @@ -6,6 +6,7 @@ mod parser { pub use options::*; // Private single import shadows public glob import, but arrives too late for initial // resolution of `use parser::ParseOptions` because it depends on that resolution itself. + #[allow(hidden_glob_reexports)] use ParseOptions; } diff --git a/tests/ui/imports/issue-55884-2.stderr b/tests/ui/imports/issue-55884-2.stderr index 5adbc4b66d1..67d4114149a 100644 --- a/tests/ui/imports/issue-55884-2.stderr +++ b/tests/ui/imports/issue-55884-2.stderr @@ -1,16 +1,16 @@ error[E0603]: struct import `ParseOptions` is private - --> $DIR/issue-55884-2.rs:12:17 + --> $DIR/issue-55884-2.rs:13:17 | LL | pub use parser::ParseOptions; | ^^^^^^^^^^^^ private struct import | note: the struct import `ParseOptions` is defined here... - --> $DIR/issue-55884-2.rs:9:9 + --> $DIR/issue-55884-2.rs:10:9 | LL | use ParseOptions; | ^^^^^^^^^^^^ note: ...and refers to the struct import `ParseOptions` which is defined here... - --> $DIR/issue-55884-2.rs:12:9 + --> $DIR/issue-55884-2.rs:13:9 | LL | pub use parser::ParseOptions; | ^^^^^^^^^^^^^^^^^^^^ consider importing it directly diff --git a/tests/ui/issues/issue-17954.stderr b/tests/ui/issues/issue-17954.stderr index e08375fee1f..3e3706bcb7d 100644 --- a/tests/ui/issues/issue-17954.stderr +++ b/tests/ui/issues/issue-17954.stderr @@ -5,7 +5,7 @@ LL | let a = &FOO; | ^^^^ thread-local variables cannot be borrowed beyond the end of the function ... LL | } - | - end of enclosing function is here + | - end of enclosing function is here error: aborting due to previous error diff --git a/tests/ui/issues/issue-52049.stderr b/tests/ui/issues/issue-52049.stderr index b25dbd1cb8b..0812976cf40 100644 --- a/tests/ui/issues/issue-52049.stderr +++ b/tests/ui/issues/issue-52049.stderr @@ -2,12 +2,10 @@ error[E0716]: temporary value dropped while borrowed --> $DIR/issue-52049.rs:6:10 | LL | foo(&unpromotable(5u32)); - | -----^^^^^^^^^^^^^^^^^^- + | -----^^^^^^^^^^^^^^^^^^-- temporary value is freed at the end of this statement | | | | | creates a temporary value which is freed while still in use | argument requires that borrow lasts for `'static` -LL | } - | - temporary value is freed at the end of this statement error: aborting due to previous error diff --git a/tests/ui/lifetimes/issue-90600-expected-return-static-indirect.stderr b/tests/ui/lifetimes/issue-90600-expected-return-static-indirect.stderr index 3602de8dd95..598f1424191 100644 --- a/tests/ui/lifetimes/issue-90600-expected-return-static-indirect.stderr +++ b/tests/ui/lifetimes/issue-90600-expected-return-static-indirect.stderr @@ -10,7 +10,7 @@ LL | let read = &refcell as &RefCell<dyn Read>; | -------- cast requires that `foo` is borrowed for `'static` ... LL | } - | - `foo` dropped here while still borrowed + | - `foo` dropped here while still borrowed error: lifetime may not live long enough --> $DIR/issue-90600-expected-return-static-indirect.rs:9:16 diff --git a/tests/ui/lint/invalid_from_utf8.rs b/tests/ui/lint/invalid_from_utf8.rs new file mode 100644 index 00000000000..9c8c636812e --- /dev/null +++ b/tests/ui/lint/invalid_from_utf8.rs @@ -0,0 +1,93 @@ +// check-pass + +#![feature(concat_bytes)] +#![warn(invalid_from_utf8_unchecked)] +#![warn(invalid_from_utf8)] + +pub fn from_utf8_unchecked_mut() { + // Valid + unsafe { + std::str::from_utf8_unchecked_mut(&mut [99, 108, 105, 112, 112, 121]); + std::str::from_utf8_unchecked_mut(&mut [b'c', b'l', b'i', b'p', b'p', b'y']); + + let x = 0xA0; + std::str::from_utf8_unchecked_mut(&mut [0xC0, x]); + } + + // Invalid + unsafe { + std::str::from_utf8_unchecked_mut(&mut [99, 108, 130, 105, 112, 112, 121]); + //~^ WARN calls to `std::str::from_utf8_unchecked_mut` + std::str::from_utf8_unchecked_mut(&mut [b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']); + //~^ WARN calls to `std::str::from_utf8_unchecked_mut` + } +} + +pub fn from_utf8_unchecked() { + // Valid + unsafe { + std::str::from_utf8_unchecked(&[99, 108, 105, 112, 112, 121]); + std::str::from_utf8_unchecked(&[b'c', b'l', b'i', b'p', b'p', b'y']); + std::str::from_utf8_unchecked(b"clippy"); + + let x = 0xA0; + std::str::from_utf8_unchecked(&[0xC0, x]); + } + + // Invalid + unsafe { + std::str::from_utf8_unchecked(&[99, 108, 130, 105, 112, 112, 121]); + //~^ WARN calls to `std::str::from_utf8_unchecked` + std::str::from_utf8_unchecked(&[b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']); + //~^ WARN calls to `std::str::from_utf8_unchecked` + std::str::from_utf8_unchecked(b"cl\x82ippy"); + //~^ WARN calls to `std::str::from_utf8_unchecked` + std::str::from_utf8_unchecked(concat_bytes!(b"cl", b"\x82ippy")); + //~^ WARN calls to `std::str::from_utf8_unchecked` + } +} + +pub fn from_utf8_mut() { + // Valid + { + std::str::from_utf8_mut(&mut [99, 108, 105, 112, 112, 121]); + std::str::from_utf8_mut(&mut [b'c', b'l', b'i', b'p', b'p', b'y']); + + let x = 0xa0; + std::str::from_utf8_mut(&mut [0xc0, x]); + } + + // Invalid + { + std::str::from_utf8_mut(&mut [99, 108, 130, 105, 112, 112, 121]); + //~^ WARN calls to `std::str::from_utf8_mut` + std::str::from_utf8_mut(&mut [b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']); + //~^ WARN calls to `std::str::from_utf8_mut` + } +} + +pub fn from_utf8() { + // Valid + { + std::str::from_utf8(&[99, 108, 105, 112, 112, 121]); + std::str::from_utf8(&[b'c', b'l', b'i', b'p', b'p', b'y']); + std::str::from_utf8(b"clippy"); + + let x = 0xA0; + std::str::from_utf8(&[0xC0, x]); + } + + // Invalid + { + std::str::from_utf8(&[99, 108, 130, 105, 112, 112, 121]); + //~^ WARN calls to `std::str::from_utf8` + std::str::from_utf8(&[b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']); + //~^ WARN calls to `std::str::from_utf8` + std::str::from_utf8(b"cl\x82ippy"); + //~^ WARN calls to `std::str::from_utf8` + std::str::from_utf8(concat_bytes!(b"cl", b"\x82ippy")); + //~^ WARN calls to `std::str::from_utf8` + } +} + +fn main() {} diff --git a/tests/ui/lint/invalid_from_utf8.stderr b/tests/ui/lint/invalid_from_utf8.stderr new file mode 100644 index 00000000000..8e00d3bf872 --- /dev/null +++ b/tests/ui/lint/invalid_from_utf8.stderr @@ -0,0 +1,110 @@ +warning: calls to `std::str::from_utf8_unchecked_mut` with a invalid literal are undefined behavior + --> $DIR/invalid_from_utf8.rs:19:9 + | +LL | std::str::from_utf8_unchecked_mut(&mut [99, 108, 130, 105, 112, 112, 121]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------------------------------^ + | | + | the literal was valid UTF-8 up to the 2 bytes + | +note: the lint level is defined here + --> $DIR/invalid_from_utf8.rs:4:9 + | +LL | #![warn(invalid_from_utf8_unchecked)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: calls to `std::str::from_utf8_unchecked_mut` with a invalid literal are undefined behavior + --> $DIR/invalid_from_utf8.rs:21:9 + | +LL | std::str::from_utf8_unchecked_mut(&mut [b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--------------------------------------------------^ + | | + | the literal was valid UTF-8 up to the 2 bytes + +warning: calls to `std::str::from_utf8_unchecked` with a invalid literal are undefined behavior + --> $DIR/invalid_from_utf8.rs:39:9 + | +LL | std::str::from_utf8_unchecked(&[99, 108, 130, 105, 112, 112, 121]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------------------------------^ + | | + | the literal was valid UTF-8 up to the 2 bytes + +warning: calls to `std::str::from_utf8_unchecked` with a invalid literal are undefined behavior + --> $DIR/invalid_from_utf8.rs:41:9 + | +LL | std::str::from_utf8_unchecked(&[b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------------------------------------^ + | | + | the literal was valid UTF-8 up to the 2 bytes + +warning: calls to `std::str::from_utf8_unchecked` with a invalid literal are undefined behavior + --> $DIR/invalid_from_utf8.rs:43:9 + | +LL | std::str::from_utf8_unchecked(b"cl\x82ippy"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-------------^ + | | + | the literal was valid UTF-8 up to the 2 bytes + +warning: calls to `std::str::from_utf8_unchecked` with a invalid literal are undefined behavior + --> $DIR/invalid_from_utf8.rs:45:9 + | +LL | std::str::from_utf8_unchecked(concat_bytes!(b"cl", b"\x82ippy")); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------------------------^ + | | + | the literal was valid UTF-8 up to the 2 bytes + +warning: calls to `std::str::from_utf8_mut` with a invalid literal always return an error + --> $DIR/invalid_from_utf8.rs:62:9 + | +LL | std::str::from_utf8_mut(&mut [99, 108, 130, 105, 112, 112, 121]); + | ^^^^^^^^^^^^^^^^^^^^^^^^---------------------------------------^ + | | + | the literal was valid UTF-8 up to the 2 bytes + | +note: the lint level is defined here + --> $DIR/invalid_from_utf8.rs:5:9 + | +LL | #![warn(invalid_from_utf8)] + | ^^^^^^^^^^^^^^^^^ + +warning: calls to `std::str::from_utf8_mut` with a invalid literal always return an error + --> $DIR/invalid_from_utf8.rs:64:9 + | +LL | std::str::from_utf8_mut(&mut [b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']); + | ^^^^^^^^^^^^^^^^^^^^^^^^--------------------------------------------------^ + | | + | the literal was valid UTF-8 up to the 2 bytes + +warning: calls to `std::str::from_utf8` with a invalid literal always return an error + --> $DIR/invalid_from_utf8.rs:82:9 + | +LL | std::str::from_utf8(&[99, 108, 130, 105, 112, 112, 121]); + | ^^^^^^^^^^^^^^^^^^^^-----------------------------------^ + | | + | the literal was valid UTF-8 up to the 2 bytes + +warning: calls to `std::str::from_utf8` with a invalid literal always return an error + --> $DIR/invalid_from_utf8.rs:84:9 + | +LL | std::str::from_utf8(&[b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']); + | ^^^^^^^^^^^^^^^^^^^^----------------------------------------------^ + | | + | the literal was valid UTF-8 up to the 2 bytes + +warning: calls to `std::str::from_utf8` with a invalid literal always return an error + --> $DIR/invalid_from_utf8.rs:86:9 + | +LL | std::str::from_utf8(b"cl\x82ippy"); + | ^^^^^^^^^^^^^^^^^^^^-------------^ + | | + | the literal was valid UTF-8 up to the 2 bytes + +warning: calls to `std::str::from_utf8` with a invalid literal always return an error + --> $DIR/invalid_from_utf8.rs:88:9 + | +LL | std::str::from_utf8(concat_bytes!(b"cl", b"\x82ippy")); + | ^^^^^^^^^^^^^^^^^^^^---------------------------------^ + | | + | the literal was valid UTF-8 up to the 2 bytes + +warning: 12 warnings emitted + diff --git a/tests/ui/lint/rfc-2383-lint-reason/root-attribute-confusion.rs b/tests/ui/lint/rfc-2383-lint-reason/root-attribute-confusion.rs new file mode 100644 index 00000000000..0cade7fef02 --- /dev/null +++ b/tests/ui/lint/rfc-2383-lint-reason/root-attribute-confusion.rs @@ -0,0 +1,7 @@ +// check-pass +// compile-flags: -Dunused_attributes + +#![deny(unused_crate_dependencies)] +#![feature(lint_reasons)] + +fn main() {} diff --git a/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-with-drop.rs b/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-with-drop.rs index 293fdca1cc9..c9b16e43910 100644 --- a/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-with-drop.rs +++ b/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-with-drop.rs @@ -5,7 +5,6 @@ fn test() { drop(b); b = Box::new(2); //~ ERROR cannot assign twice to immutable variable `b` //~| NOTE cannot assign twice to immutable - //~| NOTE in this expansion of desugaring of drop and replace drop(b); } diff --git a/tests/ui/macros/rfc-2011-nicer-assert-messages/all-expr-kinds.rs b/tests/ui/macros/rfc-2011-nicer-assert-messages/all-expr-kinds.rs index e88e24482cc..b1db05afd08 100644 --- a/tests/ui/macros/rfc-2011-nicer-assert-messages/all-expr-kinds.rs +++ b/tests/ui/macros/rfc-2011-nicer-assert-messages/all-expr-kinds.rs @@ -5,7 +5,7 @@ // needs-unwind Asserting on contents of error message #![allow(path_statements, unused_allocation)] -#![feature(core_intrinsics, generic_assert, generic_assert_internals)] +#![feature(core_intrinsics, generic_assert)] macro_rules! test { ( @@ -51,6 +51,7 @@ macro_rules! tests { const FOO: Foo = Foo { bar: 1 }; + #[derive(Clone, Copy, Debug, PartialEq)] struct Foo { bar: i32 @@ -83,9 +84,18 @@ fn main() { // cast [ elem as i32 == 3 ] => "Assertion failed: elem as i32 == 3\nWith captures:\n elem = 1\n" + // if + [ if elem == 3 { true } else { false } ] => "Assertion failed: if elem == 3 { true } else { false }\nWith captures:\n elem = 1\n" + // index [ [1i32, 1][elem as usize] == 3 ] => "Assertion failed: [1i32, 1][elem as usize] == 3\nWith captures:\n elem = 1\n" + // let + [ if let 3 = elem { true } else { false } ] => "Assertion failed: if let 3 = elem { true } else { false }\nWith captures:\n elem = 1\n" + + // match + [ match elem { 3 => true, _ => false, } ] => "Assertion failed: match elem { 3 => true, _ => false, }\nWith captures:\n elem = 1\n" + // method call [ FOO.add(elem, elem) == 3 ] => "Assertion failed: FOO.add(elem, elem) == 3\nWith captures:\n elem = 1\n" @@ -107,77 +117,4 @@ fn main() { // unary [ -elem == -3 ] => "Assertion failed: -elem == -3\nWith captures:\n elem = 1\n" ); - - // ***** Disallowed ***** - - tests!( - let mut elem = 1i32; - - // assign - [ { let local = elem; local } == 3 ] => "Assertion failed: { let local = elem; local } == 3" - - // assign op - [ { elem += 1; elem } == 3 ] => "Assertion failed: { elem += 1; elem } == 3" - - // async - [ { let _ = async { elem }; elem } == 3 ] => "Assertion failed: { let _ = async { elem }; elem } == 3" - - // await - - // block - [ { elem } == 3 ] => "Assertion failed: { elem } == 3" - - // break - [ loop { break elem; } == 3 ] => "Assertion failed: loop { break elem; } == 3" - - // closure - [(|| elem)() == 3 ] => "Assertion failed: (|| elem)() == 3" - - // const block - - // continue - - // err - - // field - [ FOO.bar == 3 ] => "Assertion failed: FOO.bar == 3" - - // for loop - [ { for _ in 0..elem { elem; } elem } == 3 ] => "Assertion failed: { for _ in 0..elem { elem; } elem } == 3" - - // if - [ if true { elem } else { elem } == 3 ] => "Assertion failed: if true { elem } else { elem } == 3" - - // inline asm - - // let - [ if let true = true { elem } else { elem } == 3 ] => "Assertion failed: if let true = true { elem } else { elem } == 3" - - // lit - - // loop - [ loop { elem; break elem; } == 3 ] => "Assertion failed: loop { elem; break elem; } == 3" - - // mac call - - // match - [ match elem { _ => elem } == 3 ] => "Assertion failed: (match elem { _ => elem, }) == 3" - - // ret - [ (|| { return elem; })() == 3 ] => "Assertion failed: (|| { return elem; })() == 3" - - // try - [ (|| { Some(Some(elem)?) })() == Some(3) ] => "Assertion failed: (|| { Some(Some(elem)?) })() == Some(3)" - - // try block - - // underscore - - // while - [ { while false { elem; break; } elem } == 3 ] => "Assertion failed: { while false { elem; break; } elem } == 3" - - // yeet - - // yield - ); } diff --git a/tests/ui/macros/rfc-2011-nicer-assert-messages/all-not-available-cases.rs b/tests/ui/macros/rfc-2011-nicer-assert-messages/all-not-available-cases.rs index d46f396ee29..fcf4f367d04 100644 --- a/tests/ui/macros/rfc-2011-nicer-assert-messages/all-not-available-cases.rs +++ b/tests/ui/macros/rfc-2011-nicer-assert-messages/all-not-available-cases.rs @@ -4,7 +4,7 @@ // run-pass // needs-unwind Asserting on contents of error message -#![feature(core_intrinsics, generic_assert, generic_assert_internals)] +#![feature(core_intrinsics, generic_assert)] extern crate common; diff --git a/tests/ui/macros/rfc-2011-nicer-assert-messages/assert-with-custom-errors-does-not-create-unnecessary-code.rs b/tests/ui/macros/rfc-2011-nicer-assert-messages/assert-with-custom-errors-does-not-create-unnecessary-code.rs index 6a1435f792b..c8408d16fbb 100644 --- a/tests/ui/macros/rfc-2011-nicer-assert-messages/assert-with-custom-errors-does-not-create-unnecessary-code.rs +++ b/tests/ui/macros/rfc-2011-nicer-assert-messages/assert-with-custom-errors-does-not-create-unnecessary-code.rs @@ -1,7 +1,7 @@ // compile-flags: --test // run-pass -#![feature(core_intrinsics, generic_assert, generic_assert_internals)] +#![feature(core_intrinsics, generic_assert)] #[should_panic(expected = "Custom user message")] #[test] diff --git a/tests/ui/macros/rfc-2011-nicer-assert-messages/assert-without-captures-does-not-create-unnecessary-code.rs b/tests/ui/macros/rfc-2011-nicer-assert-messages/assert-without-captures-does-not-create-unnecessary-code.rs index 1f5a29ab524..0e3c14a5770 100644 --- a/tests/ui/macros/rfc-2011-nicer-assert-messages/assert-without-captures-does-not-create-unnecessary-code.rs +++ b/tests/ui/macros/rfc-2011-nicer-assert-messages/assert-without-captures-does-not-create-unnecessary-code.rs @@ -3,7 +3,7 @@ // run-pass // needs-unwind Asserting on contents of error message -#![feature(core_intrinsics, generic_assert, generic_assert_internals)] +#![feature(core_intrinsics, generic_assert)] extern crate common; diff --git a/tests/ui/macros/rfc-2011-nicer-assert-messages/feature-gate-generic_assert.rs b/tests/ui/macros/rfc-2011-nicer-assert-messages/feature-gate-generic_assert.rs index 01860adaac2..0d2518dc253 100644 --- a/tests/ui/macros/rfc-2011-nicer-assert-messages/feature-gate-generic_assert.rs +++ b/tests/ui/macros/rfc-2011-nicer-assert-messages/feature-gate-generic_assert.rs @@ -2,7 +2,7 @@ // ignore-tidy-linelength // run-pass -#![feature(core_intrinsics, generic_assert, generic_assert_internals)] +#![feature(core_intrinsics, generic_assert)] use std::fmt::{Debug, Formatter}; 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 5ec84b08ff8..57b79a56b7b 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,7 +1,7 @@ // check-pass // compile-flags: -Z unpretty=expanded -#![feature(core_intrinsics, generic_assert, generic_assert_internals)] +#![feature(core_intrinsics, generic_assert)] fn arbitrary_consuming_method_for_demonstration_purposes() { let elem = 1i32; 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 b69b5bc3b53..66321bc35f0 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 @@ -3,7 +3,7 @@ // check-pass // compile-flags: -Z unpretty=expanded -#![feature(core_intrinsics, generic_assert, generic_assert_internals)] +#![feature(core_intrinsics, generic_assert)] #[prelude_import] use ::std::prelude::rust_2015::*; #[macro_use] diff --git a/tests/ui/methods/call_method_unknown_pointee.rs b/tests/ui/methods/call_method_unknown_pointee.rs new file mode 100644 index 00000000000..fe4275f5367 --- /dev/null +++ b/tests/ui/methods/call_method_unknown_pointee.rs @@ -0,0 +1,28 @@ +// edition: 2018 + +// tests that the pointee type of a raw pointer must be known to call methods on it +// see also: `tests/ui/editions/edition-raw-pointer-method-2018.rs` + +fn main() { + let val = 1_u32; + let ptr = &val as *const u32; + unsafe { + let _a: i32 = (ptr as *const _).read(); + //~^ ERROR cannot call a method on a raw pointer with an unknown pointee type [E0699] + let b = ptr as *const _; + let _b: u8 = b.read(); + //~^ ERROR cannot call a method on a raw pointer with an unknown pointee type [E0699] + let _c = (ptr as *const u8).read(); // we know the type here + } + + let mut val = 2_u32; + let ptr = &mut val as *mut u32; + unsafe { + let _a: i32 = (ptr as *mut _).read(); + //~^ ERROR cannot call a method on a raw pointer with an unknown pointee type [E0699] + let b = ptr as *mut _; + b.write(10); + //~^ ERROR cannot call a method on a raw pointer with an unknown pointee type [E0699] + (ptr as *mut i32).write(1000); // we know the type here + } +} diff --git a/tests/ui/methods/call_method_unknown_pointee.stderr b/tests/ui/methods/call_method_unknown_pointee.stderr new file mode 100644 index 00000000000..84ecf046e7a --- /dev/null +++ b/tests/ui/methods/call_method_unknown_pointee.stderr @@ -0,0 +1,27 @@ +error[E0699]: cannot call a method on a raw pointer with an unknown pointee type + --> $DIR/call_method_unknown_pointee.rs:10:41 + | +LL | let _a: i32 = (ptr as *const _).read(); + | ^^^^ + +error[E0699]: cannot call a method on a raw pointer with an unknown pointee type + --> $DIR/call_method_unknown_pointee.rs:13:24 + | +LL | let _b: u8 = b.read(); + | ^^^^ + +error[E0699]: cannot call a method on a raw pointer with an unknown pointee type + --> $DIR/call_method_unknown_pointee.rs:21:39 + | +LL | let _a: i32 = (ptr as *mut _).read(); + | ^^^^ + +error[E0699]: cannot call a method on a raw pointer with an unknown pointee type + --> $DIR/call_method_unknown_pointee.rs:24:11 + | +LL | b.write(10); + | ^^^^^ + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0699`. diff --git a/tests/ui/mir/addrof_alignment.rs b/tests/ui/mir/addrof_alignment.rs new file mode 100644 index 00000000000..892638bfb92 --- /dev/null +++ b/tests/ui/mir/addrof_alignment.rs @@ -0,0 +1,15 @@ +// run-pass +// ignore-wasm32-bare: No panic messages +// compile-flags: -C debug-assertions + +struct Misalignment { + a: u32, +} + +fn main() { + let items: [Misalignment; 2] = [Misalignment { a: 0 }, Misalignment { a: 1 }]; + unsafe { + let ptr: *const Misalignment = items.as_ptr().cast::<u8>().add(1).cast::<Misalignment>(); + let _ptr = core::ptr::addr_of!((*ptr).a); + } +} diff --git a/tests/ui/mismatched_types/E0053.stderr b/tests/ui/mismatched_types/E0053.stderr index 154f2fcbee0..d0bd5b46cf5 100644 --- a/tests/ui/mismatched_types/E0053.stderr +++ b/tests/ui/mismatched_types/E0053.stderr @@ -22,7 +22,7 @@ LL | fn bar(&mut self) { } | ^^^^^^^^^ | | | types differ in mutability - | help: change the self-receiver type to match the trait: `self: &Bar` + | help: change the self-receiver type to match the trait: `&self` | note: type in trait --> $DIR/E0053.rs:3:12 diff --git a/tests/ui/mismatched_types/issue-112036.rs b/tests/ui/mismatched_types/issue-112036.rs new file mode 100644 index 00000000000..e63471e9747 --- /dev/null +++ b/tests/ui/mismatched_types/issue-112036.rs @@ -0,0 +1,7 @@ +struct Foo; + +impl Drop for Foo { + fn drop(self) {} //~ ERROR method `drop` has an incompatible type for trait +} + +fn main() {} diff --git a/tests/ui/mismatched_types/issue-112036.stderr b/tests/ui/mismatched_types/issue-112036.stderr new file mode 100644 index 00000000000..a883aba35bf --- /dev/null +++ b/tests/ui/mismatched_types/issue-112036.stderr @@ -0,0 +1,15 @@ +error[E0053]: method `drop` has an incompatible type for trait + --> $DIR/issue-112036.rs:4:13 + | +LL | fn drop(self) {} + | ^^^^ + | | + | expected `&mut Foo`, found `Foo` + | help: change the self-receiver type to match the trait: `&mut self` + | + = note: expected signature `fn(&mut Foo)` + found signature `fn(Foo)` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0053`. diff --git a/tests/ui/offset-of/offset-of-unsized.rs b/tests/ui/offset-of/offset-of-unsized.rs new file mode 100644 index 00000000000..666387e615e --- /dev/null +++ b/tests/ui/offset-of/offset-of-unsized.rs @@ -0,0 +1,15 @@ +// build-pass +// regression test for #112051 + +#![feature(offset_of)] + +struct S<T: ?Sized> { + a: u64, + b: T, +} +trait Tr {} + +fn main() { + let _a = core::mem::offset_of!(S<dyn Tr>, a); + let _b = core::mem::offset_of!((u64, dyn Tr), 0); +} diff --git a/tests/ui/panics/nested_panic_caught.rs b/tests/ui/panics/nested_panic_caught.rs new file mode 100644 index 00000000000..d43886e8095 --- /dev/null +++ b/tests/ui/panics/nested_panic_caught.rs @@ -0,0 +1,24 @@ +// run-pass +// needs-unwind + +// Checks that nested panics work correctly. + +use std::panic::catch_unwind; + +fn double() { + struct Double; + + impl Drop for Double { + fn drop(&mut self) { + let _ = catch_unwind(|| panic!("twice")); + } + } + + let _d = Double; + + panic!("once"); +} + +fn main() { + assert!(catch_unwind(|| double()).is_err()); +} diff --git a/tests/ui/parser/issues/issue-111148.rs b/tests/ui/parser/issues/issue-111148.rs new file mode 100644 index 00000000000..2502beab443 --- /dev/null +++ b/tests/ui/parser/issues/issue-111148.rs @@ -0,0 +1,2 @@ +fn a<<i<Y<w<># +//~^ ERROR expected one of `#`, `>`, `const`, identifier, or lifetime, found `<` diff --git a/tests/ui/parser/issues/issue-111148.stderr b/tests/ui/parser/issues/issue-111148.stderr new file mode 100644 index 00000000000..e6595a5cbcc --- /dev/null +++ b/tests/ui/parser/issues/issue-111148.stderr @@ -0,0 +1,8 @@ +error: expected one of `#`, `>`, `const`, identifier, or lifetime, found `<` + --> $DIR/issue-111148.rs:1:6 + | +LL | fn a<<i<Y<w<># + | ^ expected one of `#`, `>`, `const`, identifier, or lifetime + +error: aborting due to previous error + diff --git a/tests/ui/parser/typod-const-in-const-param-def.rs b/tests/ui/parser/typod-const-in-const-param-def.rs new file mode 100644 index 00000000000..85d3ebba57a --- /dev/null +++ b/tests/ui/parser/typod-const-in-const-param-def.rs @@ -0,0 +1,16 @@ +pub fn foo<Const N: u8>() {} +//~^ ERROR `const` keyword was mistyped as `Const` + +pub fn bar<Const>() {} +// OK + +pub fn baz<Const N: u8, T>() {} +//~^ ERROR `const` keyword was mistyped as `Const` + +pub fn qux<T, Const N: u8>() {} +//~^ ERROR `const` keyword was mistyped as `Const` + +pub fn quux<T, Const N: u8, U>() {} +//~^ ERROR `const` keyword was mistyped as `Const` + +fn main() {} diff --git a/tests/ui/parser/typod-const-in-const-param-def.stderr b/tests/ui/parser/typod-const-in-const-param-def.stderr new file mode 100644 index 00000000000..75d73c6ea87 --- /dev/null +++ b/tests/ui/parser/typod-const-in-const-param-def.stderr @@ -0,0 +1,46 @@ +error: `const` keyword was mistyped as `Const` + --> $DIR/typod-const-in-const-param-def.rs:1:12 + | +LL | pub fn foo<Const N: u8>() {} + | ^^^^^ + | +help: use the `const` keyword + | +LL | pub fn foo<const N: u8>() {} + | ~~~~~ + +error: `const` keyword was mistyped as `Const` + --> $DIR/typod-const-in-const-param-def.rs:7:12 + | +LL | pub fn baz<Const N: u8, T>() {} + | ^^^^^ + | +help: use the `const` keyword + | +LL | pub fn baz<const N: u8, T>() {} + | ~~~~~ + +error: `const` keyword was mistyped as `Const` + --> $DIR/typod-const-in-const-param-def.rs:10:15 + | +LL | pub fn qux<T, Const N: u8>() {} + | ^^^^^ + | +help: use the `const` keyword + | +LL | pub fn qux<T, const N: u8>() {} + | ~~~~~ + +error: `const` keyword was mistyped as `Const` + --> $DIR/typod-const-in-const-param-def.rs:13:16 + | +LL | pub fn quux<T, Const N: u8, U>() {} + | ^^^^^ + | +help: use the `const` keyword + | +LL | pub fn quux<T, const N: u8, U>() {} + | ~~~~~ + +error: aborting due to 4 previous errors + diff --git a/tests/ui/issue-94866.rs b/tests/ui/pattern/issue-94866.rs index c4203487936..c4203487936 100644 --- a/tests/ui/issue-94866.rs +++ b/tests/ui/pattern/issue-94866.rs diff --git a/tests/ui/issue-94866.stderr b/tests/ui/pattern/issue-94866.stderr index b3c17ce8974..b3c17ce8974 100644 --- a/tests/ui/issue-94866.stderr +++ b/tests/ui/pattern/issue-94866.stderr diff --git a/tests/ui/pattern/usefulness/empty-match.exhaustive_patterns.stderr b/tests/ui/pattern/usefulness/empty-match.exhaustive_patterns.stderr index 5a145efce94..49b6dfca62e 100644 --- a/tests/ui/pattern/usefulness/empty-match.exhaustive_patterns.stderr +++ b/tests/ui/pattern/usefulness/empty-match.exhaustive_patterns.stderr @@ -1,5 +1,5 @@ error: unreachable pattern - --> $DIR/empty-match.rs:37:9 + --> $DIR/empty-match.rs:58:9 | LL | _ => {}, | ^ @@ -11,37 +11,52 @@ LL | #![deny(unreachable_patterns)] | ^^^^^^^^^^^^^^^^^^^^ error: unreachable pattern - --> $DIR/empty-match.rs:40:9 + --> $DIR/empty-match.rs:61:9 | LL | _ if false => {}, | ^ error: unreachable pattern - --> $DIR/empty-match.rs:47:9 + --> $DIR/empty-match.rs:68:9 | LL | _ => {}, | ^ error: unreachable pattern - --> $DIR/empty-match.rs:50:9 + --> $DIR/empty-match.rs:71:9 | LL | _ if false => {}, | ^ +error[E0005]: refutable pattern in local binding + --> $DIR/empty-match.rs:76:9 + | +LL | let None = x; + | ^^^^ pattern `Some(_)` not covered + | + = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant + = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html + = note: pattern `Some(_)` is currently uninhabited, but this variant contains private fields which may become inhabited in the future + = note: the matched value is of type `Option<SecretlyUninhabitedForeignStruct>` +help: you might want to use `if let` to ignore the variant that isn't matched + | +LL | if let None = x { todo!() }; + | ++ +++++++++++ + error: unreachable pattern - --> $DIR/empty-match.rs:57:9 + --> $DIR/empty-match.rs:88:9 | LL | _ => {}, | ^ error: unreachable pattern - --> $DIR/empty-match.rs:60:9 + --> $DIR/empty-match.rs:91:9 | LL | _ if false => {}, | ^ error[E0004]: non-exhaustive patterns: type `u8` is non-empty - --> $DIR/empty-match.rs:78:20 + --> $DIR/empty-match.rs:109:20 | LL | match_no_arms!(0u8); | ^^^ @@ -50,13 +65,13 @@ LL | match_no_arms!(0u8); = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern error[E0004]: non-exhaustive patterns: type `NonEmptyStruct1` is non-empty - --> $DIR/empty-match.rs:79:20 + --> $DIR/empty-match.rs:111:20 | LL | match_no_arms!(NonEmptyStruct1); | ^^^^^^^^^^^^^^^ | note: `NonEmptyStruct1` defined here - --> $DIR/empty-match.rs:14:8 + --> $DIR/empty-match.rs:15:8 | LL | struct NonEmptyStruct1; | ^^^^^^^^^^^^^^^ @@ -64,13 +79,13 @@ LL | struct NonEmptyStruct1; = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern error[E0004]: non-exhaustive patterns: type `NonEmptyStruct2` is non-empty - --> $DIR/empty-match.rs:80:20 + --> $DIR/empty-match.rs:113:20 | LL | match_no_arms!(NonEmptyStruct2(true)); | ^^^^^^^^^^^^^^^^^^^^^ | note: `NonEmptyStruct2` defined here - --> $DIR/empty-match.rs:15:8 + --> $DIR/empty-match.rs:18:8 | LL | struct NonEmptyStruct2(bool); | ^^^^^^^^^^^^^^^ @@ -78,13 +93,13 @@ LL | struct NonEmptyStruct2(bool); = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern error[E0004]: non-exhaustive patterns: type `NonEmptyUnion1` is non-empty - --> $DIR/empty-match.rs:81:20 + --> $DIR/empty-match.rs:115:20 | LL | match_no_arms!((NonEmptyUnion1 { foo: () })); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: `NonEmptyUnion1` defined here - --> $DIR/empty-match.rs:16:7 + --> $DIR/empty-match.rs:21:7 | LL | union NonEmptyUnion1 { | ^^^^^^^^^^^^^^ @@ -92,13 +107,13 @@ LL | union NonEmptyUnion1 { = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern error[E0004]: non-exhaustive patterns: type `NonEmptyUnion2` is non-empty - --> $DIR/empty-match.rs:82:20 + --> $DIR/empty-match.rs:117:20 | LL | match_no_arms!((NonEmptyUnion2 { foo: () })); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: `NonEmptyUnion2` defined here - --> $DIR/empty-match.rs:19:7 + --> $DIR/empty-match.rs:26:7 | LL | union NonEmptyUnion2 { | ^^^^^^^^^^^^^^ @@ -106,13 +121,13 @@ LL | union NonEmptyUnion2 { = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern error[E0004]: non-exhaustive patterns: `NonEmptyEnum1::Foo(_)` not covered - --> $DIR/empty-match.rs:83:20 + --> $DIR/empty-match.rs:119:20 | LL | match_no_arms!(NonEmptyEnum1::Foo(true)); | ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyEnum1::Foo(_)` not covered | note: `NonEmptyEnum1` defined here - --> $DIR/empty-match.rs:24:5 + --> $DIR/empty-match.rs:33:5 | LL | enum NonEmptyEnum1 { | ------------- @@ -122,31 +137,32 @@ LL | Foo(bool), = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern error[E0004]: non-exhaustive patterns: `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered - --> $DIR/empty-match.rs:84:20 + --> $DIR/empty-match.rs:122:20 | LL | match_no_arms!(NonEmptyEnum2::Foo(true)); | ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered | note: `NonEmptyEnum2` defined here - --> $DIR/empty-match.rs:27:5 + --> $DIR/empty-match.rs:40:5 | LL | enum NonEmptyEnum2 { | ------------- LL | Foo(bool), | ^^^ not covered +... LL | Bar, | ^^^ not covered = note: the matched value is of type `NonEmptyEnum2` = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or multiple match arms error[E0004]: non-exhaustive patterns: `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered - --> $DIR/empty-match.rs:85:20 + --> $DIR/empty-match.rs:125:20 | LL | match_no_arms!(NonEmptyEnum5::V1); | ^^^^^^^^^^^^^^^^^ patterns `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered | note: `NonEmptyEnum5` defined here - --> $DIR/empty-match.rs:30:6 + --> $DIR/empty-match.rs:49:6 | LL | enum NonEmptyEnum5 { | ^^^^^^^^^^^^^ @@ -154,7 +170,7 @@ LL | enum NonEmptyEnum5 { = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or multiple match arms error[E0004]: non-exhaustive patterns: `_` not covered - --> $DIR/empty-match.rs:87:24 + --> $DIR/empty-match.rs:129:24 | LL | match_guarded_arm!(0u8); | ^^^ pattern `_` not covered @@ -167,13 +183,13 @@ LL + _ => todo!() | error[E0004]: non-exhaustive patterns: `NonEmptyStruct1` not covered - --> $DIR/empty-match.rs:88:24 + --> $DIR/empty-match.rs:133:24 | LL | match_guarded_arm!(NonEmptyStruct1); | ^^^^^^^^^^^^^^^ pattern `NonEmptyStruct1` not covered | note: `NonEmptyStruct1` defined here - --> $DIR/empty-match.rs:14:8 + --> $DIR/empty-match.rs:15:8 | LL | struct NonEmptyStruct1; | ^^^^^^^^^^^^^^^ @@ -185,13 +201,13 @@ LL + NonEmptyStruct1 => todo!() | error[E0004]: non-exhaustive patterns: `NonEmptyStruct2(_)` not covered - --> $DIR/empty-match.rs:89:24 + --> $DIR/empty-match.rs:137:24 | LL | match_guarded_arm!(NonEmptyStruct2(true)); | ^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyStruct2(_)` not covered | note: `NonEmptyStruct2` defined here - --> $DIR/empty-match.rs:15:8 + --> $DIR/empty-match.rs:18:8 | LL | struct NonEmptyStruct2(bool); | ^^^^^^^^^^^^^^^ @@ -203,13 +219,13 @@ LL + NonEmptyStruct2(_) => todo!() | error[E0004]: non-exhaustive patterns: `NonEmptyUnion1 { .. }` not covered - --> $DIR/empty-match.rs:90:24 + --> $DIR/empty-match.rs:141:24 | LL | match_guarded_arm!((NonEmptyUnion1 { foo: () })); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion1 { .. }` not covered | note: `NonEmptyUnion1` defined here - --> $DIR/empty-match.rs:16:7 + --> $DIR/empty-match.rs:21:7 | LL | union NonEmptyUnion1 { | ^^^^^^^^^^^^^^ @@ -221,13 +237,13 @@ LL + NonEmptyUnion1 { .. } => todo!() | error[E0004]: non-exhaustive patterns: `NonEmptyUnion2 { .. }` not covered - --> $DIR/empty-match.rs:91:24 + --> $DIR/empty-match.rs:145:24 | LL | match_guarded_arm!((NonEmptyUnion2 { foo: () })); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion2 { .. }` not covered | note: `NonEmptyUnion2` defined here - --> $DIR/empty-match.rs:19:7 + --> $DIR/empty-match.rs:26:7 | LL | union NonEmptyUnion2 { | ^^^^^^^^^^^^^^ @@ -239,13 +255,13 @@ LL + NonEmptyUnion2 { .. } => todo!() | error[E0004]: non-exhaustive patterns: `NonEmptyEnum1::Foo(_)` not covered - --> $DIR/empty-match.rs:92:24 + --> $DIR/empty-match.rs:149:24 | LL | match_guarded_arm!(NonEmptyEnum1::Foo(true)); | ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyEnum1::Foo(_)` not covered | note: `NonEmptyEnum1` defined here - --> $DIR/empty-match.rs:24:5 + --> $DIR/empty-match.rs:33:5 | LL | enum NonEmptyEnum1 { | ------------- @@ -259,18 +275,19 @@ LL + NonEmptyEnum1::Foo(_) => todo!() | error[E0004]: non-exhaustive patterns: `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered - --> $DIR/empty-match.rs:93:24 + --> $DIR/empty-match.rs:153:24 | LL | match_guarded_arm!(NonEmptyEnum2::Foo(true)); | ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered | note: `NonEmptyEnum2` defined here - --> $DIR/empty-match.rs:27:5 + --> $DIR/empty-match.rs:40:5 | LL | enum NonEmptyEnum2 { | ------------- LL | Foo(bool), | ^^^ not covered +... LL | Bar, | ^^^ not covered = note: the matched value is of type `NonEmptyEnum2` @@ -281,13 +298,13 @@ LL + NonEmptyEnum2::Foo(_) | NonEmptyEnum2::Bar => todo!() | error[E0004]: non-exhaustive patterns: `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered - --> $DIR/empty-match.rs:94:24 + --> $DIR/empty-match.rs:157:24 | LL | match_guarded_arm!(NonEmptyEnum5::V1); | ^^^^^^^^^^^^^^^^^ patterns `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered | note: `NonEmptyEnum5` defined here - --> $DIR/empty-match.rs:30:6 + --> $DIR/empty-match.rs:49:6 | LL | enum NonEmptyEnum5 { | ^^^^^^^^^^^^^ @@ -298,6 +315,7 @@ LL ~ _ if false => {}, LL + _ => todo!() | -error: aborting due to 22 previous errors +error: aborting due to 23 previous errors -For more information about this error, try `rustc --explain E0004`. +Some errors have detailed explanations: E0004, E0005. +For more information about an error, try `rustc --explain E0004`. diff --git a/tests/ui/pattern/usefulness/empty-match.normal.stderr b/tests/ui/pattern/usefulness/empty-match.normal.stderr index 5a145efce94..f54a3f3364f 100644 --- a/tests/ui/pattern/usefulness/empty-match.normal.stderr +++ b/tests/ui/pattern/usefulness/empty-match.normal.stderr @@ -1,5 +1,5 @@ error: unreachable pattern - --> $DIR/empty-match.rs:37:9 + --> $DIR/empty-match.rs:58:9 | LL | _ => {}, | ^ @@ -11,37 +11,51 @@ LL | #![deny(unreachable_patterns)] | ^^^^^^^^^^^^^^^^^^^^ error: unreachable pattern - --> $DIR/empty-match.rs:40:9 + --> $DIR/empty-match.rs:61:9 | LL | _ if false => {}, | ^ error: unreachable pattern - --> $DIR/empty-match.rs:47:9 + --> $DIR/empty-match.rs:68:9 | LL | _ => {}, | ^ error: unreachable pattern - --> $DIR/empty-match.rs:50:9 + --> $DIR/empty-match.rs:71:9 | LL | _ if false => {}, | ^ +error[E0005]: refutable pattern in local binding + --> $DIR/empty-match.rs:76:9 + | +LL | let None = x; + | ^^^^ pattern `Some(_)` not covered + | + = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant + = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html + = note: the matched value is of type `Option<SecretlyUninhabitedForeignStruct>` +help: you might want to use `if let` to ignore the variant that isn't matched + | +LL | if let None = x { todo!() }; + | ++ +++++++++++ + error: unreachable pattern - --> $DIR/empty-match.rs:57:9 + --> $DIR/empty-match.rs:88:9 | LL | _ => {}, | ^ error: unreachable pattern - --> $DIR/empty-match.rs:60:9 + --> $DIR/empty-match.rs:91:9 | LL | _ if false => {}, | ^ error[E0004]: non-exhaustive patterns: type `u8` is non-empty - --> $DIR/empty-match.rs:78:20 + --> $DIR/empty-match.rs:109:20 | LL | match_no_arms!(0u8); | ^^^ @@ -50,13 +64,13 @@ LL | match_no_arms!(0u8); = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern error[E0004]: non-exhaustive patterns: type `NonEmptyStruct1` is non-empty - --> $DIR/empty-match.rs:79:20 + --> $DIR/empty-match.rs:111:20 | LL | match_no_arms!(NonEmptyStruct1); | ^^^^^^^^^^^^^^^ | note: `NonEmptyStruct1` defined here - --> $DIR/empty-match.rs:14:8 + --> $DIR/empty-match.rs:15:8 | LL | struct NonEmptyStruct1; | ^^^^^^^^^^^^^^^ @@ -64,13 +78,13 @@ LL | struct NonEmptyStruct1; = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern error[E0004]: non-exhaustive patterns: type `NonEmptyStruct2` is non-empty - --> $DIR/empty-match.rs:80:20 + --> $DIR/empty-match.rs:113:20 | LL | match_no_arms!(NonEmptyStruct2(true)); | ^^^^^^^^^^^^^^^^^^^^^ | note: `NonEmptyStruct2` defined here - --> $DIR/empty-match.rs:15:8 + --> $DIR/empty-match.rs:18:8 | LL | struct NonEmptyStruct2(bool); | ^^^^^^^^^^^^^^^ @@ -78,13 +92,13 @@ LL | struct NonEmptyStruct2(bool); = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern error[E0004]: non-exhaustive patterns: type `NonEmptyUnion1` is non-empty - --> $DIR/empty-match.rs:81:20 + --> $DIR/empty-match.rs:115:20 | LL | match_no_arms!((NonEmptyUnion1 { foo: () })); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: `NonEmptyUnion1` defined here - --> $DIR/empty-match.rs:16:7 + --> $DIR/empty-match.rs:21:7 | LL | union NonEmptyUnion1 { | ^^^^^^^^^^^^^^ @@ -92,13 +106,13 @@ LL | union NonEmptyUnion1 { = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern error[E0004]: non-exhaustive patterns: type `NonEmptyUnion2` is non-empty - --> $DIR/empty-match.rs:82:20 + --> $DIR/empty-match.rs:117:20 | LL | match_no_arms!((NonEmptyUnion2 { foo: () })); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: `NonEmptyUnion2` defined here - --> $DIR/empty-match.rs:19:7 + --> $DIR/empty-match.rs:26:7 | LL | union NonEmptyUnion2 { | ^^^^^^^^^^^^^^ @@ -106,13 +120,13 @@ LL | union NonEmptyUnion2 { = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern error[E0004]: non-exhaustive patterns: `NonEmptyEnum1::Foo(_)` not covered - --> $DIR/empty-match.rs:83:20 + --> $DIR/empty-match.rs:119:20 | LL | match_no_arms!(NonEmptyEnum1::Foo(true)); | ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyEnum1::Foo(_)` not covered | note: `NonEmptyEnum1` defined here - --> $DIR/empty-match.rs:24:5 + --> $DIR/empty-match.rs:33:5 | LL | enum NonEmptyEnum1 { | ------------- @@ -122,31 +136,32 @@ LL | Foo(bool), = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern error[E0004]: non-exhaustive patterns: `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered - --> $DIR/empty-match.rs:84:20 + --> $DIR/empty-match.rs:122:20 | LL | match_no_arms!(NonEmptyEnum2::Foo(true)); | ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered | note: `NonEmptyEnum2` defined here - --> $DIR/empty-match.rs:27:5 + --> $DIR/empty-match.rs:40:5 | LL | enum NonEmptyEnum2 { | ------------- LL | Foo(bool), | ^^^ not covered +... LL | Bar, | ^^^ not covered = note: the matched value is of type `NonEmptyEnum2` = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or multiple match arms error[E0004]: non-exhaustive patterns: `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered - --> $DIR/empty-match.rs:85:20 + --> $DIR/empty-match.rs:125:20 | LL | match_no_arms!(NonEmptyEnum5::V1); | ^^^^^^^^^^^^^^^^^ patterns `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered | note: `NonEmptyEnum5` defined here - --> $DIR/empty-match.rs:30:6 + --> $DIR/empty-match.rs:49:6 | LL | enum NonEmptyEnum5 { | ^^^^^^^^^^^^^ @@ -154,7 +169,7 @@ LL | enum NonEmptyEnum5 { = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or multiple match arms error[E0004]: non-exhaustive patterns: `_` not covered - --> $DIR/empty-match.rs:87:24 + --> $DIR/empty-match.rs:129:24 | LL | match_guarded_arm!(0u8); | ^^^ pattern `_` not covered @@ -167,13 +182,13 @@ LL + _ => todo!() | error[E0004]: non-exhaustive patterns: `NonEmptyStruct1` not covered - --> $DIR/empty-match.rs:88:24 + --> $DIR/empty-match.rs:133:24 | LL | match_guarded_arm!(NonEmptyStruct1); | ^^^^^^^^^^^^^^^ pattern `NonEmptyStruct1` not covered | note: `NonEmptyStruct1` defined here - --> $DIR/empty-match.rs:14:8 + --> $DIR/empty-match.rs:15:8 | LL | struct NonEmptyStruct1; | ^^^^^^^^^^^^^^^ @@ -185,13 +200,13 @@ LL + NonEmptyStruct1 => todo!() | error[E0004]: non-exhaustive patterns: `NonEmptyStruct2(_)` not covered - --> $DIR/empty-match.rs:89:24 + --> $DIR/empty-match.rs:137:24 | LL | match_guarded_arm!(NonEmptyStruct2(true)); | ^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyStruct2(_)` not covered | note: `NonEmptyStruct2` defined here - --> $DIR/empty-match.rs:15:8 + --> $DIR/empty-match.rs:18:8 | LL | struct NonEmptyStruct2(bool); | ^^^^^^^^^^^^^^^ @@ -203,13 +218,13 @@ LL + NonEmptyStruct2(_) => todo!() | error[E0004]: non-exhaustive patterns: `NonEmptyUnion1 { .. }` not covered - --> $DIR/empty-match.rs:90:24 + --> $DIR/empty-match.rs:141:24 | LL | match_guarded_arm!((NonEmptyUnion1 { foo: () })); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion1 { .. }` not covered | note: `NonEmptyUnion1` defined here - --> $DIR/empty-match.rs:16:7 + --> $DIR/empty-match.rs:21:7 | LL | union NonEmptyUnion1 { | ^^^^^^^^^^^^^^ @@ -221,13 +236,13 @@ LL + NonEmptyUnion1 { .. } => todo!() | error[E0004]: non-exhaustive patterns: `NonEmptyUnion2 { .. }` not covered - --> $DIR/empty-match.rs:91:24 + --> $DIR/empty-match.rs:145:24 | LL | match_guarded_arm!((NonEmptyUnion2 { foo: () })); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion2 { .. }` not covered | note: `NonEmptyUnion2` defined here - --> $DIR/empty-match.rs:19:7 + --> $DIR/empty-match.rs:26:7 | LL | union NonEmptyUnion2 { | ^^^^^^^^^^^^^^ @@ -239,13 +254,13 @@ LL + NonEmptyUnion2 { .. } => todo!() | error[E0004]: non-exhaustive patterns: `NonEmptyEnum1::Foo(_)` not covered - --> $DIR/empty-match.rs:92:24 + --> $DIR/empty-match.rs:149:24 | LL | match_guarded_arm!(NonEmptyEnum1::Foo(true)); | ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyEnum1::Foo(_)` not covered | note: `NonEmptyEnum1` defined here - --> $DIR/empty-match.rs:24:5 + --> $DIR/empty-match.rs:33:5 | LL | enum NonEmptyEnum1 { | ------------- @@ -259,18 +274,19 @@ LL + NonEmptyEnum1::Foo(_) => todo!() | error[E0004]: non-exhaustive patterns: `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered - --> $DIR/empty-match.rs:93:24 + --> $DIR/empty-match.rs:153:24 | LL | match_guarded_arm!(NonEmptyEnum2::Foo(true)); | ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered | note: `NonEmptyEnum2` defined here - --> $DIR/empty-match.rs:27:5 + --> $DIR/empty-match.rs:40:5 | LL | enum NonEmptyEnum2 { | ------------- LL | Foo(bool), | ^^^ not covered +... LL | Bar, | ^^^ not covered = note: the matched value is of type `NonEmptyEnum2` @@ -281,13 +297,13 @@ LL + NonEmptyEnum2::Foo(_) | NonEmptyEnum2::Bar => todo!() | error[E0004]: non-exhaustive patterns: `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered - --> $DIR/empty-match.rs:94:24 + --> $DIR/empty-match.rs:157:24 | LL | match_guarded_arm!(NonEmptyEnum5::V1); | ^^^^^^^^^^^^^^^^^ patterns `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered | note: `NonEmptyEnum5` defined here - --> $DIR/empty-match.rs:30:6 + --> $DIR/empty-match.rs:49:6 | LL | enum NonEmptyEnum5 { | ^^^^^^^^^^^^^ @@ -298,6 +314,7 @@ LL ~ _ if false => {}, LL + _ => todo!() | -error: aborting due to 22 previous errors +error: aborting due to 23 previous errors -For more information about this error, try `rustc --explain E0004`. +Some errors have detailed explanations: E0004, E0005. +For more information about an error, try `rustc --explain E0004`. diff --git a/tests/ui/pattern/usefulness/empty-match.rs b/tests/ui/pattern/usefulness/empty-match.rs index 9cdc0413ba1..062241faa4c 100644 --- a/tests/ui/pattern/usefulness/empty-match.rs +++ b/tests/ui/pattern/usefulness/empty-match.rs @@ -6,28 +6,49 @@ #![feature(never_type_fallback)] #![cfg_attr(exhaustive_patterns, feature(exhaustive_patterns))] #![deny(unreachable_patterns)] +//~^ NOTE the lint level is defined here extern crate empty; enum EmptyEnum {} struct NonEmptyStruct1; +//~^ NOTE `NonEmptyStruct1` defined here +//~| NOTE `NonEmptyStruct1` defined here struct NonEmptyStruct2(bool); +//~^ NOTE `NonEmptyStruct2` defined here +//~| NOTE `NonEmptyStruct2` defined here union NonEmptyUnion1 { + //~^ NOTE `NonEmptyUnion1` defined here + //~| NOTE `NonEmptyUnion1` defined here foo: (), } union NonEmptyUnion2 { + //~^ NOTE `NonEmptyUnion2` defined here + //~| NOTE `NonEmptyUnion2` defined here foo: (), bar: (), } enum NonEmptyEnum1 { Foo(bool), + //~^ NOTE `NonEmptyEnum1` defined here + //~| NOTE `NonEmptyEnum1` defined here + //~| NOTE not covered + //~| NOTE not covered } enum NonEmptyEnum2 { Foo(bool), + //~^ NOTE `NonEmptyEnum2` defined here + //~| NOTE `NonEmptyEnum2` defined here + //~| NOTE not covered + //~| NOTE not covered Bar, + //~^ NOTE not covered + //~| NOTE not covered } enum NonEmptyEnum5 { + //~^ NOTE `NonEmptyEnum5` defined here + //~| NOTE `NonEmptyEnum5` defined here V1, V2, V3, V4, V5, } @@ -51,6 +72,16 @@ fn empty_foreign_enum(x: empty::EmptyForeignEnum) { } } +fn empty_foreign_enum_private(x: Option<empty::SecretlyUninhabitedForeignStruct>) { + let None = x; + //~^ ERROR refutable pattern in local binding + //~| NOTE `let` bindings require an "irrefutable pattern" + //~| NOTE for more information, visit + //~| NOTE the matched value is of type + //~| NOTE pattern `Some(_)` not covered + //[exhaustive_patterns]~| NOTE currently uninhabited, but this variant contains private fields +} + fn never(x: !) { match x {} // ok match x { @@ -76,20 +107,55 @@ macro_rules! match_guarded_arm { fn main() { match_no_arms!(0u8); //~ ERROR type `u8` is non-empty + //~| NOTE the matched value is of type match_no_arms!(NonEmptyStruct1); //~ ERROR type `NonEmptyStruct1` is non-empty + //~| NOTE the matched value is of type match_no_arms!(NonEmptyStruct2(true)); //~ ERROR type `NonEmptyStruct2` is non-empty + //~| NOTE the matched value is of type match_no_arms!((NonEmptyUnion1 { foo: () })); //~ ERROR type `NonEmptyUnion1` is non-empty + //~| NOTE the matched value is of type match_no_arms!((NonEmptyUnion2 { foo: () })); //~ ERROR type `NonEmptyUnion2` is non-empty + //~| NOTE the matched value is of type match_no_arms!(NonEmptyEnum1::Foo(true)); //~ ERROR `NonEmptyEnum1::Foo(_)` not covered + //~| NOTE pattern `NonEmptyEnum1::Foo(_)` not covered + //~| NOTE the matched value is of type match_no_arms!(NonEmptyEnum2::Foo(true)); //~ ERROR `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered + //~| NOTE patterns `NonEmptyEnum2::Foo(_)` and + //~| NOTE the matched value is of type match_no_arms!(NonEmptyEnum5::V1); //~ ERROR `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered + //~| NOTE patterns `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2` + //~| NOTE the matched value is of type match_guarded_arm!(0u8); //~ ERROR `_` not covered + //~| NOTE the matched value is of type + //~| NOTE pattern `_` not covered + //~| NOTE in this expansion of match_guarded_arm! match_guarded_arm!(NonEmptyStruct1); //~ ERROR `NonEmptyStruct1` not covered + //~| NOTE pattern `NonEmptyStruct1` not covered + //~| NOTE the matched value is of type + //~| NOTE in this expansion of match_guarded_arm! match_guarded_arm!(NonEmptyStruct2(true)); //~ ERROR `NonEmptyStruct2(_)` not covered + //~| NOTE the matched value is of type + //~| NOTE pattern `NonEmptyStruct2(_)` not covered + //~| NOTE in this expansion of match_guarded_arm! match_guarded_arm!((NonEmptyUnion1 { foo: () })); //~ ERROR `NonEmptyUnion1 { .. }` not covered + //~| NOTE the matched value is of type + //~| NOTE pattern `NonEmptyUnion1 { .. }` not covered + //~| NOTE in this expansion of match_guarded_arm! match_guarded_arm!((NonEmptyUnion2 { foo: () })); //~ ERROR `NonEmptyUnion2 { .. }` not covered + //~| NOTE the matched value is of type + //~| NOTE pattern `NonEmptyUnion2 { .. }` not covered + //~| NOTE in this expansion of match_guarded_arm! match_guarded_arm!(NonEmptyEnum1::Foo(true)); //~ ERROR `NonEmptyEnum1::Foo(_)` not covered + //~| NOTE the matched value is of type + //~| NOTE pattern `NonEmptyEnum1::Foo(_)` not covered + //~| NOTE in this expansion of match_guarded_arm! match_guarded_arm!(NonEmptyEnum2::Foo(true)); //~ ERROR `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered + //~| NOTE the matched value is of type + //~| NOTE patterns `NonEmptyEnum2::Foo(_)` and + //~| NOTE in this expansion of match_guarded_arm! match_guarded_arm!(NonEmptyEnum5::V1); //~ ERROR `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered + //~| NOTE the matched value is of type + //~| NOTE patterns `NonEmptyEnum5::V1`, + //~| NOTE in this expansion of match_guarded_arm! } diff --git a/tests/ui/privacy/issue-111220-2-tuple-struct-fields-projection.rs b/tests/ui/privacy/issue-111220-2-tuple-struct-fields-projection.rs new file mode 100644 index 00000000000..f413b502778 --- /dev/null +++ b/tests/ui/privacy/issue-111220-2-tuple-struct-fields-projection.rs @@ -0,0 +1,33 @@ +mod b { + pub struct A(u32); +} + +trait Id { + type Assoc; +} +impl Id for b::A { + type Assoc = b::A; +} +impl Id for u32 { + type Assoc = u32; +} + + +trait Trait<T> { + fn method(&self) + where + T: Id<Assoc = b::A>; +} + +impl<T: Id> Trait<T> for <T as Id>::Assoc { + fn method(&self) + where + T: Id<Assoc = b::A>, + { + let Self(a) = self; + //~^ ERROR: tuple struct constructor `A` is private + println!("{a}"); + } +} + +fn main() {} diff --git a/tests/ui/privacy/issue-111220-2-tuple-struct-fields-projection.stderr b/tests/ui/privacy/issue-111220-2-tuple-struct-fields-projection.stderr new file mode 100644 index 00000000000..231a4da8b5f --- /dev/null +++ b/tests/ui/privacy/issue-111220-2-tuple-struct-fields-projection.stderr @@ -0,0 +1,9 @@ +error[E0603]: tuple struct constructor `A` is private + --> $DIR/issue-111220-2-tuple-struct-fields-projection.rs:27:13 + | +LL | let Self(a) = self; + | ^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0603`. diff --git a/tests/ui/privacy/issue-111220-tuple-struct-fields.rs b/tests/ui/privacy/issue-111220-tuple-struct-fields.rs new file mode 100644 index 00000000000..78d35fd96da --- /dev/null +++ b/tests/ui/privacy/issue-111220-tuple-struct-fields.rs @@ -0,0 +1,46 @@ +mod b { + #[derive(Default)] + pub struct A(u32); +} + +impl b::A { + fn inherent_bypass(&self) { + let Self(x) = self; + //~^ ERROR: tuple struct constructor `A` is private + println!("{x}"); + } +} + +pub trait B { + fn f(&self); +} + +impl B for b::A { + fn f(&self) { + let Self(a) = self; + //~^ ERROR: tuple struct constructor `A` is private + println!("{}", a); + } +} + +pub trait Projector { + type P; +} + +impl Projector for () { + type P = b::A; +} + +pub trait Bypass2 { + fn f2(&self); +} + +impl Bypass2 for <() as Projector>::P { + fn f2(&self) { + let Self(a) = self; + //~^ ERROR: tuple struct constructor `A` is private + println!("{}", a); + } +} + +fn main() {} diff --git a/tests/ui/privacy/issue-111220-tuple-struct-fields.stderr b/tests/ui/privacy/issue-111220-tuple-struct-fields.stderr new file mode 100644 index 00000000000..17a32379cc0 --- /dev/null +++ b/tests/ui/privacy/issue-111220-tuple-struct-fields.stderr @@ -0,0 +1,21 @@ +error[E0603]: tuple struct constructor `A` is private + --> $DIR/issue-111220-tuple-struct-fields.rs:8:13 + | +LL | let Self(x) = self; + | ^^^^^^^ + +error[E0603]: tuple struct constructor `A` is private + --> $DIR/issue-111220-tuple-struct-fields.rs:20:13 + | +LL | let Self(a) = self; + | ^^^^^^^ + +error[E0603]: tuple struct constructor `A` is private + --> $DIR/issue-111220-tuple-struct-fields.rs:40:13 + | +LL | let Self(a) = self; + | ^^^^^^^ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0603`. diff --git a/tests/ui/process/process-panic-after-fork.rs b/tests/ui/process/process-panic-after-fork.rs index da268312173..7c2fc296bb0 100644 --- a/tests/ui/process/process-panic-after-fork.rs +++ b/tests/ui/process/process-panic-after-fork.rs @@ -11,6 +11,8 @@ #![feature(never_type)] #![feature(panic_always_abort)] +#![allow(invalid_from_utf8)] + extern crate libc; use std::alloc::{GlobalAlloc, Layout}; diff --git a/tests/ui/resolve/hidden_glob_reexports.rs b/tests/ui/resolve/hidden_glob_reexports.rs new file mode 100644 index 00000000000..361243fcd7b --- /dev/null +++ b/tests/ui/resolve/hidden_glob_reexports.rs @@ -0,0 +1,52 @@ +// check-pass + +pub mod upstream_a { + mod inner { + pub struct Foo {} + pub struct Bar {} + } + + pub use self::inner::*; + + struct Foo; + //~^ WARN private item shadows public glob re-export +} + +pub mod upstream_b { + mod inner { + pub struct Foo {} + pub struct Qux {} + } + + mod other { + pub struct Foo; + } + + pub use self::inner::*; + + use self::other::Foo; + //~^ WARN private item shadows public glob re-export +} + +pub mod upstream_c { + mod no_def_id { + #![allow(non_camel_case_types)] + pub struct u8; + pub struct World; + } + + pub use self::no_def_id::*; + + use std::primitive::u8; + //~^ WARN private item shadows public glob re-export +} + +// Downstream crate +// mod downstream { +// fn proof() { +// let _ = crate::upstream_a::Foo; +// let _ = crate::upstream_b::Foo; +// } +// } + +pub fn main() {} diff --git a/tests/ui/resolve/hidden_glob_reexports.stderr b/tests/ui/resolve/hidden_glob_reexports.stderr new file mode 100644 index 00000000000..ddf7bcda827 --- /dev/null +++ b/tests/ui/resolve/hidden_glob_reexports.stderr @@ -0,0 +1,31 @@ +warning: private item shadows public glob re-export + --> $DIR/hidden_glob_reexports.rs:11:5 + | +LL | pub use self::inner::*; + | -------------- the name `Foo` in the type namespace is supposed to be publicly re-exported here +LL | +LL | struct Foo; + | ^^^^^^^^^^^ but the private item here shadows it + | + = note: `#[warn(hidden_glob_reexports)]` on by default + +warning: private item shadows public glob re-export + --> $DIR/hidden_glob_reexports.rs:27:9 + | +LL | pub use self::inner::*; + | -------------- the name `Foo` in the type namespace is supposed to be publicly re-exported here +LL | +LL | use self::other::Foo; + | ^^^^^^^^^^^^^^^^ but the private item here shadows it + +warning: private item shadows public glob re-export + --> $DIR/hidden_glob_reexports.rs:40:9 + | +LL | pub use self::no_def_id::*; + | ------------------ the name `u8` in the type namespace is supposed to be publicly re-exported here +LL | +LL | use std::primitive::u8; + | ^^^^^^^^^^^^^^^^^^ but the private item here shadows it + +warning: 3 warnings emitted + diff --git a/tests/ui/issues/issue-3008-1.rs b/tests/ui/structs-enums/issue-3008-1.rs index 1124969e6d0..1124969e6d0 100644 --- a/tests/ui/issues/issue-3008-1.rs +++ b/tests/ui/structs-enums/issue-3008-1.rs diff --git a/tests/ui/issues/issue-3008-1.stderr b/tests/ui/structs-enums/issue-3008-1.stderr index be25b9091d5..be25b9091d5 100644 --- a/tests/ui/issues/issue-3008-1.stderr +++ b/tests/ui/structs-enums/issue-3008-1.stderr diff --git a/tests/ui/issues/issue-3008-2.rs b/tests/ui/structs-enums/issue-3008-2.rs index 5846c69da41..5846c69da41 100644 --- a/tests/ui/issues/issue-3008-2.rs +++ b/tests/ui/structs-enums/issue-3008-2.rs diff --git a/tests/ui/issues/issue-3008-2.stderr b/tests/ui/structs-enums/issue-3008-2.stderr index 858a8fd6af8..858a8fd6af8 100644 --- a/tests/ui/issues/issue-3008-2.stderr +++ b/tests/ui/structs-enums/issue-3008-2.stderr diff --git a/tests/ui/issues/issue-3008-3.rs b/tests/ui/structs-enums/issue-3008-3.rs index 212eb2eb8e0..212eb2eb8e0 100644 --- a/tests/ui/issues/issue-3008-3.rs +++ b/tests/ui/structs-enums/issue-3008-3.rs diff --git a/tests/ui/issues/issue-3008-3.stderr b/tests/ui/structs-enums/issue-3008-3.stderr index a1a81e29367..a1a81e29367 100644 --- a/tests/ui/issues/issue-3008-3.stderr +++ b/tests/ui/structs-enums/issue-3008-3.stderr diff --git a/tests/ui/suggestions/issue-103646.rs b/tests/ui/suggestions/issue-103646.rs new file mode 100644 index 00000000000..f679640c5dc --- /dev/null +++ b/tests/ui/suggestions/issue-103646.rs @@ -0,0 +1,11 @@ +trait Cat { + fn nya() {} +} + +fn uwu<T: Cat>(c: T) { + c.nya(); + //~^ ERROR no method named `nya` found for type parameter `T` in the current scope + //~| Suggestion T::nya() +} + +fn main() {} diff --git a/tests/ui/suggestions/issue-103646.stderr b/tests/ui/suggestions/issue-103646.stderr new file mode 100644 index 00000000000..3ae9813d491 --- /dev/null +++ b/tests/ui/suggestions/issue-103646.stderr @@ -0,0 +1,21 @@ +error[E0599]: no method named `nya` found for type parameter `T` in the current scope + --> $DIR/issue-103646.rs:6:7 + | +LL | fn uwu<T: Cat>(c: T) { + | - method `nya` not found for this type parameter +LL | c.nya(); + | --^^^-- + | | | + | | this is an associated function, not a method + | help: use associated function syntax instead: `T::nya()` + | + = note: found the following associated functions; to be used as methods, functions must have a `self` parameter +note: the candidate is defined in the trait `Cat` + --> $DIR/issue-103646.rs:2:5 + | +LL | fn nya() {} + | ^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/thir-print/thir-flat.stdout b/tests/ui/thir-print/thir-flat.stdout index 9d467f73d09..b0aa44b56aa 100644 --- a/tests/ui/thir-print/thir-flat.stdout +++ b/tests/ui/thir-print/thir-flat.stdout @@ -1,7 +1,7 @@ DefId(0:3 ~ thir_flat[7b97]::main): Thir { body_type: Fn( - ([]; c_variadic: false)->(), + fn(), ), arms: [], blocks: [ diff --git a/tests/ui/track-diagnostics/track6.stderr b/tests/ui/track-diagnostics/track6.stderr index 89438aea9ad..583b02555b4 100644 --- a/tests/ui/track-diagnostics/track6.stderr +++ b/tests/ui/track-diagnostics/track6.stderr @@ -3,7 +3,7 @@ error[E0658]: specialization is unstable | LL | default fn bar() {} | ^^^^^^^^^^^^^^^^^^^ --Ztrack-diagnostics: created at $COMPILER_DIR/rustc_session/src/parse.rs:LL:CC +-Ztrack-diagnostics: created at compiler/rustc_ast_passes/src/feature_gate.rs:LL:CC | = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information = help: add `#![feature(specialization)]` to the crate attributes to enable diff --git a/tests/ui/traits/new-solver/leak-check-coinductive-cycle.rs b/tests/ui/traits/new-solver/leak-check-coinductive-cycle.rs new file mode 100644 index 00000000000..1f7d4a49c90 --- /dev/null +++ b/tests/ui/traits/new-solver/leak-check-coinductive-cycle.rs @@ -0,0 +1,33 @@ +// check-pass +// compile-flags: -Ztrait-solver=next +#![feature(rustc_attrs)] + +#[rustc_coinductive] +trait Trait<T> {} +impl<'a, 'b, T> Trait<T> for (&'a (), &'b ()) +where + 'b: 'a, + &'a (): Trait<T>, +{} + +impl Trait<i32> for &'static () {} +impl<'a> Trait<u32> for &'a () +where + for<'b> (&'a (), &'b ()): Trait<u32>, +{} + + +fn impls_trait<T: Trait<U>, U>() {} + +fn main() { + // This infers to `impls_trait::<(&'static (), &'static ()), i32>();` + // + // In the first attempt we have 2 candidates for `&'a (): Trait<_>` + // and we get ambiguity. The result is therefore ambiguity with a `'b: 'a` + // constraint. The next attempt then uses that provisional result when + // trying to apply `impl<'a> Trait<u32> for &'a ()`. This means we get a + // `for<'b> 'b: 'a` bound which fails the leak check. Because of this we + // end up with a single impl for `&'a (): Trait<_>` which infers `_` to `i32` + // and succeeds. + impls_trait::<(&(), &()), _>(); +} diff --git a/tests/ui/type-alias-impl-trait/coherence_different_hidden_ty.rs b/tests/ui/type-alias-impl-trait/coherence_different_hidden_ty.rs new file mode 100644 index 00000000000..39b3d535ad4 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/coherence_different_hidden_ty.rs @@ -0,0 +1,25 @@ +// When checking whether these two impls overlap, we could detect that we +// would require the hidden type of `TAIT` to be equal to both `u32` and `i32` +// and therefore accept them as disjoint. That is annoying to implement with +// the current system because we would have to add the following to each +// returning branch in coherence. +// +// let _ = infcx.take_opaque_types(); +// +// @lcnr: Because of this I decided to not bother and cause this to fail instead. +// In the future we can definitely modify the compiler to accept this +// again. +#![feature(type_alias_impl_trait)] + +trait Trait {} + +type TAIT = impl Sized; + +impl Trait for (TAIT, TAIT) {} + +impl Trait for (u32, i32) {} +//~^ ERROR conflicting implementations of trait `Trait` for type `(TAIT, TAIT)` + +fn define() -> TAIT {} + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/coherence_different_hidden_ty.stderr b/tests/ui/type-alias-impl-trait/coherence_different_hidden_ty.stderr new file mode 100644 index 00000000000..f2aee798608 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/coherence_different_hidden_ty.stderr @@ -0,0 +1,12 @@ +error[E0119]: conflicting implementations of trait `Trait` for type `(TAIT, TAIT)` + --> $DIR/coherence_different_hidden_ty.rs:20:1 + | +LL | impl Trait for (TAIT, TAIT) {} + | --------------------------- first implementation here +LL | +LL | impl Trait for (u32, i32) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(TAIT, TAIT)` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/type-alias-impl-trait/coherence_generalization.rs b/tests/ui/type-alias-impl-trait/coherence_generalization.rs index 5c9ad9498b6..679b2b0f188 100644 --- a/tests/ui/type-alias-impl-trait/coherence_generalization.rs +++ b/tests/ui/type-alias-impl-trait/coherence_generalization.rs @@ -1,5 +1,7 @@ // check-pass +// FIXME(type_alias_impl_trait): What does this test? This needs a comment +// explaining what we're worried about here. #![feature(type_alias_impl_trait)] trait Trait {} type Opaque<T> = impl Sized; diff --git a/tests/ui/typeck/issue-106929.rs b/tests/ui/typeck/issue-106929.rs new file mode 100644 index 00000000000..91342229ae1 --- /dev/null +++ b/tests/ui/typeck/issue-106929.rs @@ -0,0 +1,13 @@ +struct Client; + +impl Client { + fn post<T: std::ops::Add>(&self, _: T, _: T) {} +} + +fn f() { + let c = Client; + post(c, ()); + //~^ ERROR cannot find function `post` in this scope +} + +fn main() {} diff --git a/tests/ui/typeck/issue-106929.stderr b/tests/ui/typeck/issue-106929.stderr new file mode 100644 index 00000000000..f744e5a41f0 --- /dev/null +++ b/tests/ui/typeck/issue-106929.stderr @@ -0,0 +1,15 @@ +error[E0425]: cannot find function `post` in this scope + --> $DIR/issue-106929.rs:9:5 + | +LL | post(c, ()); + | ^^^^ not found in this scope + | +help: use the `.` operator to call the method `post` on `&Client` + | +LL - post(c, ()); +LL + c.post(()); + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/issues/issue-1871.rs b/tests/ui/typeck/issue-1871.rs index f7a2bdd5659..f7a2bdd5659 100644 --- a/tests/ui/issues/issue-1871.rs +++ b/tests/ui/typeck/issue-1871.rs diff --git a/tests/ui/issues/issue-1871.stderr b/tests/ui/typeck/issue-1871.stderr index b774ca22dd7..b774ca22dd7 100644 --- a/tests/ui/issues/issue-1871.stderr +++ b/tests/ui/typeck/issue-1871.stderr diff --git a/tests/ui/issues/issue-2063-resource.rs b/tests/ui/typeck/issue-2063-resource.rs index 1d0527447ba..1d0527447ba 100644 --- a/tests/ui/issues/issue-2063-resource.rs +++ b/tests/ui/typeck/issue-2063-resource.rs diff --git a/tests/ui/issues/issue-2063.rs b/tests/ui/typeck/issue-2063.rs index f08f9d4cfe4..f08f9d4cfe4 100644 --- a/tests/ui/issues/issue-2063.rs +++ b/tests/ui/typeck/issue-2063.rs diff --git a/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-1.rs b/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-1.rs index a6c86311b37..e7f7fdc513b 100644 --- a/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-1.rs +++ b/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-1.rs @@ -2,7 +2,7 @@ trait One<A> { fn foo(&self) -> A; } -fn foo(_: &dyn One()) //~ ERROR associated type `Output` not found for `One<()>` +fn foo(_: &dyn One()) //~ ERROR associated type `Output` not found for `One` {} fn main() { } diff --git a/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-1.stderr b/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-1.stderr index 59e7bc8c832..e4772478bd9 100644 --- a/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-1.stderr +++ b/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-1.stderr @@ -1,4 +1,4 @@ -error[E0220]: associated type `Output` not found for `One<()>` +error[E0220]: associated type `Output` not found for `One` --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters-1.rs:5:16 | LL | fn foo(_: &dyn One()) diff --git a/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-3.stderr b/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-3.stderr index 5d7fe3fa533..eb18b121957 100644 --- a/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-3.stderr +++ b/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-3.stderr @@ -12,7 +12,7 @@ note: trait defined here, with 3 generic parameters: `A`, `B`, `C` LL | trait Three<A,B,C> { fn dummy(&self) -> (A,B,C); } | ^^^^^ - - - -error[E0220]: associated type `Output` not found for `Three<(), [type error], [type error]>` +error[E0220]: associated type `Output` not found for `Three` --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters-3.rs:5:16 | LL | fn foo(_: &dyn Three()) diff --git a/tests/ui/issues/issue-50825-1.rs b/tests/ui/where-clauses/issue-50825-1.rs index ee4316029a8..ee4316029a8 100644 --- a/tests/ui/issues/issue-50825-1.rs +++ b/tests/ui/where-clauses/issue-50825-1.rs diff --git a/tests/ui/issues/issue-50825.rs b/tests/ui/where-clauses/issue-50825.rs index 1ece2e9fc84..1ece2e9fc84 100644 --- a/tests/ui/issues/issue-50825.rs +++ b/tests/ui/where-clauses/issue-50825.rs diff --git a/triagebot.toml b/triagebot.toml index d7cd3ea1275..c160c83cc95 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -190,6 +190,7 @@ trigger_files = [ "src/stage0.json", "src/tools/compiletest", "src/tools/tidy", + "src/tools/rustdoc-gui-test", ] [autolabel."T-infra"] @@ -640,3 +641,4 @@ style-team = [ "/src/tools/rustdoc-themes" = ["rustdoc"] "/src/tools/tidy" = ["bootstrap"] "/src/tools/x" = ["bootstrap"] +"/src/tools/rustdoc-gui-test" = ["bootstrap", "@ozkanonur"] |
